mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-27 20:25:44 +00:00
Backed out changeset e09130fcb013
This commit is contained in:
parent
19c9082e33
commit
d366588e38
@ -964,8 +964,6 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
||||
0, /* JSOP_DEFFUN_DBGFC */
|
||||
0, /* JSOP_DEFLOCALFUN_DBGFC */
|
||||
0, /* JSOP_LAMBDA_DBGFC */
|
||||
0, /* JSOP_SETMETHOD */
|
||||
0, /* JSOP_INITMETHOD */
|
||||
};
|
||||
#define JSOP_IS_IMACOP(x) (0 \
|
||||
|| x == JSOP_BITOR \
|
||||
|
@ -3544,7 +3544,7 @@ JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
||||
jsval *vp)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, vp))
|
||||
if (!js_GetMethod(cx, obj, id, false, vp))
|
||||
return JS_FALSE;
|
||||
if (objp)
|
||||
*objp = obj;
|
||||
|
@ -792,7 +792,7 @@ array_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
if (prop) {
|
||||
if (OBJ_IS_NATIVE(obj2)) {
|
||||
sprop = (JSScopeProperty *) prop;
|
||||
if (!js_NativeGet(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, vp))
|
||||
if (!js_NativeGet(cx, obj, obj2, sprop, vp))
|
||||
return JS_FALSE;
|
||||
}
|
||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||
|
@ -337,9 +337,9 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, IN
|
||||
jsval FASTCALL
|
||||
js_CallGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
|
||||
{
|
||||
JS_ASSERT(!SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop));
|
||||
JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop));
|
||||
jsval v;
|
||||
if (!sprop->get(cx, obj, &v))
|
||||
if (!js_GetSprop(cx, sprop, obj, &v))
|
||||
return JSVAL_ERROR_COOKIE;
|
||||
return v;
|
||||
}
|
||||
|
@ -6529,15 +6529,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
ale = cg->atomList.add(cg->compiler, pn3->pn_atom);
|
||||
if (!ale)
|
||||
return JS_FALSE;
|
||||
|
||||
JSOp initOp = (PN_OP(pn2->pn_right) == JSOP_LAMBDA
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
&& op != JSOP_GETTER && op != JSOP_SETTER
|
||||
#endif
|
||||
)
|
||||
? JSOP_INITMETHOD
|
||||
: JSOP_INITPROP;
|
||||
EMIT_INDEX_OP(initOp, ALE_INDEX(ale));
|
||||
EMIT_INDEX_OP(JSOP_INITPROP, ALE_INDEX(ale));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
* vim: set ts=8 sw=4 et tw=79:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
@ -184,36 +184,22 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
||||
* is a plain old method? It's a function-valued property with stub
|
||||
* getter, so get of a function is idempotent.
|
||||
*/
|
||||
if (cs->format & JOF_CALLOP) {
|
||||
if ((cs->format & JOF_CALLOP) &&
|
||||
SPROP_HAS_STUB_GETTER(sprop) &&
|
||||
SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
||||
jsval v;
|
||||
|
||||
if (sprop->isMethod()) {
|
||||
/*
|
||||
* A compiler-created function object, AKA a method, already
|
||||
* memoized in the property tree.
|
||||
*/
|
||||
JS_ASSERT(scope->hasMethodBarrier());
|
||||
v = sprop->methodValue();
|
||||
JS_ASSERT(VALUE_IS_FUNCTION(cx, v));
|
||||
vword = JSVAL_OBJECT_TO_PCVAL(v);
|
||||
break;
|
||||
}
|
||||
|
||||
if (SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop) &&
|
||||
SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
||||
v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
|
||||
if (VALUE_IS_FUNCTION(cx, v)) {
|
||||
/*
|
||||
* Great, we have a function-valued prototype property
|
||||
* where the getter is JS_PropertyStub. The type id in
|
||||
* pobj's scope does not evolve with changes to property
|
||||
* values, however.
|
||||
* Great, we have a function-valued prototype property where
|
||||
* the getter is JS_PropertyStub. The type id in pobj's scope
|
||||
* does not evolve with changes to property values, however.
|
||||
*
|
||||
* So here, on first cache fill for this method, we brand
|
||||
* the scope with a new shape and set the SCOPE_BRANDED
|
||||
* flag. Once this scope flag is set, any write that adds
|
||||
* or deletes a function-valued plain old property in
|
||||
* scope->object will result in shape being regenerated.
|
||||
* So here, on first cache fill for this method, we brand the
|
||||
* scope with a new shape and set the SCOPE_BRANDED flag. Once
|
||||
* this scope flag is set, any write to a function-valued plain
|
||||
* old property in pobj will result in shape being regenerated.
|
||||
*/
|
||||
if (!scope->branded()) {
|
||||
PCMETER(cache->brandfills++);
|
||||
@ -234,11 +220,10 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If getting a value via a stub getter, we can cache the slot. */
|
||||
if (!(cs->format & (JOF_SET | JOF_INCDEC | JOF_FOR)) &&
|
||||
SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop) &&
|
||||
SPROP_HAS_STUB_GETTER(sprop) &&
|
||||
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);
|
||||
@ -250,30 +235,30 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
||||
scope->shape == sprop->shape) {
|
||||
/*
|
||||
* Our caller added a new property. We also know that a setter
|
||||
* that js_NativeSet could have run has not mutated the scope,
|
||||
* so the added property is still the last one added, and the
|
||||
* that js_NativeSet could have run has not mutated the scope
|
||||
* so the added property is still the last one added and the
|
||||
* scope is not branded.
|
||||
*
|
||||
* We want to cache under scope's shape before the property
|
||||
* addition to bias for the case when the mutator opcode
|
||||
* always adds the same property. This allows us to optimize
|
||||
* periodic execution of object initializers or other explicit
|
||||
* initialization sequences such as
|
||||
* always adds the same property. It allows to optimize
|
||||
* periodic execution of object initializers or explicit
|
||||
* initialization sequences like
|
||||
*
|
||||
* obj = {}; obj.x = 1; obj.y = 2;
|
||||
*
|
||||
* We assume that on average the win from this optimization is
|
||||
* greater than the cost of an extra mismatch per loop owing to
|
||||
* bigger that the cost of an extra mismatch per loop due to
|
||||
* the bias for the following case:
|
||||
*
|
||||
* obj = {}; ... for (...) { ... obj.x = ... }
|
||||
*
|
||||
* On the first iteration of such a for loop, JSOP_SETPROP
|
||||
* fills the cache with the shape of the newly created object
|
||||
* obj, not the shape of obj after obj.x has been assigned.
|
||||
* That mismatches obj's shape on the second iteration. Note
|
||||
* that on the third and subsequent iterations the cache will
|
||||
* be hit because the shape is no longer updated.
|
||||
* On the first iteration JSOP_SETPROP fills the cache with
|
||||
* the shape of newly created object, not the shape after
|
||||
* obj.x is assigned. That mismatches obj's shape on the
|
||||
* second iteration. Note that on third and the following
|
||||
* iterations the cache will be hit since the shape no longer
|
||||
* mutates.
|
||||
*/
|
||||
JS_ASSERT(scope->owned());
|
||||
if (sprop->parent) {
|
||||
@ -1004,7 +989,7 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp)
|
||||
|
||||
MUST_FLOW_THROUGH("out");
|
||||
id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
|
||||
ok = js_GetMethod(cx, obj, id, 0, &tvr.u.value);
|
||||
ok = js_GetMethod(cx, obj, id, false, &tvr.u.value);
|
||||
if (!ok)
|
||||
goto out;
|
||||
if (JSVAL_IS_PRIMITIVE(tvr.u.value)) {
|
||||
@ -2147,9 +2132,9 @@ js_TraceOpcode(JSContext *cx)
|
||||
fp->script, cx->tracePrevPc);
|
||||
|
||||
/*
|
||||
* If there aren't that many elements on the stack, then we have
|
||||
* probably entered a new frame, and printing output would just be
|
||||
* misleading.
|
||||
* If there aren't that many elements on the stack, then
|
||||
* we have probably entered a new frame, and printing output
|
||||
* would just be misleading.
|
||||
*/
|
||||
if (ndefs != 0 &&
|
||||
ndefs < regs->sp - fp->slots) {
|
||||
@ -2615,7 +2600,7 @@ AssertValidPropertyCacheHit(JSContext *cx, JSScript *script, JSFrameRegs& regs,
|
||||
JS_ASSERT(PCVAL_IS_OBJECT(entry->vword));
|
||||
JS_ASSERT(entry->vword != PCVAL_NULL);
|
||||
JS_ASSERT(OBJ_SCOPE(pobj)->branded());
|
||||
JS_ASSERT(SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop));
|
||||
JS_ASSERT(SPROP_HAS_STUB_GETTER(sprop));
|
||||
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));
|
||||
@ -2652,11 +2637,9 @@ JS_STATIC_ASSERT(JSOP_DEFFUN_FC_LENGTH == JSOP_DEFFUN_DBGFC_LENGTH);
|
||||
|
||||
/*
|
||||
* Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
|
||||
* remain distinct for the decompiler. Likewise for JSOP_INIT{PROP,METHOD}.
|
||||
* remain distinct for the decompiler.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
|
||||
JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETMETHOD_LENGTH);
|
||||
JS_STATIC_ASSERT(JSOP_INITPROP_LENGTH == JSOP_INITMETHOD_LENGTH);
|
||||
|
||||
/* See TRY_BRANCH_AFTER_COND. */
|
||||
JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
|
||||
@ -2717,6 +2700,14 @@ js_Interpret(JSContext *cx)
|
||||
#endif
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define JS_EXTENSION __extension__
|
||||
# define JS_EXTENSION_(s) __extension__ ({ s; })
|
||||
#else
|
||||
# define JS_EXTENSION
|
||||
# define JS_EXTENSION_(s) s
|
||||
#endif
|
||||
|
||||
# ifdef DEBUG
|
||||
/*
|
||||
* We call this macro from BEGIN_CASE in threaded interpreters,
|
||||
@ -3619,7 +3610,7 @@ js_Interpret(JSContext *cx)
|
||||
goto error; \
|
||||
JS_END_MACRO
|
||||
|
||||
#define NATIVE_GET(cx,obj,pobj,sprop,getHow,vp) \
|
||||
#define NATIVE_GET(cx,obj,pobj,sprop,vp) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (SPROP_HAS_STUB_GETTER(sprop)) { \
|
||||
/* Fast path for Object instance properties. */ \
|
||||
@ -3629,7 +3620,7 @@ js_Interpret(JSContext *cx)
|
||||
? LOCKED_OBJ_GET_SLOT(pobj, (sprop)->slot) \
|
||||
: JSVAL_VOID; \
|
||||
} else { \
|
||||
if (!js_NativeGet(cx, obj, pobj, sprop, getHow, vp)) \
|
||||
if (!js_NativeGet(cx, obj, pobj, sprop, vp)) \
|
||||
goto error; \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
@ -4490,7 +4481,7 @@ js_Interpret(JSContext *cx)
|
||||
} else {
|
||||
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
||||
sprop = PCVAL_TO_SPROP(entry->vword);
|
||||
NATIVE_GET(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, &rval);
|
||||
NATIVE_GET(cx, obj, obj2, sprop, &rval);
|
||||
}
|
||||
JS_UNLOCK_OBJ(cx, obj2);
|
||||
break;
|
||||
@ -4504,9 +4495,7 @@ js_Interpret(JSContext *cx)
|
||||
}
|
||||
id = ATOM_TO_JSID(atom);
|
||||
if (entry
|
||||
? !js_GetPropertyHelper(cx, obj, id,
|
||||
JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
|
||||
&rval)
|
||||
? !js_GetPropertyHelper(cx, obj, id, true, &rval)
|
||||
: !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
|
||||
goto error;
|
||||
}
|
||||
@ -4583,7 +4572,7 @@ js_Interpret(JSContext *cx)
|
||||
} else {
|
||||
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
||||
sprop = PCVAL_TO_SPROP(entry->vword);
|
||||
NATIVE_GET(cx, obj, obj2, sprop, 0, &rval);
|
||||
NATIVE_GET(cx, obj, obj2, sprop, &rval);
|
||||
}
|
||||
JS_UNLOCK_OBJ(cx, obj2);
|
||||
STORE_OPND(-1, rval);
|
||||
@ -4602,13 +4591,13 @@ js_Interpret(JSContext *cx)
|
||||
id = ATOM_TO_JSID(atom);
|
||||
PUSH(JSVAL_NULL);
|
||||
if (!JSVAL_IS_PRIMITIVE(lval)) {
|
||||
if (!js_GetMethod(cx, obj, id, entry ? JSGET_CACHE_RESULT : 0, &rval))
|
||||
if (!js_GetMethod(cx, obj, id, !!entry, &rval))
|
||||
goto error;
|
||||
STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
|
||||
STORE_OPND(-2, rval);
|
||||
} else {
|
||||
JS_ASSERT(obj->map->ops->getProperty == js_GetProperty);
|
||||
if (!js_GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, &rval))
|
||||
if (!js_GetPropertyHelper(cx, obj, id, true, &rval))
|
||||
goto error;
|
||||
STORE_OPND(-1, lval);
|
||||
STORE_OPND(-2, rval);
|
||||
@ -4639,12 +4628,9 @@ js_Interpret(JSContext *cx)
|
||||
|
||||
BEGIN_CASE(JSOP_SETNAME)
|
||||
BEGIN_CASE(JSOP_SETPROP)
|
||||
BEGIN_CASE(JSOP_SETMETHOD)
|
||||
do_setprop:
|
||||
rval = FETCH_OPND(-1);
|
||||
JS_ASSERT_IF(op == JSOP_SETMETHOD, VALUE_IS_FUNCTION(cx, rval));
|
||||
lval = FETCH_OPND(-2);
|
||||
JS_ASSERT_IF(op == JSOP_SETNAME, !JSVAL_IS_PRIMITIVE(lval));
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval) || op == JSOP_SETPROP);
|
||||
VALUE_TO_OBJECT(cx, -2, lval, obj);
|
||||
|
||||
do {
|
||||
@ -4798,21 +4784,9 @@ js_Interpret(JSContext *cx)
|
||||
sprop = sprop2;
|
||||
} else {
|
||||
scope->extend(cx, sprop);
|
||||
|
||||
jsuint index;
|
||||
if (js_IdIsIndex(sprop->id, &index))
|
||||
scope->setIndexedProperties();
|
||||
|
||||
if (sprop->isMethod())
|
||||
scope->setMethodBarrier();
|
||||
}
|
||||
|
||||
/*
|
||||
* No LOCKED_OBJ_WRITE_BARRIER because here we
|
||||
* are adding a new property, not updating an
|
||||
* existing slot's value that might contain a
|
||||
* method of a branded scope.
|
||||
*/
|
||||
LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, rval);
|
||||
TRACE_2(SetPropHit, entry, sprop);
|
||||
LOCKED_OBJ_SET_SLOT(obj, slot, rval);
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
@ -4856,10 +4830,7 @@ js_Interpret(JSContext *cx)
|
||||
LOAD_ATOM(0);
|
||||
id = ATOM_TO_JSID(atom);
|
||||
if (entry) {
|
||||
uintN defineHow = (op == JSOP_SETMETHOD)
|
||||
? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD
|
||||
: JSDNP_CACHE_RESULT;
|
||||
if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval))
|
||||
if (!js_SetPropertyHelper(cx, obj, id, true, &rval))
|
||||
goto error;
|
||||
} else {
|
||||
if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
|
||||
@ -4916,7 +4887,7 @@ js_Interpret(JSContext *cx)
|
||||
END_CASE(JSOP_GETELEM)
|
||||
|
||||
BEGIN_CASE(JSOP_CALLELEM)
|
||||
ELEMENT_OP(-1, js_GetMethod(cx, obj, id, 0, &rval));
|
||||
ELEMENT_OP(-1, js_GetMethod(cx, obj, id, false, &rval));
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) {
|
||||
regs.sp[-2] = regs.sp[-1];
|
||||
@ -5370,7 +5341,7 @@ js_Interpret(JSContext *cx)
|
||||
} else {
|
||||
sprop = (JSScopeProperty *)prop;
|
||||
do_native_get:
|
||||
NATIVE_GET(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, &rval);
|
||||
NATIVE_GET(cx, obj, obj2, sprop, &rval);
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *) sprop);
|
||||
}
|
||||
|
||||
@ -5951,7 +5922,7 @@ js_Interpret(JSContext *cx)
|
||||
sprop = (JSScopeProperty *) prop;
|
||||
if ((sprop->attrs & JSPROP_PERMANENT) &&
|
||||
SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)) &&
|
||||
SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop) &&
|
||||
SPROP_HAS_STUB_GETTER(sprop) &&
|
||||
SPROP_HAS_STUB_SETTER(sprop)) {
|
||||
/*
|
||||
* Fast globals use frame variables to map the global
|
||||
@ -6245,64 +6216,23 @@ js_Interpret(JSContext *cx)
|
||||
obj = FUN_OBJECT(fun);
|
||||
|
||||
if (FUN_NULL_CLOSURE(fun)) {
|
||||
parent = fp->scopeChain;
|
||||
|
||||
if (OBJ_GET_PARENT(cx, obj) == parent) {
|
||||
JSScope *scope;
|
||||
|
||||
lval = FETCH_OPND(-1);
|
||||
op = JSOp(regs.pc[JSOP_LAMBDA_LENGTH]);
|
||||
|
||||
/*
|
||||
* Optimize ({method: function () { ... }, ...}) and
|
||||
* this.method = function () { ... }; bytecode sequences.
|
||||
*
|
||||
* Note that we jump to the entry points for JSOP_SETPROP
|
||||
* and JSOP_INITPROP without calling the trace recorder,
|
||||
* because the record hooks for those ops are essentially
|
||||
* no-ops (this can't change given the predictive shape
|
||||
* guarding the recorder must do).
|
||||
*/
|
||||
if (op == JSOP_SETMETHOD) {
|
||||
#ifdef DEBUG
|
||||
op2 = JSOp(regs.pc[JSOP_LAMBDA_LENGTH + JSOP_SETMETHOD_LENGTH]);
|
||||
JS_ASSERT(op2 == JSOP_POP || op2 == JSOP_POPV);
|
||||
#endif
|
||||
|
||||
if (JSVAL_IS_OBJECT(lval) &&
|
||||
(obj2 = JSVAL_TO_OBJECT(lval)) &&
|
||||
OBJ_GET_CLASS(cx, obj2) == &js_ObjectClass) {
|
||||
scope = OBJ_SCOPE(obj2);
|
||||
if (scope->object == obj2) {
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||
regs.pc += JSOP_LAMBDA_LENGTH;
|
||||
goto do_setprop;
|
||||
}
|
||||
}
|
||||
} else if (op == JSOP_INITMETHOD) {
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval));
|
||||
obj2 = JSVAL_TO_OBJECT(lval);
|
||||
scope = OBJ_SCOPE(obj2);
|
||||
|
||||
/*
|
||||
* JSOP_NEWINIT gave the new object it created (obj2
|
||||
* here) its own scope.
|
||||
*/
|
||||
JS_ASSERT(scope->object == obj2);
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||
regs.pc += JSOP_LAMBDA_LENGTH;
|
||||
goto do_initprop;
|
||||
}
|
||||
}
|
||||
obj = js_CloneFunctionObject(cx, fun, fp->scopeChain);
|
||||
if (!obj)
|
||||
goto error;
|
||||
} else {
|
||||
parent = js_GetScopeChain(cx, fp);
|
||||
if (!parent)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: bug 471214, Cloning here even when the compiler saw
|
||||
* the right parent is wasteful but we don't fully support
|
||||
* joined function objects, yet.
|
||||
*/
|
||||
obj = js_CloneFunctionObject(cx, fun, parent);
|
||||
if (!obj)
|
||||
goto error;
|
||||
}
|
||||
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||
END_CASE(JSOP_LAMBDA)
|
||||
@ -6449,26 +6379,11 @@ js_Interpret(JSContext *cx)
|
||||
BEGIN_CASE(JSOP_NEWINIT)
|
||||
i = GET_INT8(regs.pc);
|
||||
JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
|
||||
if (i == JSProto_Array) {
|
||||
obj = js_NewArrayObject(cx, 0, NULL);
|
||||
obj = (i == JSProto_Array)
|
||||
? js_NewArrayObject(cx, 0, NULL)
|
||||
: js_NewObject(cx, &js_ObjectClass, NULL, NULL);
|
||||
if (!obj)
|
||||
goto error;
|
||||
} else {
|
||||
obj = js_NewObject(cx, &js_ObjectClass, NULL, NULL);
|
||||
if (!obj)
|
||||
goto error;
|
||||
|
||||
if (regs.pc[JSOP_NEWINIT_LENGTH] != JSOP_ENDINIT) {
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
JSScope *scope = js_GetMutableScope(cx, obj);
|
||||
if (!scope) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
goto error;
|
||||
}
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||
fp->sharpDepth++;
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
@ -6486,8 +6401,6 @@ js_Interpret(JSContext *cx)
|
||||
END_CASE(JSOP_ENDINIT)
|
||||
|
||||
BEGIN_CASE(JSOP_INITPROP)
|
||||
BEGIN_CASE(JSOP_INITMETHOD)
|
||||
do_initprop:
|
||||
/* Load the property's initial value into rval. */
|
||||
JS_ASSERT(regs.sp - StackBase(fp) >= 2);
|
||||
rval = FETCH_OPND(-1);
|
||||
@ -6508,7 +6421,6 @@ js_Interpret(JSContext *cx)
|
||||
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
scope = OBJ_SCOPE(obj);
|
||||
JS_ASSERT(scope->object == obj);
|
||||
JS_ASSERT(!scope->sealed());
|
||||
kshape = scope->shape;
|
||||
cache = &JS_PROPERTY_CACHE(cx);
|
||||
@ -6538,6 +6450,14 @@ js_Interpret(JSContext *cx)
|
||||
if (!SPROP_HAS_STUB_SETTER(sprop))
|
||||
goto do_initprop_miss;
|
||||
|
||||
if (!scope->owned()) {
|
||||
scope = js_GetMutableScope(cx, obj);
|
||||
if (!scope) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect a repeated property name and force a miss to
|
||||
* share the strict warning code and cope with complexity
|
||||
@ -6588,11 +6508,7 @@ js_Interpret(JSContext *cx)
|
||||
scope->lastProp = sprop;
|
||||
}
|
||||
|
||||
/*
|
||||
* No LOCKED_OBJ_WRITE_BARRIER because here we are adding a
|
||||
* new property, not updating an existing slot's value that
|
||||
* might contain a method of a branded scope.
|
||||
*/
|
||||
LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, rval);
|
||||
TRACE_2(SetPropHit, entry, sprop);
|
||||
LOCKED_OBJ_SET_SLOT(obj, slot, rval);
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
@ -6613,16 +6529,12 @@ js_Interpret(JSContext *cx)
|
||||
goto error;
|
||||
}
|
||||
|
||||
uintN defineHow = (op == JSOP_INITMETHOD)
|
||||
? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD
|
||||
: JSDNP_CACHE_RESULT;
|
||||
if (!(JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
|
||||
? js_SetPropertyHelper(cx, obj, id, defineHow, &rval)
|
||||
? js_SetPropertyHelper(cx, obj, id, true, &rval)
|
||||
: js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
|
||||
JSPROP_ENUMERATE, 0, 0, NULL,
|
||||
defineHow))) {
|
||||
JSDNP_CACHE_RESULT)))
|
||||
goto error;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
/* Common tail for property cache hit and miss cases. */
|
||||
|
@ -376,7 +376,7 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)
|
||||
*vp = OBJECT_TO_JSVAL(iterobj);
|
||||
} else {
|
||||
atom = cx->runtime->atomState.iteratorAtom;
|
||||
if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), 0, vp))
|
||||
if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), false, vp))
|
||||
goto bad;
|
||||
if (JSVAL_IS_VOID(*vp)) {
|
||||
default_iter:
|
||||
|
113
js/src/jsobj.cpp
113
js/src/jsobj.cpp
@ -418,7 +418,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
||||
JSScopeProperty *sprop = (JSScopeProperty *) prop;
|
||||
val = JSVAL_NULL;
|
||||
if (attrs & JSPROP_GETTER)
|
||||
val = sprop->getterValue();
|
||||
val = js_CastAsObjectJSVal(sprop->getter);
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
if (val != JSVAL_NULL) {
|
||||
/* Mark the getter, then set val to setter. */
|
||||
@ -426,7 +426,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
||||
NULL)
|
||||
!= NULL);
|
||||
}
|
||||
val = sprop->setterValue();
|
||||
val = js_CastAsObjectJSVal(sprop->setter);
|
||||
}
|
||||
} else {
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
|
||||
@ -782,7 +782,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
(attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
|
||||
JSScopeProperty *sprop = (JSScopeProperty *) prop;
|
||||
if (attrs & JSPROP_GETTER) {
|
||||
val[valcnt] = sprop->getterValue();
|
||||
val[valcnt] = js_CastAsObjectJSVal(sprop->getter);
|
||||
gsopold[valcnt] =
|
||||
ATOM_TO_STRING(cx->runtime->atomState.getterAtom);
|
||||
gsop[valcnt] =
|
||||
@ -791,7 +791,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
valcnt++;
|
||||
}
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
val[valcnt] = sprop->setterValue();
|
||||
val[valcnt] = js_CastAsObjectJSVal(sprop->setter);
|
||||
gsopold[valcnt] =
|
||||
ATOM_TO_STRING(cx->runtime->atomState.setterAtom);
|
||||
gsop[valcnt] =
|
||||
@ -1905,7 +1905,7 @@ obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp)
|
||||
if (OBJ_IS_NATIVE(pobj)) {
|
||||
sprop = (JSScopeProperty *) prop;
|
||||
if (sprop->attrs & JSPROP_GETTER)
|
||||
*vp = sprop->getterValue();
|
||||
*vp = js_CastAsObjectJSVal(sprop->getter);
|
||||
}
|
||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||
}
|
||||
@ -1930,7 +1930,7 @@ obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp)
|
||||
if (OBJ_IS_NATIVE(pobj)) {
|
||||
sprop = (JSScopeProperty *) prop;
|
||||
if (sprop->attrs & JSPROP_SETTER)
|
||||
*vp = sprop->setterValue();
|
||||
*vp = js_CastAsObjectJSVal(sprop->setter);
|
||||
}
|
||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||
}
|
||||
@ -3557,8 +3557,6 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSScope *scope;
|
||||
JSScopeProperty *sprop;
|
||||
|
||||
JS_ASSERT(!(flags & SPROP_IS_METHOD));
|
||||
|
||||
/*
|
||||
* Purge the property cache of now-shadowed id in obj's scope chain. Do
|
||||
* this optimistically (assuming no failure below) before locking obj, so
|
||||
@ -3640,7 +3638,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
JSScopeProperty *sprop;
|
||||
JSBool added;
|
||||
|
||||
JS_ASSERT((defineHow & ~(JSDNP_CACHE_RESULT | JSDNP_DONT_PURGE | JSDNP_SET_METHOD)) == 0);
|
||||
JS_ASSERT((defineHow & ~(JSDNP_CACHE_RESULT | JSDNP_DONT_PURGE)) == 0);
|
||||
js_LeaveTraceIfGlobalObject(cx, obj);
|
||||
|
||||
/* Convert string indices to integers if appropriate. */
|
||||
@ -3712,12 +3710,10 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
|
||||
/* Use the object's class getter and setter by default. */
|
||||
clasp = LOCKED_OBJ_GET_CLASS(obj);
|
||||
if (!(defineHow & JSDNP_SET_METHOD)) {
|
||||
if (!getter)
|
||||
getter = clasp->getProperty;
|
||||
if (!setter)
|
||||
setter = clasp->setProperty;
|
||||
}
|
||||
|
||||
/* Get obj's own scope if it has one, or create a new one for obj. */
|
||||
scope = js_GetMutableScope(cx, obj);
|
||||
@ -3729,16 +3725,6 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
/* Add a new property, or replace an existing one of the same id. */
|
||||
if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)
|
||||
attrs |= JSPROP_SHARED;
|
||||
|
||||
if (defineHow & JSDNP_SET_METHOD) {
|
||||
JS_ASSERT(LOCKED_OBJ_GET_CLASS(obj) == &js_ObjectClass);
|
||||
JS_ASSERT(VALUE_IS_FUNCTION(cx, value));
|
||||
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
|
||||
JS_ASSERT(!getter && !setter);
|
||||
flags |= SPROP_IS_METHOD;
|
||||
getter = js_CastAsPropertyOp(JSVAL_TO_OBJECT(value));
|
||||
}
|
||||
|
||||
sprop = scope->add(cx, id, getter, setter, SPROP_INVALID_SLOT, attrs,
|
||||
flags, shortid);
|
||||
if (!sprop)
|
||||
@ -3747,12 +3733,8 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
}
|
||||
|
||||
/* Store value before calling addProperty, in case the latter GC's. */
|
||||
if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
||||
if (added)
|
||||
LOCKED_OBJ_SET_SLOT(obj, sprop->slot, value);
|
||||
else
|
||||
LOCKED_OBJ_WRITE_BARRIER(cx, obj, sprop->slot, value);
|
||||
}
|
||||
if (SPROP_HAS_VALID_SLOT(sprop, scope))
|
||||
LOCKED_OBJ_WRITE_SLOT(cx, obj, sprop->slot, value);
|
||||
|
||||
/* XXXbe called with lock held */
|
||||
ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, &value,
|
||||
@ -4156,7 +4138,7 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
|
||||
|
||||
JSBool
|
||||
js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
|
||||
JSScopeProperty *sprop, uintN getHow, jsval *vp)
|
||||
JSScopeProperty *sprop, jsval *vp)
|
||||
{
|
||||
js_LeaveTraceIfGlobalObject(cx, pobj);
|
||||
|
||||
@ -4175,20 +4157,17 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
|
||||
? LOCKED_OBJ_GET_SLOT(pobj, slot)
|
||||
: JSVAL_VOID;
|
||||
if (SPROP_HAS_STUB_GETTER(sprop))
|
||||
return true;
|
||||
|
||||
if (JS_UNLIKELY(sprop->isMethod()) && !(getHow & JSGET_METHOD_BARRIER))
|
||||
return true;
|
||||
return JS_TRUE;
|
||||
|
||||
sample = cx->runtime->propertyRemovals;
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, pobj, &tvr2);
|
||||
ok = sprop->get(cx, obj, vp);
|
||||
ok = js_GetSprop(cx, sprop, obj, vp);
|
||||
JS_POP_TEMP_ROOT(cx, &tvr2);
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
if (!ok)
|
||||
return false;
|
||||
return JS_FALSE;
|
||||
|
||||
JS_LOCK_SCOPE(cx, scope);
|
||||
if (SLOT_IN_SCOPE(slot, scope) &&
|
||||
@ -4197,7 +4176,7 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
|
||||
LOCKED_OBJ_SET_SLOT(pobj, slot, *vp);
|
||||
}
|
||||
|
||||
return true;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
@ -4241,7 +4220,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp)
|
||||
sample = cx->runtime->propertyRemovals;
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);
|
||||
ok = sprop->set(cx, obj, vp);
|
||||
ok = js_SetSprop(cx, sprop, obj, vp);
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
@ -4258,7 +4237,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp)
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
||||
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
|
||||
jsval *vp)
|
||||
{
|
||||
JSObject *aobj, *obj2;
|
||||
@ -4266,8 +4245,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
||||
JSProperty *prop;
|
||||
JSScopeProperty *sprop;
|
||||
|
||||
JS_ASSERT_IF(getHow & JSGET_CACHE_RESULT, !JS_ON_TRACE(cx));
|
||||
|
||||
JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx));
|
||||
/* Convert string indices to integers if appropriate. */
|
||||
id = js_CheckForStringIndex(id);
|
||||
|
||||
@ -4282,7 +4260,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
||||
if (!OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, ID_TO_VALUE(id), vp))
|
||||
return JS_FALSE;
|
||||
|
||||
PCMETER(getHow & JSGET_CACHE_RESULT && JS_PROPERTY_CACHE(cx).nofills++);
|
||||
PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).nofills++);
|
||||
|
||||
/*
|
||||
* Give a strict warning if foo.bar is evaluated by a script for an
|
||||
@ -4343,12 +4321,12 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
||||
|
||||
sprop = (JSScopeProperty *) prop;
|
||||
|
||||
if (getHow & JSGET_CACHE_RESULT) {
|
||||
if (cacheResult) {
|
||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||
js_FillPropertyCache(cx, aobj, 0, protoIndex, obj2, sprop, false);
|
||||
}
|
||||
|
||||
if (!js_NativeGet(cx, obj, obj2, sprop, getHow, vp))
|
||||
if (!js_NativeGet(cx, obj, obj2, sprop, vp))
|
||||
return JS_FALSE;
|
||||
|
||||
JS_UNLOCK_OBJ(cx, obj2);
|
||||
@ -4358,19 +4336,20 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
||||
JSBool
|
||||
js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
return js_GetPropertyHelper(cx, obj, id, JSGET_METHOD_BARRIER, vp);
|
||||
return js_GetPropertyHelper(cx, obj, id, false, vp);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, jsval *vp)
|
||||
js_GetMethod(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
|
||||
jsval *vp)
|
||||
{
|
||||
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
|
||||
|
||||
if (obj->map->ops == &js_ObjectOps ||
|
||||
obj->map->ops->getProperty == js_GetProperty) {
|
||||
return js_GetPropertyHelper(cx, obj, id, getHow, vp);
|
||||
return js_GetPropertyHelper(cx, obj, id, cacheResult, vp);
|
||||
}
|
||||
JS_ASSERT_IF(getHow & JSGET_CACHE_RESULT, OBJ_IS_DENSE_ARRAY(cx, obj));
|
||||
JS_ASSERT_IF(cacheResult, OBJ_IS_DENSE_ARRAY(cx, obj));
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
if (OBJECT_IS_XML(cx, obj))
|
||||
return js_GetXMLMethod(cx, obj, id, vp);
|
||||
@ -4401,11 +4380,10 @@ js_CheckUndeclaredVarAssignment(JSContext *cx)
|
||||
|
||||
/*
|
||||
* Note: all non-error exits in this function must notify the tracer using
|
||||
* SetPropHit when called from the interpreter, which is detected by testing
|
||||
* (defineHow & JSDNP_CACHE_RESULT).
|
||||
* SetPropHit when called from the interpreter loop (cacheResult is true).
|
||||
*/
|
||||
JSBool
|
||||
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
|
||||
jsval *vp)
|
||||
{
|
||||
int protoIndex;
|
||||
@ -4419,8 +4397,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
JSPropertyOp getter, setter;
|
||||
bool added;
|
||||
|
||||
JS_ASSERT((defineHow & ~(JSDNP_CACHE_RESULT | JSDNP_SET_METHOD)) == 0);
|
||||
if (defineHow & JSDNP_CACHE_RESULT)
|
||||
if (cacheResult)
|
||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||
|
||||
/* Convert string indices to integers if appropriate. */
|
||||
@ -4493,8 +4470,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
if (attrs & JSPROP_READONLY) {
|
||||
if (!JS_HAS_STRICT_OPTION(cx)) {
|
||||
/* Just return true per ECMA if not in strict mode. */
|
||||
PCMETER((defineHow & JSDNP_CACHE_RESULT) && JS_PROPERTY_CACHE(cx).rofills++);
|
||||
if (defineHow & JSDNP_CACHE_RESULT)
|
||||
PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).rofills++);
|
||||
if (cacheResult)
|
||||
TRACE_2(SetPropHit, JS_NO_PROP_CACHE_FILL, sprop);
|
||||
return JS_TRUE;
|
||||
error: // TRACE_2 jumps here in case of error.
|
||||
@ -4507,10 +4484,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
goto read_only_error;
|
||||
}
|
||||
|
||||
if (pobj == obj) {
|
||||
if (!(defineHow & JSDNP_SET_METHOD) != !sprop->isMethod())
|
||||
sprop = NULL;
|
||||
} else {
|
||||
if (pobj != obj) {
|
||||
/*
|
||||
* We found id in a prototype object: prepare to share or shadow.
|
||||
*
|
||||
@ -4522,7 +4496,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
|
||||
/* Don't clone a shared prototype property. */
|
||||
if (attrs & JSPROP_SHARED) {
|
||||
if (defineHow & JSDNP_CACHE_RESULT) {
|
||||
if (cacheResult) {
|
||||
JSPropCacheEntry *entry;
|
||||
entry = js_FillPropertyCache(cx, obj, 0, protoIndex, pobj, sprop, false);
|
||||
TRACE_2(SetPropHit, entry, sprop);
|
||||
@ -4533,7 +4507,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
return sprop->set(cx, obj, vp);
|
||||
return js_SetSprop(cx, sprop, obj, vp);
|
||||
}
|
||||
|
||||
/* Restore attrs to the ECMA default for new properties. */
|
||||
@ -4580,23 +4554,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)
|
||||
attrs |= JSPROP_SHARED;
|
||||
|
||||
/*
|
||||
* Check for Object class here to avoid defining a method on a class
|
||||
* with magic resolve, addProperty, getProperty, etc. hooks.
|
||||
*/
|
||||
if ((defineHow & JSDNP_SET_METHOD) &&
|
||||
LOCKED_OBJ_GET_CLASS(obj) == &js_ObjectClass) {
|
||||
JS_ASSERT(VALUE_IS_FUNCTION(cx, *vp));
|
||||
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
|
||||
flags |= SPROP_IS_METHOD;
|
||||
getter = JS_EXTENSION (JSPropertyOp) JSVAL_TO_OBJECT(*vp);
|
||||
setter = NULL;
|
||||
}
|
||||
|
||||
sprop = scope->add(cx, id, getter, setter, SPROP_INVALID_SLOT, attrs,
|
||||
flags, shortid);
|
||||
if (!sprop) {
|
||||
@ -4620,7 +4579,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
added = true;
|
||||
}
|
||||
|
||||
if (defineHow & JSDNP_CACHE_RESULT) {
|
||||
if (cacheResult) {
|
||||
JSPropCacheEntry *entry;
|
||||
entry = js_FillPropertyCache(cx, obj, 0, 0, obj, sprop, added);
|
||||
TRACE_2(SetPropHit, entry, sprop);
|
||||
@ -4799,7 +4758,7 @@ js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
|
||||
}
|
||||
|
||||
if (sprop &&
|
||||
SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop) &&
|
||||
SPROP_HAS_STUB_GETTER(sprop) &&
|
||||
SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
||||
jsval fval = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
|
||||
|
||||
@ -5589,7 +5548,7 @@ js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom,
|
||||
older = JS_SetErrorReporter(cx, NULL);
|
||||
id = ATOM_TO_JSID(atom);
|
||||
fval = JSVAL_VOID;
|
||||
ok = js_GetMethod(cx, obj, id, 0, &fval);
|
||||
ok = js_GetMethod(cx, obj, id, false, &fval);
|
||||
if (!ok)
|
||||
JS_ClearPendingException(cx);
|
||||
JS_SetErrorReporter(cx, older);
|
||||
|
@ -664,9 +664,6 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
*/
|
||||
const uintN JSDNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */
|
||||
const uintN JSDNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */
|
||||
const uintN JSDNP_SET_METHOD = 4; /* js_{DefineNativeProperty,SetPropertyHelper}
|
||||
must pass the SPROP_IS_METHOD flag on to
|
||||
js_AddScopeProperty */
|
||||
|
||||
extern JSBool
|
||||
js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
@ -715,17 +712,6 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id);
|
||||
extern JSObject *
|
||||
js_FindVariableScope(JSContext *cx, JSFunction **funp);
|
||||
|
||||
/*
|
||||
* JSGET_CACHE_RESULT is the analogue of JSDNP_CACHE_RESULT for js_GetMethod.
|
||||
*
|
||||
* JSGET_METHOD_BARRIER enables a read barrier that preserves standard function
|
||||
* object semantics (by default we assume our caller won't leak a joined callee
|
||||
* to script, where it would create hazardous mutable object sharing as well as
|
||||
* observable identity according to == and ===.
|
||||
*/
|
||||
const uintN JSGET_CACHE_RESULT = 1; // call from a caching interpreter opcode
|
||||
const uintN JSGET_METHOD_BARRIER = 2; // caller may leak shared function object
|
||||
|
||||
/*
|
||||
* NB: js_NativeGet and js_NativeSet are called with the scope containing sprop
|
||||
* (pobj's scope for Get, obj's for Set) locked, and on successful return, that
|
||||
@ -734,20 +720,21 @@ const uintN JSGET_METHOD_BARRIER = 2; // caller may leak shared function object
|
||||
*/
|
||||
extern JSBool
|
||||
js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
|
||||
JSScopeProperty *sprop, uintN getHow, jsval *vp);
|
||||
JSScopeProperty *sprop, jsval *vp);
|
||||
|
||||
extern JSBool
|
||||
js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp);
|
||||
|
||||
extern JSBool
|
||||
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
||||
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
|
||||
jsval *vp);
|
||||
|
||||
extern JSBool
|
||||
js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
|
||||
|
||||
extern JSBool
|
||||
js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, jsval *vp);
|
||||
js_GetMethod(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
|
||||
jsval *vp);
|
||||
|
||||
/*
|
||||
* Check whether it is OK to assign an undeclared property of the global
|
||||
@ -757,7 +744,7 @@ extern JS_FRIEND_API(JSBool)
|
||||
js_CheckUndeclaredVarAssignment(JSContext *cx);
|
||||
|
||||
extern JSBool
|
||||
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
|
||||
jsval *vp);
|
||||
|
||||
extern JSBool
|
||||
|
@ -3823,7 +3823,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
goto do_getprop;
|
||||
|
||||
case JSOP_SETPROP:
|
||||
case JSOP_SETMETHOD:
|
||||
LOAD_ATOM(0);
|
||||
GET_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval);
|
||||
rval = POP_STR();
|
||||
@ -4485,7 +4484,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
break;
|
||||
|
||||
case JSOP_INITPROP:
|
||||
case JSOP_INITMETHOD:
|
||||
LOAD_ATOM(0);
|
||||
xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),
|
||||
(jschar)
|
||||
|
@ -582,16 +582,10 @@ OPDEF(JSOP_OBJTOP, 227,"objtop", NULL, 3, 0, 0, 0, JOF_UINT16
|
||||
OPDEF(JSOP_LOOP, 228, "loop", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
||||
/*
|
||||
* Debugger versions of JSOP_{GET,CALL}UPVAR and the flat closure (_FC) ops.
|
||||
* Debugger versions of JSOP_{GET,CALL}UPVAR.
|
||||
*/
|
||||
OPDEF(JSOP_GETUPVAR_DBG, 229,"getupvar_dbg", NULL, 3, 0, 1, 19, JOF_UINT16|JOF_NAME)
|
||||
OPDEF(JSOP_CALLUPVAR_DBG, 230,"callupvar_dbg", NULL, 3, 0, 2, 19, JOF_UINT16|JOF_NAME|JOF_CALLOP)
|
||||
OPDEF(JSOP_DEFFUN_DBGFC, 231,"deffun_dbgfc", NULL, 3, 0, 0, 0, JOF_OBJECT|JOF_DECLARING)
|
||||
OPDEF(JSOP_DEFLOCALFUN_DBGFC,232,"deflocalfun_dbgfc",NULL, 5, 0, 0, 0, JOF_SLOTOBJECT|JOF_DECLARING)
|
||||
OPDEF(JSOP_LAMBDA_DBGFC, 233,"lambda_dbgfc", NULL, 3, 0, 1, 19, JOF_OBJECT)
|
||||
|
||||
/*
|
||||
* Joined function object as method optimization support.
|
||||
*/
|
||||
OPDEF(JSOP_SETMETHOD, 234,"setmethod", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
|
||||
OPDEF(JSOP_INITMETHOD, 235,"initprop", NULL, 3, 1, 0, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
|
||||
|
@ -5508,18 +5508,6 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
pn->pn_type = TOK_SEMI;
|
||||
pn->pn_pos = pn2->pn_pos;
|
||||
pn->pn_kid = pn2;
|
||||
|
||||
/*
|
||||
* Specialize JSOP_SETPROP into JSOP_SETMETHOD to defer or avoid null
|
||||
* closure cloning. Do this here rather than in AssignExpr as only now
|
||||
* do we know that the uncloned (unjoined in ES3 terms) function object
|
||||
* result of the assignment expression can't escape.
|
||||
*/
|
||||
if (PN_TYPE(pn2) == TOK_ASSIGN && PN_OP(pn2) == JSOP_NOP &&
|
||||
PN_OP(pn2->pn_left) == JSOP_SETPROP &&
|
||||
PN_OP(pn2->pn_right) == JSOP_LAMBDA) {
|
||||
pn2->pn_left->pn_op = JSOP_SETMETHOD;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -444,13 +444,12 @@ js_HashScopeProperty(JSDHashTable *table, const void *key)
|
||||
|
||||
/* Accumulate from least to most random so the low bits are most random. */
|
||||
hash = 0;
|
||||
JS_ASSERT_IF(sprop->isMethod(), !sprop->setter);
|
||||
gsop = sprop->getter;
|
||||
if (gsop)
|
||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsword(gsop);
|
||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsword)gsop;
|
||||
gsop = sprop->setter;
|
||||
if (gsop)
|
||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsword(gsop);
|
||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsword)gsop;
|
||||
|
||||
hash = JS_ROTATE_LEFT32(hash, 4)
|
||||
^ (sprop->flags & ~SPROP_FLAGS_NOT_MATCHED);
|
||||
@ -1055,9 +1054,6 @@ JSScope::add(JSContext *cx, jsid id,
|
||||
JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, this));
|
||||
CHECK_ANCESTOR_LINE(this, true);
|
||||
|
||||
JS_ASSERT_IF(attrs & JSPROP_GETTER, getter);
|
||||
JS_ASSERT_IF(attrs & JSPROP_SETTER, setter);
|
||||
|
||||
/*
|
||||
* You can't add properties to a sealed scope. But note well that you can
|
||||
* change property attributes in a sealed scope, even though that replaces
|
||||
@ -1073,17 +1069,10 @@ JSScope::add(JSContext *cx, jsid id,
|
||||
* Normalize stub getter and setter values for faster is-stub testing in
|
||||
* the SPROP_CALL_[GS]ETTER macros.
|
||||
*/
|
||||
if (setter == JS_PropertyStub)
|
||||
setter = NULL;
|
||||
if (flags & SPROP_IS_METHOD) {
|
||||
/* Here, getter is the method, a function object reference. */
|
||||
JS_ASSERT(getter);
|
||||
JS_ASSERT(!setter);
|
||||
JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
|
||||
} else {
|
||||
if (getter == JS_PropertyStub)
|
||||
getter = NULL;
|
||||
}
|
||||
if (setter == JS_PropertyStub)
|
||||
setter = NULL;
|
||||
|
||||
/*
|
||||
* Search for id in order to claim its entry, allocating a property tree
|
||||
@ -1365,9 +1354,6 @@ JSScope::add(JSContext *cx, jsid id,
|
||||
if (js_IdIsIndex(sprop->id, &index))
|
||||
setIndexedProperties();
|
||||
|
||||
if (sprop->isMethod())
|
||||
setMethodBarrier();
|
||||
|
||||
METER(adds);
|
||||
return sprop;
|
||||
|
||||
@ -1669,11 +1655,11 @@ JSScopeProperty::trace(JSTracer *trc)
|
||||
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
|
||||
if (attrs & JSPROP_GETTER) {
|
||||
JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, this, 0);
|
||||
JS_CallTracer(trc, getterObject(), JSTRACE_OBJECT);
|
||||
JS_CallTracer(trc, js_CastAsObject(getter), JSTRACE_OBJECT);
|
||||
}
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, this, 1);
|
||||
JS_CallTracer(trc, setterObject(), JSTRACE_OBJECT);
|
||||
JS_CallTracer(trc, js_CastAsObject(setter), JSTRACE_OBJECT);
|
||||
}
|
||||
}
|
||||
#endif /* JS_HAS_GETTER_SETTER */
|
||||
|
168
js/src/jsscope.h
168
js/src/jsscope.h
@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
@ -286,13 +286,12 @@ struct JSScope {
|
||||
BRANDED = 0x0004,
|
||||
INDEXED_PROPERTIES = 0x0008,
|
||||
OWN_SHAPE = 0x0010,
|
||||
METHOD_BARRIER = 0x0020,
|
||||
|
||||
/*
|
||||
* This flag toggles with each shape-regenerating GC cycle.
|
||||
* See JSRuntime::gcRegenShapesScopeFlag.
|
||||
*/
|
||||
SHAPE_REGEN = 0x0040
|
||||
SHAPE_REGEN = 0x0020
|
||||
};
|
||||
|
||||
bool hadMiddleDelete() { return flags & MIDDLE_DELETE; }
|
||||
@ -323,42 +322,6 @@ struct JSScope {
|
||||
|
||||
bool hasRegenFlag(uint8 regenFlag) { return (flags & SHAPE_REGEN) == regenFlag; }
|
||||
|
||||
/*
|
||||
* A scope has a method barrier when some compiler-created "null closure"
|
||||
* function objects (functions that do not use lexical bindings above their
|
||||
* scope, only free variable names) that have a correct JSSLOT_PARENT value
|
||||
* thanks to the COMPILE_N_GO optimization are stored as newly added direct
|
||||
* property values.
|
||||
*
|
||||
* The de-facto standard JS language requires each evaluation of such a
|
||||
* closure to result in a unique (according to === and observable effects)
|
||||
* function object. ES3 tried to allow implementations to "join" such
|
||||
* objects to a single compiler-created object, but this makes an overt
|
||||
* mutation hazard, also an "identity hazard" against interoperation among
|
||||
* implementations that join and do not join.
|
||||
*
|
||||
* To stay compatible with the de-facto standard, we store the compiler-
|
||||
* created function object as the method value, set the METHOD_BARRIER
|
||||
* flag, and brand the scope with a predictable shape that reflects its
|
||||
* method values, which are cached and traced without being loaded, based
|
||||
* on shape-qualified cache hit logic and equivalent trace guards. See
|
||||
* BRANDED above.
|
||||
*
|
||||
* This means scope->hasMethodBarrier() => scope->branded(), but of course
|
||||
* not the other way around.
|
||||
*
|
||||
* Then when reading from a scope for which scope->hasMethodBarrier() is
|
||||
* true, we count on the scope's qualified/guarded shape being unique and
|
||||
* add a read barrier that clones the compiler-created function object on
|
||||
* demand, reshaping the scope.
|
||||
*
|
||||
* This read barrier is bypassed when evaluating the callee sub-expression
|
||||
* of a call expression (see the JOF_CALLOP opcodes in jsopcode.tbl), since
|
||||
* such ops do not present an identity or mutation hazard.
|
||||
*/
|
||||
bool hasMethodBarrier() { return flags & METHOD_BARRIER; }
|
||||
void setMethodBarrier() { flags |= METHOD_BARRIER | BRANDED; }
|
||||
|
||||
bool owned() { return object != NULL; }
|
||||
};
|
||||
|
||||
@ -400,8 +363,7 @@ js_CastAsPropertyOp(JSObject *object)
|
||||
struct JSScopeProperty {
|
||||
jsid id; /* int-tagged jsval/untagged JSAtom* */
|
||||
JSPropertyOp getter; /* getter and setter hooks or objects */
|
||||
JSPropertyOp setter; /* getter is JSObject* and setter is 0
|
||||
if sprop->isMethod() */
|
||||
JSPropertyOp setter;
|
||||
uint32 slot; /* abstract index in object slots */
|
||||
uint8 attrs; /* attributes, see jsapi.h JSPROP_* */
|
||||
uint8 flags; /* flags, see below for defines */
|
||||
@ -411,53 +373,6 @@ struct JSScopeProperty {
|
||||
to many-kids data structure */
|
||||
uint32 shape; /* property cache shape identifier */
|
||||
|
||||
/* Bits stored in sprop->flags. */
|
||||
#define SPROP_MARK 0x01
|
||||
#define SPROP_IS_ALIAS 0x02
|
||||
#define SPROP_HAS_SHORTID 0x04
|
||||
#define SPROP_FLAG_SHAPE_REGEN 0x08
|
||||
#define SPROP_IS_METHOD 0x10
|
||||
|
||||
bool isMethod() const {
|
||||
return flags & SPROP_IS_METHOD;
|
||||
}
|
||||
JSObject *method() const {
|
||||
JS_ASSERT(isMethod());
|
||||
return js_CastAsObject(getter);
|
||||
}
|
||||
jsval methodValue() const {
|
||||
JS_ASSERT(isMethod());
|
||||
return js_CastAsObjectJSVal(getter);
|
||||
}
|
||||
|
||||
bool hasGetter() const {
|
||||
return attrs & JSPROP_GETTER;
|
||||
}
|
||||
JSObject *getterObject() const {
|
||||
JS_ASSERT(hasGetter());
|
||||
return js_CastAsObject(getter);
|
||||
}
|
||||
jsval getterValue() const {
|
||||
JS_ASSERT(hasGetter());
|
||||
return js_CastAsObjectJSVal(getter);
|
||||
}
|
||||
|
||||
bool hasSetter() const {
|
||||
return attrs & JSPROP_SETTER;
|
||||
}
|
||||
JSObject *setterObject() const {
|
||||
JS_ASSERT(hasSetter());
|
||||
return js_CastAsObject(setter);
|
||||
}
|
||||
jsval setterValue() const {
|
||||
JS_ASSERT(hasSetter());
|
||||
return js_CastAsObjectJSVal(setter);
|
||||
}
|
||||
|
||||
bool methodBarrier(JSContext *cx, JSObject *obj, jsval *vp);
|
||||
bool get(JSContext* cx, JSObject* obj, jsval* vp);
|
||||
bool set(JSContext* cx, JSObject* obj, jsval* vp);
|
||||
|
||||
void trace(JSTracer *trc);
|
||||
};
|
||||
|
||||
@ -493,6 +408,12 @@ JSScope::has(JSScopeProperty *sprop)
|
||||
return lookup(sprop->id) == sprop;
|
||||
}
|
||||
|
||||
/* Bits stored in sprop->flags. */
|
||||
#define SPROP_MARK 0x01
|
||||
#define SPROP_IS_ALIAS 0x02
|
||||
#define SPROP_HAS_SHORTID 0x04
|
||||
#define SPROP_FLAG_SHAPE_REGEN 0x08
|
||||
|
||||
/*
|
||||
* If SPROP_HAS_SHORTID is set in sprop->flags, we use sprop->shortid rather
|
||||
* than id when calling sprop's getter or setter.
|
||||
@ -509,9 +430,6 @@ JSScope::has(JSScopeProperty *sprop)
|
||||
#define SPROP_HAS_STUB_GETTER(sprop) (!(sprop)->getter)
|
||||
#define SPROP_HAS_STUB_SETTER(sprop) (!(sprop)->setter)
|
||||
|
||||
#define SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop) \
|
||||
(SPROP_HAS_STUB_GETTER(sprop) || (sprop)->isMethod())
|
||||
|
||||
#ifndef JS_THREADSAFE
|
||||
# define js_GenerateShape(cx, gcLocked) js_GenerateShape (cx)
|
||||
#endif
|
||||
@ -633,47 +551,15 @@ JSScope::trace(JSTracer *trc)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read barrier for deferred cloning of compiler-created function objects
|
||||
* optimized as typically non-escaping, ad-hoc methods in obj.
|
||||
*/
|
||||
JS_ALWAYS_INLINE bool
|
||||
JSScopeProperty::methodBarrier(JSContext *cx, JSObject *obj, jsval *vp)
|
||||
static JS_INLINE bool
|
||||
js_GetSprop(JSContext* cx, JSScopeProperty* sprop, JSObject* obj, jsval* vp)
|
||||
{
|
||||
JSScope *scope = OBJ_SCOPE(obj);
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(scope->title.ownercx == cx);
|
||||
#endif
|
||||
JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop));
|
||||
|
||||
if (scope->hasMethodBarrier()) {
|
||||
JSObject *funobj = JSVAL_TO_OBJECT(*vp);
|
||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||
|
||||
if (FUN_OBJECT(fun) == funobj && FUN_INTERPRETED(fun)) {
|
||||
funobj = js_CloneFunctionObject(cx, fun, OBJ_GET_PARENT(cx, funobj));
|
||||
if (!funobj)
|
||||
return false;
|
||||
*vp = OBJECT_TO_JSVAL(funobj);
|
||||
return js_SetPropertyHelper(cx, obj, id, 0, vp);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
JSScopeProperty::get(JSContext* cx, JSObject* obj, jsval* vp)
|
||||
{
|
||||
JS_ASSERT(!SPROP_HAS_STUB_GETTER(this));
|
||||
|
||||
if (attrs & JSPROP_GETTER) {
|
||||
JS_ASSERT(!isMethod());
|
||||
jsval fval = getterValue();
|
||||
return js_InternalGetOrSet(cx, obj, id, fval, JSACC_READ, 0, 0, vp);
|
||||
}
|
||||
|
||||
if (isMethod()) {
|
||||
*vp = methodValue();
|
||||
return methodBarrier(cx, obj, vp);
|
||||
if (sprop->attrs & JSPROP_GETTER) {
|
||||
jsval fval = js_CastAsObjectJSVal(sprop->getter);
|
||||
return js_InternalGetOrSet(cx, obj, sprop->id, fval, JSACC_READ,
|
||||
0, 0, vp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -684,28 +570,30 @@ JSScopeProperty::get(JSContext* cx, JSObject* obj, jsval* vp)
|
||||
*/
|
||||
if (STOBJ_GET_CLASS(obj) == &js_WithClass)
|
||||
obj = obj->map->ops->thisObject(cx, obj);
|
||||
return getter(cx, obj, SPROP_USERID(this), vp);
|
||||
return sprop->getter(cx, obj, SPROP_USERID(sprop), vp);
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
JSScopeProperty::set(JSContext* cx, JSObject* obj, jsval* vp)
|
||||
static JS_INLINE bool
|
||||
js_SetSprop(JSContext* cx, JSScopeProperty* sprop, JSObject* obj, jsval* vp)
|
||||
{
|
||||
JS_ASSERT_IF(SPROP_HAS_STUB_SETTER(this), attrs & JSPROP_GETTER);
|
||||
JS_ASSERT(!(SPROP_HAS_STUB_SETTER(sprop) &&
|
||||
!(sprop->attrs & JSPROP_GETTER)));
|
||||
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
jsval fval = setterValue();
|
||||
return js_InternalGetOrSet(cx, obj, id, fval, JSACC_WRITE, 1, vp, vp);
|
||||
if (sprop->attrs & JSPROP_SETTER) {
|
||||
jsval fval = js_CastAsObjectJSVal(sprop->setter);
|
||||
return js_InternalGetOrSet(cx, obj, (sprop)->id, fval, JSACC_WRITE,
|
||||
1, vp, vp);
|
||||
}
|
||||
|
||||
if (attrs & JSPROP_GETTER) {
|
||||
if (sprop->attrs & JSPROP_GETTER) {
|
||||
js_ReportGetterOnlyAssignment(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* See the comment in JSScopeProperty::get as to why we can check for With. */
|
||||
/* See the comment in js_GetSprop as to why we can check for 'with'. */
|
||||
if (STOBJ_GET_CLASS(obj) == &js_WithClass)
|
||||
obj = obj->map->ops->thisObject(cx, obj);
|
||||
return setter(cx, obj, SPROP_USERID(this), vp);
|
||||
return sprop->setter(cx, obj, SPROP_USERID(sprop), vp);
|
||||
}
|
||||
|
||||
/* Macro for common expression to test for shared permanent attributes. */
|
||||
|
@ -2636,9 +2636,8 @@ TraceRecorder::isValidSlot(JSScope* scope, JSScopeProperty* sprop)
|
||||
if (sprop->attrs & JSPROP_READONLY)
|
||||
ABORT_TRACE_RV("writing to a read-only property", false);
|
||||
}
|
||||
|
||||
/* This check applies even when setflags == 0. */
|
||||
if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop))
|
||||
if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop))
|
||||
ABORT_TRACE_RV("non-stub getter", false);
|
||||
|
||||
if (!SPROP_HAS_VALID_SLOT(sprop, scope))
|
||||
@ -4101,7 +4100,7 @@ TraceRecorder::hasMethod(JSObject* obj, jsid id)
|
||||
JSScope* scope = OBJ_SCOPE(pobj);
|
||||
JSScopeProperty* sprop = (JSScopeProperty*) prop;
|
||||
|
||||
if (SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop) &&
|
||||
if (SPROP_HAS_STUB_GETTER(sprop) &&
|
||||
SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
||||
jsval v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
|
||||
if (VALUE_IS_FUNCTION(cx, v)) {
|
||||
@ -10486,16 +10485,15 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
|
||||
if (setflags && (sprop->attrs & JSPROP_READONLY))
|
||||
ABORT_TRACE("writing to a readonly property");
|
||||
if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop)) {
|
||||
if (setflags == 0) {
|
||||
// FIXME 450335: generalize this away from regexp built-in getters.
|
||||
if (sprop->getter == js_RegExpClass.getProperty &&
|
||||
if (setflags == 0 &&
|
||||
sprop->getter == js_RegExpClass.getProperty &&
|
||||
sprop->shortid < 0) {
|
||||
if (sprop->shortid == REGEXP_LAST_INDEX)
|
||||
ABORT_TRACE("can't trace RegExp.lastIndex yet");
|
||||
LIns* args[] = { INS_CONSTPTR(sprop), obj_ins, cx_ins };
|
||||
v_ins = lir->insCall(&js_CallGetter_ci, args);
|
||||
guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT);
|
||||
|
||||
/*
|
||||
* BIG FAT WARNING: This snapshot cannot be a BRANCH_EXIT, since
|
||||
* the value to the top of the stack is not the value we unbox.
|
||||
@ -10505,7 +10503,8 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
|
||||
snapshot(MISMATCH_EXIT));
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
if (sprop->getter == js_StringClass.getProperty &&
|
||||
if (setflags == 0 &&
|
||||
sprop->getter == js_StringClass.getProperty &&
|
||||
sprop->id == ATOM_KEY(cx->runtime->atomState.lengthAtom)) {
|
||||
if (!guardClass(obj, obj_ins, &js_StringClass, snapshot(MISMATCH_EXIT)))
|
||||
ABORT_TRACE("can't trace String.length on non-String objects");
|
||||
@ -10513,7 +10512,6 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
|
||||
v_ins = lir->ins1(LIR_i2f, getStringLength(str_ins));
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
}
|
||||
ABORT_TRACE("non-stub getter");
|
||||
}
|
||||
if (!SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2)))
|
||||
@ -11864,9 +11862,7 @@ TraceRecorder::record_JSOP_CALLPROP()
|
||||
} else if (JSVAL_TAG(l) == JSVAL_BOOLEAN) {
|
||||
if (l == JSVAL_VOID)
|
||||
ABORT_TRACE("callprop on void");
|
||||
guard(false,
|
||||
lir->ins2i(LIR_eq, get(&l), JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)),
|
||||
MISMATCH_EXIT);
|
||||
guard(false, lir->ins2i(LIR_eq, get(&l), JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)), MISMATCH_EXIT);
|
||||
i = JSProto_Boolean;
|
||||
debug_only_stmt(protoname = "Boolean.prototype";)
|
||||
} else {
|
||||
@ -12378,18 +12374,6 @@ DBG_STUB(JSOP_DEFFUN_DBGFC)
|
||||
DBG_STUB(JSOP_DEFLOCALFUN_DBGFC)
|
||||
DBG_STUB(JSOP_LAMBDA_DBGFC)
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::record_JSOP_SETMETHOD()
|
||||
{
|
||||
return record_JSOP_SETPROP();
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::record_JSOP_INITMETHOD()
|
||||
{
|
||||
return record_JSOP_INITPROP();
|
||||
}
|
||||
|
||||
#ifdef JS_JIT_SPEW
|
||||
/* Prints information about entry typemaps and unstable exits for all peers at a PC */
|
||||
void
|
||||
|
@ -456,14 +456,6 @@ typedef JSUintPtr JSUword;
|
||||
# define JS_DATA_TO_FUNC_PTR(type, ptr) ((type) (void *) (ptr))
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define JS_EXTENSION __extension__
|
||||
# define JS_EXTENSION_(s) __extension__ ({ s; })
|
||||
#else
|
||||
# define JS_EXTENSION
|
||||
# define JS_EXTENSION_(s) s
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jstypes_h___ */
|
||||
|
@ -204,7 +204,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
|
||||
* before deserialization of bytecode. If the saved version does not match
|
||||
* the current version, abort deserialization and invalidate the file.
|
||||
*/
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 50)
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 49)
|
||||
|
||||
/*
|
||||
* Library-private functions.
|
||||
|
Loading…
Reference in New Issue
Block a user