mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 580752 - TM: optimize setelem. r=gal.
This commit is contained in:
parent
8b137e037b
commit
887c472b16
@ -517,6 +517,23 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, const Value &v)
|
||||
return obj->setProperty(cx, idr.id(), &tmp);
|
||||
}
|
||||
|
||||
#ifdef JS_TRACER
|
||||
JSBool JS_FASTCALL
|
||||
js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i)
|
||||
{
|
||||
jsuint u = jsuint(i);
|
||||
jsuint capacity = obj->getDenseArrayCapacity();
|
||||
if (u < capacity)
|
||||
return true;
|
||||
if (INDEX_TOO_SPARSE(obj, u))
|
||||
return false;
|
||||
return obj->ensureDenseArrayElements(cx, u + 1);
|
||||
|
||||
}
|
||||
JS_DEFINE_CALLINFO_3(extern, BOOL, js_EnsureDenseArrayCapacity, CONTEXT, OBJECT, INT32, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
#endif
|
||||
|
||||
static JSBool
|
||||
DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index)
|
||||
{
|
||||
@ -851,66 +868,18 @@ js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
|
||||
|
||||
#ifdef JS_TRACER
|
||||
|
||||
static JS_ALWAYS_INLINE JSBool FASTCALL
|
||||
dense_grow(JSContext* cx, JSObject* obj, jsint i, const Value &v)
|
||||
JSBool FASTCALL
|
||||
js_Array_dense_setelem_hole(JSContext* cx, JSObject* obj, jsint i)
|
||||
{
|
||||
JS_ASSERT(obj->isDenseArray());
|
||||
if (js_PrototypeHasIndexedProperties(cx, obj))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Let the interpreter worry about negative array indexes.
|
||||
*/
|
||||
JS_ASSERT((MAX_DSLOTS_LENGTH > MAX_DSLOTS_LENGTH32) == (sizeof(intptr_t) != sizeof(uint32)));
|
||||
if (MAX_DSLOTS_LENGTH > MAX_DSLOTS_LENGTH32) {
|
||||
/*
|
||||
* Have to check for negative values bleeding through on 64-bit machines only,
|
||||
* since we can't allocate large enough arrays for this on 32-bit machines.
|
||||
*/
|
||||
if (i < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If needed, grow the array as long it remains dense, otherwise fall off trace.
|
||||
*/
|
||||
jsuint u = jsuint(i);
|
||||
jsuint capacity = obj->getDenseArrayCapacity();
|
||||
if ((u >= capacity) && (INDEX_TOO_SPARSE(obj, u) || !obj->ensureDenseArrayElements(cx, u + 1)))
|
||||
return JS_FALSE;
|
||||
|
||||
if (obj->getDenseArrayElement(u).isMagic()) {
|
||||
if (js_PrototypeHasIndexedProperties(cx, obj))
|
||||
return JS_FALSE;
|
||||
|
||||
if (u >= obj->getArrayLength())
|
||||
obj->setArrayLength(u + 1);
|
||||
}
|
||||
|
||||
obj->setDenseArrayElement(u, v);
|
||||
return JS_TRUE;
|
||||
if (u >= obj->getArrayLength())
|
||||
obj->setArrayLength(u + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool FASTCALL
|
||||
js_Array_dense_setelem(JSContext* cx, JSObject* obj, jsint i, ValueArgType v)
|
||||
{
|
||||
return dense_grow(cx, obj, i, ValueArgToConstRef(v));
|
||||
}
|
||||
JS_DEFINE_CALLINFO_4(extern, BOOL, js_Array_dense_setelem, CONTEXT, OBJECT, INT32, VALUE,
|
||||
0, nanojit::ACCSET_STORE_ANY)
|
||||
|
||||
JSBool FASTCALL
|
||||
js_Array_dense_setelem_int(JSContext* cx, JSObject* obj, jsint i, int32 j)
|
||||
{
|
||||
return dense_grow(cx, obj, i, Int32Value(j));
|
||||
}
|
||||
JS_DEFINE_CALLINFO_4(extern, BOOL, js_Array_dense_setelem_int, CONTEXT, OBJECT, INT32, INT32,
|
||||
0, nanojit::ACCSET_STORE_ANY)
|
||||
|
||||
JSBool FASTCALL
|
||||
js_Array_dense_setelem_double(JSContext* cx, JSObject* obj, jsint i, jsdouble d)
|
||||
{
|
||||
return dense_grow(cx, obj, i, NumberValue(d));
|
||||
}
|
||||
JS_DEFINE_CALLINFO_4(extern, BOOL, js_Array_dense_setelem_double, CONTEXT, OBJECT, INT32, DOUBLE,
|
||||
JS_DEFINE_CALLINFO_3(extern, BOOL, js_Array_dense_setelem_hole, CONTEXT, OBJECT, INT32,
|
||||
0, nanojit::ACCSET_STORE_ANY)
|
||||
#endif
|
||||
|
||||
|
@ -280,4 +280,7 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone);
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_IsDensePrimitiveArray(JSObject *obj);
|
||||
|
||||
extern JSBool JS_FASTCALL
|
||||
js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i);
|
||||
|
||||
#endif /* jsarray_h___ */
|
||||
|
@ -573,12 +573,11 @@ js_dmod(jsdouble a, jsdouble b);
|
||||
#endif /* !JS_TRACER */
|
||||
|
||||
/* Defined in jsarray.cpp. */
|
||||
JS_DECLARE_CALLINFO(js_Array_dense_setelem)
|
||||
JS_DECLARE_CALLINFO(js_Array_dense_setelem_int)
|
||||
JS_DECLARE_CALLINFO(js_Array_dense_setelem_double)
|
||||
JS_DECLARE_CALLINFO(js_Array_dense_setelem_hole)
|
||||
JS_DECLARE_CALLINFO(js_NewEmptyArray)
|
||||
JS_DECLARE_CALLINFO(js_NewPreallocatedArray)
|
||||
JS_DECLARE_CALLINFO(js_ArrayCompPush_tn)
|
||||
JS_DECLARE_CALLINFO(js_EnsureDenseArrayCapacity)
|
||||
|
||||
/* Defined in jsbuiltins.cpp. */
|
||||
JS_DECLARE_CALLINFO(js_UnboxDouble)
|
||||
|
@ -9467,6 +9467,15 @@ TraceRecorder::stobj_get_fslot_uint32(LIns* obj_ins, unsigned slot)
|
||||
offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset,
|
||||
ACCSET_OTHER);
|
||||
}
|
||||
|
||||
LIns*
|
||||
TraceRecorder::stobj_set_fslot_uint32(LIns* value_ins, LIns* obj_ins, unsigned slot)
|
||||
{
|
||||
JS_ASSERT(slot < JS_INITIAL_NSLOTS);
|
||||
return lir->insStore(LIR_sti, value_ins, obj_ins,
|
||||
offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset,
|
||||
ACCSET_OTHER);
|
||||
}
|
||||
#endif
|
||||
|
||||
LIns*
|
||||
@ -9985,14 +9994,12 @@ TraceRecorder::guardHasPrototype(JSObject* obj, LIns* obj_ins,
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK RecordingStatus
|
||||
TraceRecorder::guardPrototypeHasNoIndexedProperties(JSObject* obj, LIns* obj_ins, ExitType exitType)
|
||||
TraceRecorder::guardPrototypeHasNoIndexedProperties(JSObject* obj, LIns* obj_ins, VMSideExit *exit)
|
||||
{
|
||||
/*
|
||||
* Guard that no object along the prototype chain has any indexed
|
||||
* properties which might become visible through holes in the array.
|
||||
*/
|
||||
VMSideExit* exit = snapshot(exitType);
|
||||
|
||||
if (js_PrototypeHasIndexedProperties(cx, obj))
|
||||
return RECORD_STOP;
|
||||
|
||||
@ -12683,9 +12690,10 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
|
||||
*cx->regs->pc == JSOP_INITELEM));
|
||||
} else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) {
|
||||
// Fast path: assigning to element of typed array.
|
||||
VMSideExit* branchExit = snapshot(BRANCH_EXIT);
|
||||
|
||||
// Ensure array is a typed array and is the same type as what was written
|
||||
guardClass(obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), LOAD_CONST);
|
||||
guardClass(obj_ins, obj->getClass(), branchExit, LOAD_CONST);
|
||||
|
||||
js::TypedArray* tarray = js::TypedArray::fromJSObject(obj);
|
||||
|
||||
@ -12693,8 +12701,8 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
|
||||
|
||||
// The index was on the stack and is therefore a LIR float; force it to
|
||||
// be an integer.
|
||||
idx_ins = makeNumberInt32(idx_ins);
|
||||
|
||||
idx_ins = makeNumberInt32(idx_ins);
|
||||
|
||||
// Ensure idx >= 0 && idx < length (by using uint32)
|
||||
lir->insGuard(LIR_xf,
|
||||
lir->ins2(LIR_ltui,
|
||||
@ -12798,47 +12806,71 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
|
||||
*cx->regs->pc == JSOP_INITELEM));
|
||||
} else {
|
||||
// Fast path: assigning to element of dense array.
|
||||
VMSideExit* branchExit = snapshot(BRANCH_EXIT);
|
||||
VMSideExit* mismatchExit = snapshot(MISMATCH_EXIT);
|
||||
|
||||
// Make sure the array is actually dense.
|
||||
if (!obj->isDenseArray())
|
||||
return ARECORD_STOP;
|
||||
guardDenseArray(obj_ins, BRANCH_EXIT);
|
||||
guardDenseArray(obj_ins, branchExit);
|
||||
|
||||
// The index was on the stack and is therefore a LIR float. Force it to
|
||||
// be an integer.
|
||||
idx_ins = makeNumberInt32(idx_ins);
|
||||
|
||||
// Box the value so we can use one builtin instead of having to add
|
||||
// one builtin for every storage type. Special case for integers
|
||||
// though, since they are so common; but make sure we don't rebox
|
||||
// unnecessarily.
|
||||
LIns* res_ins;
|
||||
LIns* args[] = { NULL, idx_ins, obj_ins, cx_ins };
|
||||
if (v.isNumber()) {
|
||||
if (fcallinfo(v_ins) == &js_UnboxDouble_ci) {
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
LIns *boxed = lir->insAlloc(sizeof(Value));
|
||||
LIns *tag_ins = fcallarg(v_ins, 0);
|
||||
LIns *payload_ins = fcallarg(v_ins, 1);
|
||||
lir->insStore(tag_ins, boxed, sTagOffset, ACCSET_OTHER);
|
||||
lir->insStore(payload_ins, boxed, sPayloadOffset, ACCSET_OTHER);
|
||||
args[0] = boxed;
|
||||
#else
|
||||
args[0] = fcallarg(v_ins, 0);
|
||||
#endif
|
||||
res_ins = lir->insCall(&js_Array_dense_setelem_ci, args);
|
||||
} else if (isPromoteInt(v_ins)) {
|
||||
args[0] = demote(lir, v_ins);
|
||||
res_ins = lir->insCall(&js_Array_dense_setelem_int_ci, args);
|
||||
} else {
|
||||
args[0] = v_ins;
|
||||
res_ins = lir->insCall(&js_Array_dense_setelem_double_ci, args);
|
||||
}
|
||||
} else {
|
||||
args[0] = box_value_for_native_call(v, v_ins);
|
||||
res_ins = lir->insCall(&js_Array_dense_setelem_ci, args);
|
||||
if (MAX_DSLOTS_LENGTH > MAX_DSLOTS_LENGTH32) {
|
||||
/*
|
||||
* Check for negative values bleeding through on 64-bit machines only,
|
||||
* since we can't allocate large enough arrays for this on 32-bit
|
||||
* machines.
|
||||
*/
|
||||
guard(true, lir->ins2ImmI(LIR_gei, idx_ins, 0), mismatchExit);
|
||||
}
|
||||
guard(false, lir->insEqI_0(res_ins), MISMATCH_EXIT);
|
||||
|
||||
if (!js_EnsureDenseArrayCapacity(cx, obj, idx.toInt32()))
|
||||
RETURN_STOP_A("couldn't ensure dense array capacity for setelem");
|
||||
|
||||
// Grow the array if the index exceeds the capacity. This happens
|
||||
// rarely, eg. less than 1% of the time in SunSpider.
|
||||
LIns* capacity_ins =
|
||||
addName(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_CAPACITY),
|
||||
"capacity");
|
||||
LIns* br = lir->insBranch(LIR_jt, lir->ins2(LIR_ltui, idx_ins, capacity_ins), NULL);
|
||||
LIns* args[] = { idx_ins, obj_ins, cx_ins };
|
||||
LIns* res_ins = lir->insCall(&js_EnsureDenseArrayCapacity_ci, args);
|
||||
guard(false, lir->insEqI_0(res_ins), mismatchExit);
|
||||
br->setTarget(lir->ins0(LIR_label));
|
||||
|
||||
// Get the address of the element.
|
||||
LIns *dslots_ins =
|
||||
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACCSET_OTHER), "dslots");
|
||||
JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this.
|
||||
LIns *addr_ins = lir->ins2(LIR_addp, dslots_ins,
|
||||
lir->ins2ImmI(LIR_lshp, lir->insUI2P(idx_ins), 3));
|
||||
|
||||
// If we are overwriting a hole:
|
||||
// - Guard that we don't have any indexed properties along the prototype chain.
|
||||
// - Check if the length has changed; if so, update it to index+1.
|
||||
// This happens moderately often, eg. close to 10% of the time in
|
||||
// SunSpider, and for some benchmarks it's close to 100%.
|
||||
LIns* cond = lir->ins2(LIR_eqi,
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
lir->insLoad(LIR_ldi, addr_ins, sTagOffset, ACCSET_OTHER),
|
||||
#else
|
||||
lir->ins1(LIR_q2i, lir->ins2ImmI(LIR_rshuq,
|
||||
lir->insLoad(LIR_ldq, addr_ins, 0, ACCSET_OTHER),
|
||||
JSVAL_TAG_SHIFT)),
|
||||
#endif
|
||||
INS_CONSTU(JSVAL_TAG_MAGIC));
|
||||
LIns* br2 = lir->insBranch(LIR_jf, cond, NULL);
|
||||
LIns* args2[] = { idx_ins, obj_ins, cx_ins };
|
||||
LIns* res_ins2 = addName(lir->insCall(&js_Array_dense_setelem_hole_ci, args2),
|
||||
"hasNoIndexedProperties");
|
||||
guard(false, lir->insEqI_0(res_ins2), mismatchExit);
|
||||
br2->setTarget(lir->ins0(LIR_label));
|
||||
|
||||
// Right, actually set the element.
|
||||
box_value_into(v, v_ins, addr_ins, 0, ACCSET_OTHER);
|
||||
}
|
||||
|
||||
jsbytecode* pc = cx->regs->pc;
|
||||
@ -13666,7 +13698,7 @@ TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_
|
||||
/* If not idx < capacity, stay on trace (and read value as undefined). */
|
||||
guard(true, lir->ins2(LIR_geui, idx_ins, capacity_ins), exit);
|
||||
|
||||
CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT));
|
||||
CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, snapshot(MISMATCH_EXIT)));
|
||||
|
||||
// Return undefined and indicate that we didn't actually read this (addr_ins).
|
||||
v_ins = INS_UNDEFINED();
|
||||
@ -13688,7 +13720,7 @@ TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_
|
||||
|
||||
/* Don't let the hole value escape. Turn it into an undefined. */
|
||||
if (vp->isMagic()) {
|
||||
CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT));
|
||||
CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, snapshot(MISMATCH_EXIT)));
|
||||
v_ins = INS_UNDEFINED();
|
||||
}
|
||||
return RECORD_CONTINUE;
|
||||
|
@ -1177,6 +1177,8 @@ class TraceRecorder
|
||||
nanojit::LIns* stobj_get_const_private_ptr(nanojit::LIns* obj_ins,
|
||||
unsigned slot = JSSLOT_PRIVATE);
|
||||
nanojit::LIns* stobj_get_fslot_uint32(nanojit::LIns* obj_ins, unsigned slot);
|
||||
nanojit::LIns* stobj_set_fslot_uint32(nanojit::LIns* value_ins, nanojit::LIns* obj_ins,
|
||||
unsigned slot);
|
||||
nanojit::LIns* stobj_get_fslot_ptr(nanojit::LIns* obj_ins, unsigned slot);
|
||||
nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot,
|
||||
VMSideExit *exit);
|
||||
@ -1311,8 +1313,8 @@ class TraceRecorder
|
||||
JSObject** pobj, nanojit::LIns** pobj_ins,
|
||||
VMSideExit* exit);
|
||||
JS_REQUIRES_STACK RecordingStatus guardPrototypeHasNoIndexedProperties(JSObject* obj,
|
||||
nanojit::LIns* obj_ins,
|
||||
ExitType exitType);
|
||||
nanojit::LIns* obj_ins,
|
||||
VMSideExit *exit);
|
||||
JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v);
|
||||
JS_REQUIRES_STACK JSStackFrame* entryFrame() const;
|
||||
JS_REQUIRES_STACK void clearEntryFrameSlotsFromTracker(Tracker& which);
|
||||
|
Loading…
Reference in New Issue
Block a user