Bug 500431 part 4 - Encapsulate PropertyCacheEntry::pcval. r=brendan.

This commit is contained in:
Jason Orendorff 2010-03-26 09:01:01 -05:00
parent d26dffb193
commit 785e3b6713
6 changed files with 118 additions and 112 deletions

View File

@ -2252,23 +2252,23 @@ AssertValidPropertyCacheHit(JSContext *cx, JSScript *script, JSFrameRegs& regs,
JS_ASSERT(pobj == found);
JSScopeProperty *sprop = (JSScopeProperty *) prop;
if (PCVAL_IS_SLOT(entry->vword)) {
JS_ASSERT(PCVAL_TO_SLOT(entry->vword) == sprop->slot);
if (entry->vword.isSlot()) {
JS_ASSERT(entry->vword.toSlot() == sprop->slot);
JS_ASSERT(!sprop->isMethod());
} else if (PCVAL_IS_SPROP(entry->vword)) {
JS_ASSERT(PCVAL_TO_SPROP(entry->vword) == sprop);
} else if (entry->vword.isSprop()) {
JS_ASSERT(entry->vword.toSprop() == sprop);
JS_ASSERT_IF(sprop->isMethod(),
sprop->methodValue() == LOCKED_OBJ_GET_SLOT(pobj, sprop->slot));
} else {
jsval v;
JS_ASSERT(PCVAL_IS_OBJECT(entry->vword));
JS_ASSERT(entry->vword != PCVAL_NULL);
JS_ASSERT(entry->vword.isObject());
JS_ASSERT(!entry->vword.isNull());
JS_ASSERT(OBJ_SCOPE(pobj)->brandedOrHasMethodBarrier());
JS_ASSERT(sprop->hasDefaultGetterOrIsMethod());
JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj)));
v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
JS_ASSERT(VALUE_IS_FUNCTION(cx, v));
JS_ASSERT(PCVAL_TO_OBJECT(entry->vword) == JSVAL_TO_OBJECT(v));
JS_ASSERT(entry->vword.toObject() == JSVAL_TO_OBJECT(v));
if (sprop->isMethod()) {
JS_ASSERT(js_CodeSpec[*regs.pc].format & JOF_CALLOP);

View File

@ -1223,8 +1223,8 @@ BEGIN_CASE(JSOP_NAMEDEC)
JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom);
if (!atom) {
ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
if (obj == obj2 && PCVAL_IS_SLOT(entry->vword)) {
slot = PCVAL_TO_SLOT(entry->vword);
if (obj == obj2 && entry->vword.isSlot()) {
slot = entry->vword.toSlot();
JS_ASSERT(slot < OBJ_SCOPE(obj)->freeslot);
rval = LOCKED_OBJ_GET_SLOT(obj, slot);
if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
@ -1487,15 +1487,15 @@ BEGIN_CASE(JSOP_GETXPROP)
JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom);
if (!atom) {
ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry);
if (PCVAL_IS_OBJECT(entry->vword)) {
rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
} else if (PCVAL_IS_SLOT(entry->vword)) {
slot = PCVAL_TO_SLOT(entry->vword);
if (entry->vword.isObject()) {
rval = entry->vword.toJsval();
} else if (entry->vword.isSlot()) {
slot = entry->vword.toSlot();
JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
} else {
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
sprop = PCVAL_TO_SPROP(entry->vword);
JS_ASSERT(entry->vword.isSprop());
sprop = entry->vword.toSprop();
NATIVE_GET(cx, obj, obj2, sprop,
fp->imacpc ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
&rval);
@ -1583,15 +1583,15 @@ BEGIN_CASE(JSOP_CALLPROP)
JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom);
if (!atom) {
ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry);
if (PCVAL_IS_OBJECT(entry->vword)) {
rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
} else if (PCVAL_IS_SLOT(entry->vword)) {
slot = PCVAL_TO_SLOT(entry->vword);
if (entry->vword.isObject()) {
rval = entry->vword.toJsval();
} else if (entry->vword.isSlot()) {
slot = entry->vword.toSlot();
JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
} else {
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
sprop = PCVAL_TO_SPROP(entry->vword);
JS_ASSERT(entry->vword.isSprop());
sprop = entry->vword.toSprop();
NATIVE_GET(cx, obj, obj2, sprop, JSGET_NO_METHOD_BARRIER, &rval);
}
STORE_OPND(-1, rval);
@ -1709,8 +1709,8 @@ BEGIN_CASE(JSOP_SETMETHOD)
* added directly to obj by this set, or on an existing "own"
* property, or on a prototype property that has a setter.
*/
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
sprop = PCVAL_TO_SPROP(entry->vword);
JS_ASSERT(entry->vword.isSprop());
sprop = entry->vword.toSprop();
JS_ASSERT(sprop->writable());
JS_ASSERT_IF(sprop->hasSlot(), entry->vcapTag() == 0);
@ -1843,8 +1843,8 @@ BEGIN_CASE(JSOP_SETMETHOD)
ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
sprop = NULL;
if (obj == obj2) {
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
sprop = PCVAL_TO_SPROP(entry->vword);
JS_ASSERT(entry->vword.isSprop());
sprop = entry->vword.toSprop();
JS_ASSERT(sprop->writable());
JS_ASSERT(!OBJ_SCOPE(obj2)->sealed());
NATIVE_SET(cx, obj, sprop, entry, &rval);
@ -2295,20 +2295,20 @@ BEGIN_CASE(JSOP_CALLNAME)
JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom);
if (!atom) {
ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
if (PCVAL_IS_OBJECT(entry->vword)) {
rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
if (entry->vword.isObject()) {
rval = entry->vword.toJsval();
goto do_push_rval;
}
if (PCVAL_IS_SLOT(entry->vword)) {
slot = PCVAL_TO_SLOT(entry->vword);
if (entry->vword.isSlot()) {
slot = entry->vword.toSlot();
JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
goto do_push_rval;
}
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
sprop = PCVAL_TO_SPROP(entry->vword);
JS_ASSERT(entry->vword.isSprop());
sprop = entry->vword.toSprop();
goto do_native_get;
}
} else {
@ -3400,8 +3400,8 @@ BEGIN_CASE(JSOP_INITMETHOD)
PCMETER(cache->pchits++);
PCMETER(cache->inipchits++);
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
sprop = PCVAL_TO_SPROP(entry->vword);
JS_ASSERT(entry->vword.isSprop());
sprop = entry->vword.toSprop();
JS_ASSERT(sprop->writable());
/*

View File

@ -44,6 +44,8 @@
using namespace js;
JS_STATIC_ASSERT(sizeof(PCVal) == sizeof(jsuword));
JS_REQUIRES_STACK PropertyCacheEntry *
PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoIndex,
JSObject *pobj, JSScopeProperty *sprop, JSBool adding)
@ -53,7 +55,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
jsuword kshape, vshape;
JSOp op;
const JSCodeSpec *cs;
jsuword vword;
PCVal vword;
PropertyCacheEntry *entry;
JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
@ -148,7 +150,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
v = sprop->methodValue();
JS_ASSERT(VALUE_IS_FUNCTION(cx, v));
JS_ASSERT(v == LOCKED_OBJ_GET_SLOT(pobj, sprop->slot));
vword = JSVAL_OBJECT_TO_PCVAL(v);
vword.setObject(JSVAL_TO_OBJECT(v));
break;
}
@ -182,7 +184,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
if (!scope->brand(cx, sprop->slot, v))
return JS_NO_PROP_CACHE_FILL;
}
vword = JSVAL_OBJECT_TO_PCVAL(v);
vword.setObject(JSVAL_TO_OBJECT(v));
break;
}
}
@ -193,10 +195,10 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
sprop->hasDefaultGetter() &&
SPROP_HAS_VALID_SLOT(sprop, scope)) {
/* Great, let's cache sprop's slot and use it on cache hit. */
vword = SLOT_TO_PCVAL(sprop->slot);
vword.setSlot(sprop->slot);
} else {
/* Best we can do is to cache sprop (still a nice speedup). */
vword = SPROP_TO_PCVAL(sprop);
vword.setSprop(sprop);
if (adding &&
sprop == scope->lastProperty() &&
scope->shape == sprop->shape) {
@ -290,7 +292,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
JS_ASSERT(vshape < SHAPE_OVERFLOW_BIT);
entry = &table[hash(pc, kshape)];
PCMETER(PCVAL_IS_NULL(entry->vword) || recycles++);
PCMETER(entry->vword.isNull() || recycles++);
entry->assign(pc, kshape, vshape, scopeIndex, protoIndex, vword);
empty = false;
@ -416,13 +418,11 @@ PropertyCache::assertEmpty()
JS_ASSERT(!table[i].kpc);
JS_ASSERT(!table[i].kshape);
JS_ASSERT(!table[i].vcap);
JS_ASSERT(!table[i].vword);
JS_ASSERT(table[i].vword.isNull());
}
}
#endif
JS_STATIC_ASSERT(PCVAL_NULL == 0);
void
PropertyCache::purge(JSContext *cx)
{
@ -432,6 +432,7 @@ PropertyCache::purge(JSContext *cx)
}
PodArrayZero(table);
JS_ASSERT(table[0].vword.isNull());
empty = true;
#ifdef JS_PROPERTY_CACHE_METERING
@ -497,7 +498,8 @@ PropertyCache::purgeForScript(JSScript *script)
if (JS_UPTRDIFF(entry->kpc, script->code) < script->length) {
entry->kpc = NULL;
#ifdef DEBUG
entry->kshape = entry->vcap = entry->vword = 0;
entry->kshape = entry->vcap = 0;
entry->vword.setNull();
#endif
}
}

View File

@ -69,12 +69,51 @@ enum {
const uint32 SHAPE_OVERFLOW_BIT = JS_BIT(32 - PCVCAP_TAGBITS);
/*
* Property cache value. This is simply a tagged union:
* PCVal = (JSObject * | uint32 | JSScopeProperty *).
* It is the type of PropertyCacheEntry::vword and combines with the tag bits
* of PropertyCacheEntry::vcap to tell how to get or set the property, once a
* property cache hit is validated.
*
* PropertyCache::purge depends on the bit-pattern of a null PCVal being 0.
*/
class PCVal
{
private:
enum {
OBJECT = 0,
SLOT = 1,
SPROP = 2,
TAG = 3
};
jsuword v;
public:
bool isNull() const { return v == 0; }
void setNull() { v = 0; }
bool isObject() const { return (v & TAG) == OBJECT; }
JSObject *toObject() const { JS_ASSERT(isObject()); return reinterpret_cast<JSObject *>(v); }
jsval toJsval() const { return OBJECT_TO_JSVAL(toObject()); }
void setObject(JSObject *obj) { v = reinterpret_cast<jsuword>(obj); }
bool isSlot() const { return v & SLOT; }
uint32 toSlot() const { JS_ASSERT(isSlot()); return uint32(v) >> 1; }
void setSlot(uint32 slot) { v = (jsuword(slot) << 1) | SLOT; }
bool isSprop() const { return (v & TAG) == SPROP; }
JSScopeProperty *toSprop() const { JS_ASSERT(isSprop()); return reinterpret_cast<JSScopeProperty *>(v & ~TAG); }
void setSprop(JSScopeProperty *sprop) { JS_ASSERT(sprop); v = reinterpret_cast<jsuword>(sprop) | SPROP; }
};
struct PropertyCacheEntry
{
jsbytecode *kpc; /* pc of cache-testing bytecode */
jsuword kshape; /* shape of direct (key) object */
jsuword vcap; /* value capability, see above */
jsuword vword; /* value word, see PCVAL_* below */
PCVal vword; /* value word, see PCVal above */
bool adding() const { return vcapTag() == 0 && kshape != vshape(); }
bool directHit() const { return vcapTag() == 0 && kshape == vshape(); }
@ -85,7 +124,7 @@ struct PropertyCacheEntry
jsuword protoIndex() const { return vcap & PCVCAP_PROTOMASK; }
void assign(jsbytecode *kpc, jsuword kshape, jsuword vshape,
uintN scopeIndex, uintN protoIndex, jsuword vword) {
uintN scopeIndex, uintN protoIndex, PCVal vword) {
JS_ASSERT(kshape < SHAPE_OVERFLOW_BIT);
JS_ASSERT(vshape < SHAPE_OVERFLOW_BIT);
JS_ASSERT(scopeIndex <= PCVCAP_SCOPEMASK);
@ -195,41 +234,6 @@ struct PropertyCache
#endif
};
/*
* Property cache value tagging/untagging macros.
*/
enum {
PCVAL_OBJECT = 0,
PCVAL_SLOT = 1,
PCVAL_SPROP = 2,
PCVAL_TAGBITS = 2,
PCVAL_TAGMASK = JS_BITMASK(PCVAL_TAGBITS),
PCVAL_NULL = 0
};
inline jsuword PCVAL_TAG(jsuword v) { return v & PCVAL_TAGMASK; }
inline jsuword PCVAL_CLRTAG(jsuword v) { return v & ~jsuword(PCVAL_TAGMASK); }
inline jsuword PCVAL_SETTAG(jsuword v, jsuword t) { return v | t; }
inline bool PCVAL_IS_NULL(jsuword v) { return v == PCVAL_NULL; }
inline bool PCVAL_IS_OBJECT(jsuword v) { return PCVAL_TAG(v) == PCVAL_OBJECT; }
inline JSObject *PCVAL_TO_OBJECT(jsuword v) { JS_ASSERT(PCVAL_IS_OBJECT(v)); return (JSObject *) v; }
inline jsuword OBJECT_TO_PCVAL(JSObject *obj) { return jsuword(obj); }
inline jsval PCVAL_OBJECT_TO_JSVAL(jsuword v) { return OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v)); }
inline jsuword JSVAL_OBJECT_TO_PCVAL(jsval v) { return OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v)); }
inline bool PCVAL_IS_SLOT(jsuword v) { return v & PCVAL_SLOT; }
inline jsuint PCVAL_TO_SLOT(jsuword v) { JS_ASSERT(PCVAL_IS_SLOT(v)); return jsuint(v) >> 1; }
inline jsuword SLOT_TO_PCVAL(jsuint i) { return (jsuword(i) << 1) | PCVAL_SLOT; }
inline bool PCVAL_IS_SPROP(jsuword v) { return PCVAL_TAG(v) == PCVAL_SPROP; }
inline JSScopeProperty *PCVAL_TO_SPROP(jsuword v) { JS_ASSERT(PCVAL_IS_SPROP(v)); return (JSScopeProperty *) PCVAL_CLRTAG(v); }
inline jsuword SPROP_TO_PCVAL(JSScopeProperty *sprop) { return PCVAL_SETTAG(jsuword(sprop), PCVAL_SPROP); }
} /* namespace js */
#endif /* jspropertycache_h___ */

View File

@ -9145,7 +9145,7 @@ TraceRecorder::guardNativePropertyOp(JSObject* aobj, LIns* map_ins)
}
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, jsuword& pcval)
TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, PCVal& pcval)
{
jsbytecode* pc = cx->fp->regs->pc;
JS_ASSERT(*pc != JSOP_INITPROP && *pc != JSOP_INITMETHOD &&
@ -9223,8 +9223,8 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
// the global it's assigning does not yet exist, create it.
obj2 = obj;
// Use PCVAL_NULL to return "no such property" to our caller.
pcval = PCVAL_NULL;
// Use a null pcval to return "no such property" to our caller.
pcval.setNull();
return ARECORD_CONTINUE;
}
@ -9250,7 +9250,7 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins,
JSObject* aobj,
JSObject* obj2,
PropertyCacheEntry* entry,
jsuword& pcval)
PCVal& pcval)
{
VMSideExit* exit = snapshot(BRANCH_EXIT);
@ -11292,7 +11292,7 @@ TraceRecorder::setProp(jsval &l, PropertyCacheEntry* entry, JSScopeProperty* spr
// Guard before anything else.
LIns* map_ins = map(obj_ins);
CHECK_STATUS(guardNativePropertyOp(obj, map_ins));
jsuword pcval;
PCVal pcval;
CHECK_STATUS(guardPropertyCacheHit(obj_ins, map_ins, obj, obj2, entry, pcval));
JS_ASSERT(scope->object == obj2);
JS_ASSERT(scope->hasProperty(sprop));
@ -12202,16 +12202,16 @@ TraceRecorder::record_JSOP_CALLNAME()
LIns* obj_ins = INS_CONSTOBJ(globalObj);
JSObject* obj2;
jsuword pcval;
PCVal pcval;
CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval));
if (PCVAL_IS_NULL(pcval) || !PCVAL_IS_OBJECT(pcval))
if (pcval.isNull() || !pcval.isObject())
RETURN_STOP_A("callee is not an object");
JS_ASSERT(HAS_FUNCTION_CLASS(PCVAL_TO_OBJECT(pcval)));
JS_ASSERT(HAS_FUNCTION_CLASS(pcval.toObject()));
stack(0, INS_CONSTOBJ(PCVAL_TO_OBJECT(pcval)));
stack(0, INS_CONSTOBJ(pcval.toObject()));
stack(1, obj_ins);
return ARECORD_CONTINUE;
}
@ -12757,7 +12757,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr)
uint32 slot;
JSObject* obj2;
jsuword pcval;
PCVal pcval;
/*
* Property cache ensures that we are dealing with an existing property,
@ -12766,7 +12766,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr)
CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval));
/* Abort if property doesn't exist (interpreter will report an error.) */
if (PCVAL_IS_NULL(pcval))
if (pcval.isNull())
RETURN_STOP_A("named property not found");
/* Insist on obj being the directly addressed object. */
@ -12774,15 +12774,15 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr)
RETURN_STOP_A("name() hit prototype chain");
/* Don't trace getter or setter calls, our caller wants a direct slot. */
if (PCVAL_IS_SPROP(pcval)) {
JSScopeProperty* sprop = PCVAL_TO_SPROP(pcval);
if (pcval.isSprop()) {
JSScopeProperty* sprop = pcval.toSprop();
if (!isValidSlot(OBJ_SCOPE(obj), sprop))
RETURN_STOP_A("name() not accessing a valid slot");
slot = sprop->slot;
} else {
if (!PCVAL_IS_SLOT(pcval))
if (!pcval.isSlot())
RETURN_STOP_A("PCE is not a slot");
slot = PCVAL_TO_SLOT(pcval);
slot = pcval.toSlot();
}
if (!lazilyImportGlobalSlot(slot))
@ -12831,11 +12831,11 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp,
* and guards the shape for us.
*/
JSObject* obj2;
jsuword pcval;
PCVal pcval;
CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval));
/* Check for non-existent property reference, which results in undefined. */
if (PCVAL_IS_NULL(pcval)) {
if (pcval.isNull()) {
if (slotp)
RETURN_STOP_A("property not found");
@ -12876,7 +12876,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp,
}
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, jsuword pcval,
TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcval,
uint32 *slotp, LIns** v_insp, jsval *outp)
{
const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
@ -12887,8 +12887,8 @@ TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, jsuword pc
uint32 slot;
bool isMethod;
if (PCVAL_IS_SPROP(pcval)) {
sprop = PCVAL_TO_SPROP(pcval);
if (pcval.isSprop()) {
sprop = pcval.toSprop();
JS_ASSERT(OBJ_SCOPE(obj2)->hasProperty(sprop));
if (setflags && !sprop->hasDefaultSetter())
@ -12910,9 +12910,9 @@ TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, jsuword pc
isMethod = sprop->isMethod();
JS_ASSERT_IF(isMethod, OBJ_SCOPE(obj2)->hasMethodBarrier());
} else {
if (!PCVAL_IS_SLOT(pcval))
if (!pcval.isSlot())
RETURN_STOP_A("PCE is not a slot");
slot = PCVAL_TO_SLOT(pcval);
slot = pcval.toSlot();
sprop = NULL;
isMethod = false;
}
@ -14606,27 +14606,27 @@ TraceRecorder::record_JSOP_CALLPROP()
}
JSObject* obj2;
jsuword pcval;
PCVal pcval;
CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval));
if (PCVAL_IS_OBJECT(pcval)) {
if (PCVAL_IS_NULL(pcval))
if (pcval.isObject()) {
if (pcval.isNull())
RETURN_STOP_A("callprop of missing method");
JS_ASSERT(HAS_FUNCTION_CLASS(PCVAL_TO_OBJECT(pcval)));
JS_ASSERT(HAS_FUNCTION_CLASS(pcval.toObject()));
if (JSVAL_IS_PRIMITIVE(l)) {
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, PCVAL_TO_OBJECT(pcval));
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, pcval.toObject());
if (!PRIMITIVE_THIS_TEST(fun, l))
RETURN_STOP_A("callee does not accept primitive |this|");
}
set(&l, INS_CONSTOBJ(PCVAL_TO_OBJECT(pcval)));
set(&l, INS_CONSTOBJ(pcval.toObject()));
} else {
if (JSVAL_IS_PRIMITIVE(l))
RETURN_STOP_A("callprop of primitive method");
JS_ASSERT_IF(PCVAL_IS_SPROP(pcval), !PCVAL_TO_SPROP(pcval)->isMethod());
JS_ASSERT_IF(pcval.isSprop(), !pcval.toSprop()->isMethod());
AbortableRecordingStatus status = propTail(obj, obj_ins, obj2, pcval, NULL, NULL, &l);
if (status != ARECORD_CONTINUE)

View File

@ -1208,7 +1208,7 @@ class TraceRecorder
JS_REQUIRES_STACK bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins,
nanojit::LIns*& ops_ins, size_t op_offset = 0);
JS_REQUIRES_STACK AbortableRecordingStatus test_property_cache(JSObject* obj, nanojit::LIns* obj_ins,
JSObject*& obj2, jsuword& pcval);
JSObject*& obj2, PCVal& pcval);
JS_REQUIRES_STACK RecordingStatus guardNativePropertyOp(JSObject* aobj,
nanojit::LIns* map_ins);
JS_REQUIRES_STACK RecordingStatus guardPropertyCacheHit(nanojit::LIns* obj_ins,
@ -1216,7 +1216,7 @@ class TraceRecorder
JSObject* aobj,
JSObject* obj2,
PropertyCacheEntry* entry,
jsuword& pcval);
PCVal& pcval);
void stobj_set_fslot(nanojit::LIns *obj_ins, unsigned slot,
nanojit::LIns* v_ins);
@ -1249,7 +1249,7 @@ class TraceRecorder
uint32 *slotp, nanojit::LIns** v_insp,
jsval* outp);
JS_REQUIRES_STACK AbortableRecordingStatus propTail(JSObject* obj, nanojit::LIns* obj_ins,
JSObject* obj2, jsuword pcval,
JSObject* obj2, PCVal pcval,
uint32 *slotp, nanojit::LIns** v_insp,
jsval* outp);
JS_REQUIRES_STACK RecordingStatus denseArrayElement(jsval& oval, jsval& idx, jsval*& vp,