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_DEFFUN_DBGFC */
|
||||||
0, /* JSOP_DEFLOCALFUN_DBGFC */
|
0, /* JSOP_DEFLOCALFUN_DBGFC */
|
||||||
0, /* JSOP_LAMBDA_DBGFC */
|
0, /* JSOP_LAMBDA_DBGFC */
|
||||||
0, /* JSOP_SETMETHOD */
|
|
||||||
0, /* JSOP_INITMETHOD */
|
|
||||||
};
|
};
|
||||||
#define JSOP_IS_IMACOP(x) (0 \
|
#define JSOP_IS_IMACOP(x) (0 \
|
||||||
|| x == JSOP_BITOR \
|
|| x == JSOP_BITOR \
|
||||||
|
@ -3544,7 +3544,7 @@ JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
|||||||
jsval *vp)
|
jsval *vp)
|
||||||
{
|
{
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, vp))
|
if (!js_GetMethod(cx, obj, id, false, vp))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
if (objp)
|
if (objp)
|
||||||
*objp = obj;
|
*objp = obj;
|
||||||
|
@ -792,7 +792,7 @@ array_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
|||||||
if (prop) {
|
if (prop) {
|
||||||
if (OBJ_IS_NATIVE(obj2)) {
|
if (OBJ_IS_NATIVE(obj2)) {
|
||||||
sprop = (JSScopeProperty *) prop;
|
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;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||||
|
@ -337,9 +337,9 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, IN
|
|||||||
jsval FASTCALL
|
jsval FASTCALL
|
||||||
js_CallGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
|
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;
|
jsval v;
|
||||||
if (!sprop->get(cx, obj, &v))
|
if (!js_GetSprop(cx, sprop, obj, &v))
|
||||||
return JSVAL_ERROR_COOKIE;
|
return JSVAL_ERROR_COOKIE;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -6529,15 +6529,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||||||
ale = cg->atomList.add(cg->compiler, pn3->pn_atom);
|
ale = cg->atomList.add(cg->compiler, pn3->pn_atom);
|
||||||
if (!ale)
|
if (!ale)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
EMIT_INDEX_OP(JSOP_INITPROP, ALE_INDEX(ale));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
/* -*- 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 *****
|
* ***** BEGIN LICENSE BLOCK *****
|
||||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
@ -184,61 +184,46 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||||||
* is a plain old method? It's a function-valued property with stub
|
* is a plain old method? It's a function-valued property with stub
|
||||||
* getter, so get of a function is idempotent.
|
* 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;
|
jsval v;
|
||||||
|
|
||||||
if (sprop->isMethod()) {
|
v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
|
||||||
|
if (VALUE_IS_FUNCTION(cx, v)) {
|
||||||
/*
|
/*
|
||||||
* A compiler-created function object, AKA a method, already
|
* Great, we have a function-valued prototype property where
|
||||||
* memoized in the property tree.
|
* 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 to a function-valued plain
|
||||||
|
* old property in pobj will result in shape being regenerated.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(scope->hasMethodBarrier());
|
if (!scope->branded()) {
|
||||||
v = sprop->methodValue();
|
PCMETER(cache->brandfills++);
|
||||||
JS_ASSERT(VALUE_IS_FUNCTION(cx, v));
|
#ifdef DEBUG_notme
|
||||||
|
fprintf(stderr,
|
||||||
|
"branding %p (%s) for funobj %p (%s), shape %lu\n",
|
||||||
|
pobj, LOCKED_OBJ_GET_CLASS(pobj)->name,
|
||||||
|
JSVAL_TO_OBJECT(v),
|
||||||
|
JS_GetFunctionName(GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v))),
|
||||||
|
OBJ_SHAPE(obj));
|
||||||
|
#endif
|
||||||
|
scope->brandingShapeChange(cx, sprop->slot, v);
|
||||||
|
if (js_IsPropertyCacheDisabled(cx)) /* check for rt->shapeGen overflow */
|
||||||
|
return JS_NO_PROP_CACHE_FILL;
|
||||||
|
scope->setBranded();
|
||||||
|
}
|
||||||
vword = JSVAL_OBJECT_TO_PCVAL(v);
|
vword = JSVAL_OBJECT_TO_PCVAL(v);
|
||||||
break;
|
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.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
if (!scope->branded()) {
|
|
||||||
PCMETER(cache->brandfills++);
|
|
||||||
#ifdef DEBUG_notme
|
|
||||||
fprintf(stderr,
|
|
||||||
"branding %p (%s) for funobj %p (%s), shape %lu\n",
|
|
||||||
pobj, LOCKED_OBJ_GET_CLASS(pobj)->name,
|
|
||||||
JSVAL_TO_OBJECT(v),
|
|
||||||
JS_GetFunctionName(GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v))),
|
|
||||||
OBJ_SHAPE(obj));
|
|
||||||
#endif
|
|
||||||
scope->brandingShapeChange(cx, sprop->slot, v);
|
|
||||||
if (js_IsPropertyCacheDisabled(cx)) /* check for rt->shapeGen overflow */
|
|
||||||
return JS_NO_PROP_CACHE_FILL;
|
|
||||||
scope->setBranded();
|
|
||||||
}
|
|
||||||
vword = JSVAL_OBJECT_TO_PCVAL(v);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If getting a value via a stub getter, we can cache the slot. */
|
/* If getting a value via a stub getter, we can cache the slot. */
|
||||||
if (!(cs->format & (JOF_SET | JOF_INCDEC | JOF_FOR)) &&
|
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)) {
|
SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
||||||
/* Great, let's cache sprop's slot and use it on cache hit. */
|
/* Great, let's cache sprop's slot and use it on cache hit. */
|
||||||
vword = SLOT_TO_PCVAL(sprop->slot);
|
vword = SLOT_TO_PCVAL(sprop->slot);
|
||||||
@ -250,30 +235,30 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj,
|
|||||||
scope->shape == sprop->shape) {
|
scope->shape == sprop->shape) {
|
||||||
/*
|
/*
|
||||||
* Our caller added a new property. We also know that a setter
|
* Our caller added a new property. We also know that a setter
|
||||||
* that js_NativeSet could have run has not mutated the scope,
|
* that js_NativeSet could have run has not mutated the scope
|
||||||
* so the added property is still the last one added, and the
|
* so the added property is still the last one added and the
|
||||||
* scope is not branded.
|
* scope is not branded.
|
||||||
*
|
*
|
||||||
* We want to cache under scope's shape before the property
|
* We want to cache under scope's shape before the property
|
||||||
* addition to bias for the case when the mutator opcode
|
* addition to bias for the case when the mutator opcode
|
||||||
* always adds the same property. This allows us to optimize
|
* always adds the same property. It allows to optimize
|
||||||
* periodic execution of object initializers or other explicit
|
* periodic execution of object initializers or explicit
|
||||||
* initialization sequences such as
|
* initialization sequences like
|
||||||
*
|
*
|
||||||
* obj = {}; obj.x = 1; obj.y = 2;
|
* obj = {}; obj.x = 1; obj.y = 2;
|
||||||
*
|
*
|
||||||
* We assume that on average the win from this optimization is
|
* 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:
|
* the bias for the following case:
|
||||||
*
|
*
|
||||||
* obj = {}; ... for (...) { ... obj.x = ... }
|
* obj = {}; ... for (...) { ... obj.x = ... }
|
||||||
*
|
*
|
||||||
* On the first iteration of such a for loop, JSOP_SETPROP
|
* On the first iteration JSOP_SETPROP fills the cache with
|
||||||
* fills the cache with the shape of the newly created object
|
* the shape of newly created object, not the shape after
|
||||||
* obj, not the shape of obj after obj.x has been assigned.
|
* obj.x is assigned. That mismatches obj's shape on the
|
||||||
* That mismatches obj's shape on the second iteration. Note
|
* second iteration. Note that on third and the following
|
||||||
* that on the third and subsequent iterations the cache will
|
* iterations the cache will be hit since the shape no longer
|
||||||
* be hit because the shape is no longer updated.
|
* mutates.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(scope->owned());
|
JS_ASSERT(scope->owned());
|
||||||
if (sprop->parent) {
|
if (sprop->parent) {
|
||||||
@ -1004,7 +989,7 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp)
|
|||||||
|
|
||||||
MUST_FLOW_THROUGH("out");
|
MUST_FLOW_THROUGH("out");
|
||||||
id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
|
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)
|
if (!ok)
|
||||||
goto out;
|
goto out;
|
||||||
if (JSVAL_IS_PRIMITIVE(tvr.u.value)) {
|
if (JSVAL_IS_PRIMITIVE(tvr.u.value)) {
|
||||||
@ -2147,9 +2132,9 @@ js_TraceOpcode(JSContext *cx)
|
|||||||
fp->script, cx->tracePrevPc);
|
fp->script, cx->tracePrevPc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there aren't that many elements on the stack, then we have
|
* If there aren't that many elements on the stack, then
|
||||||
* probably entered a new frame, and printing output would just be
|
* we have probably entered a new frame, and printing output
|
||||||
* misleading.
|
* would just be misleading.
|
||||||
*/
|
*/
|
||||||
if (ndefs != 0 &&
|
if (ndefs != 0 &&
|
||||||
ndefs < regs->sp - fp->slots) {
|
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(PCVAL_IS_OBJECT(entry->vword));
|
||||||
JS_ASSERT(entry->vword != PCVAL_NULL);
|
JS_ASSERT(entry->vword != PCVAL_NULL);
|
||||||
JS_ASSERT(OBJ_SCOPE(pobj)->branded());
|
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)));
|
JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(pobj)));
|
||||||
v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
|
v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
|
||||||
JS_ASSERT(VALUE_IS_FUNCTION(cx, v));
|
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
|
* 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_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. */
|
/* See TRY_BRANCH_AFTER_COND. */
|
||||||
JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
|
JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
|
||||||
@ -2717,6 +2700,14 @@ js_Interpret(JSContext *cx)
|
|||||||
#endif
|
#endif
|
||||||
JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
|
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
|
# ifdef DEBUG
|
||||||
/*
|
/*
|
||||||
* We call this macro from BEGIN_CASE in threaded interpreters,
|
* We call this macro from BEGIN_CASE in threaded interpreters,
|
||||||
@ -3619,7 +3610,7 @@ js_Interpret(JSContext *cx)
|
|||||||
goto error; \
|
goto error; \
|
||||||
JS_END_MACRO
|
JS_END_MACRO
|
||||||
|
|
||||||
#define NATIVE_GET(cx,obj,pobj,sprop,getHow,vp) \
|
#define NATIVE_GET(cx,obj,pobj,sprop,vp) \
|
||||||
JS_BEGIN_MACRO \
|
JS_BEGIN_MACRO \
|
||||||
if (SPROP_HAS_STUB_GETTER(sprop)) { \
|
if (SPROP_HAS_STUB_GETTER(sprop)) { \
|
||||||
/* Fast path for Object instance properties. */ \
|
/* Fast path for Object instance properties. */ \
|
||||||
@ -3629,7 +3620,7 @@ js_Interpret(JSContext *cx)
|
|||||||
? LOCKED_OBJ_GET_SLOT(pobj, (sprop)->slot) \
|
? LOCKED_OBJ_GET_SLOT(pobj, (sprop)->slot) \
|
||||||
: JSVAL_VOID; \
|
: JSVAL_VOID; \
|
||||||
} else { \
|
} else { \
|
||||||
if (!js_NativeGet(cx, obj, pobj, sprop, getHow, vp)) \
|
if (!js_NativeGet(cx, obj, pobj, sprop, vp)) \
|
||||||
goto error; \
|
goto error; \
|
||||||
} \
|
} \
|
||||||
JS_END_MACRO
|
JS_END_MACRO
|
||||||
@ -4490,7 +4481,7 @@ js_Interpret(JSContext *cx)
|
|||||||
} else {
|
} else {
|
||||||
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
||||||
sprop = PCVAL_TO_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);
|
JS_UNLOCK_OBJ(cx, obj2);
|
||||||
break;
|
break;
|
||||||
@ -4504,9 +4495,7 @@ js_Interpret(JSContext *cx)
|
|||||||
}
|
}
|
||||||
id = ATOM_TO_JSID(atom);
|
id = ATOM_TO_JSID(atom);
|
||||||
if (entry
|
if (entry
|
||||||
? !js_GetPropertyHelper(cx, obj, id,
|
? !js_GetPropertyHelper(cx, obj, id, true, &rval)
|
||||||
JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
|
|
||||||
&rval)
|
|
||||||
: !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
|
: !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -4583,7 +4572,7 @@ js_Interpret(JSContext *cx)
|
|||||||
} else {
|
} else {
|
||||||
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
||||||
sprop = PCVAL_TO_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);
|
JS_UNLOCK_OBJ(cx, obj2);
|
||||||
STORE_OPND(-1, rval);
|
STORE_OPND(-1, rval);
|
||||||
@ -4602,13 +4591,13 @@ js_Interpret(JSContext *cx)
|
|||||||
id = ATOM_TO_JSID(atom);
|
id = ATOM_TO_JSID(atom);
|
||||||
PUSH(JSVAL_NULL);
|
PUSH(JSVAL_NULL);
|
||||||
if (!JSVAL_IS_PRIMITIVE(lval)) {
|
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;
|
goto error;
|
||||||
STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
|
STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
|
||||||
STORE_OPND(-2, rval);
|
STORE_OPND(-2, rval);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(obj->map->ops->getProperty == js_GetProperty);
|
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;
|
goto error;
|
||||||
STORE_OPND(-1, lval);
|
STORE_OPND(-1, lval);
|
||||||
STORE_OPND(-2, rval);
|
STORE_OPND(-2, rval);
|
||||||
@ -4639,12 +4628,9 @@ js_Interpret(JSContext *cx)
|
|||||||
|
|
||||||
BEGIN_CASE(JSOP_SETNAME)
|
BEGIN_CASE(JSOP_SETNAME)
|
||||||
BEGIN_CASE(JSOP_SETPROP)
|
BEGIN_CASE(JSOP_SETPROP)
|
||||||
BEGIN_CASE(JSOP_SETMETHOD)
|
|
||||||
do_setprop:
|
|
||||||
rval = FETCH_OPND(-1);
|
rval = FETCH_OPND(-1);
|
||||||
JS_ASSERT_IF(op == JSOP_SETMETHOD, VALUE_IS_FUNCTION(cx, rval));
|
|
||||||
lval = FETCH_OPND(-2);
|
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);
|
VALUE_TO_OBJECT(cx, -2, lval, obj);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -4798,21 +4784,9 @@ js_Interpret(JSContext *cx)
|
|||||||
sprop = sprop2;
|
sprop = sprop2;
|
||||||
} else {
|
} else {
|
||||||
scope->extend(cx, sprop);
|
scope->extend(cx, sprop);
|
||||||
|
|
||||||
jsuint index;
|
|
||||||
if (js_IdIsIndex(sprop->id, &index))
|
|
||||||
scope->setIndexedProperties();
|
|
||||||
|
|
||||||
if (sprop->isMethod())
|
|
||||||
scope->setMethodBarrier();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, rval);
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
TRACE_2(SetPropHit, entry, sprop);
|
TRACE_2(SetPropHit, entry, sprop);
|
||||||
LOCKED_OBJ_SET_SLOT(obj, slot, rval);
|
LOCKED_OBJ_SET_SLOT(obj, slot, rval);
|
||||||
JS_UNLOCK_SCOPE(cx, scope);
|
JS_UNLOCK_SCOPE(cx, scope);
|
||||||
@ -4856,10 +4830,7 @@ js_Interpret(JSContext *cx)
|
|||||||
LOAD_ATOM(0);
|
LOAD_ATOM(0);
|
||||||
id = ATOM_TO_JSID(atom);
|
id = ATOM_TO_JSID(atom);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
uintN defineHow = (op == JSOP_SETMETHOD)
|
if (!js_SetPropertyHelper(cx, obj, id, true, &rval))
|
||||||
? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD
|
|
||||||
: JSDNP_CACHE_RESULT;
|
|
||||||
if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval))
|
|
||||||
goto error;
|
goto error;
|
||||||
} else {
|
} else {
|
||||||
if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
|
if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
|
||||||
@ -4916,7 +4887,7 @@ js_Interpret(JSContext *cx)
|
|||||||
END_CASE(JSOP_GETELEM)
|
END_CASE(JSOP_GETELEM)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_CALLELEM)
|
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_HAS_NO_SUCH_METHOD
|
||||||
if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) {
|
if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) {
|
||||||
regs.sp[-2] = regs.sp[-1];
|
regs.sp[-2] = regs.sp[-1];
|
||||||
@ -5370,7 +5341,7 @@ js_Interpret(JSContext *cx)
|
|||||||
} else {
|
} else {
|
||||||
sprop = (JSScopeProperty *)prop;
|
sprop = (JSScopeProperty *)prop;
|
||||||
do_native_get:
|
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);
|
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *) sprop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5951,7 +5922,7 @@ js_Interpret(JSContext *cx)
|
|||||||
sprop = (JSScopeProperty *) prop;
|
sprop = (JSScopeProperty *) prop;
|
||||||
if ((sprop->attrs & JSPROP_PERMANENT) &&
|
if ((sprop->attrs & JSPROP_PERMANENT) &&
|
||||||
SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)) &&
|
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)) {
|
SPROP_HAS_STUB_SETTER(sprop)) {
|
||||||
/*
|
/*
|
||||||
* Fast globals use frame variables to map the global
|
* Fast globals use frame variables to map the global
|
||||||
@ -6245,64 +6216,23 @@ js_Interpret(JSContext *cx)
|
|||||||
obj = FUN_OBJECT(fun);
|
obj = FUN_OBJECT(fun);
|
||||||
|
|
||||||
if (FUN_NULL_CLOSURE(fun)) {
|
if (FUN_NULL_CLOSURE(fun)) {
|
||||||
parent = fp->scopeChain;
|
obj = js_CloneFunctionObject(cx, fun, fp->scopeChain);
|
||||||
|
if (!obj)
|
||||||
if (OBJ_GET_PARENT(cx, obj) == parent) {
|
goto error;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
parent = js_GetScopeChain(cx, fp);
|
parent = js_GetScopeChain(cx, fp);
|
||||||
if (!parent)
|
if (!parent)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
|
|
||||||
obj = js_CloneFunctionObject(cx, fun, parent);
|
/*
|
||||||
if (!obj)
|
* FIXME: bug 471214, Cloning here even when the compiler saw
|
||||||
goto error;
|
* 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));
|
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||||
END_CASE(JSOP_LAMBDA)
|
END_CASE(JSOP_LAMBDA)
|
||||||
@ -6449,26 +6379,11 @@ js_Interpret(JSContext *cx)
|
|||||||
BEGIN_CASE(JSOP_NEWINIT)
|
BEGIN_CASE(JSOP_NEWINIT)
|
||||||
i = GET_INT8(regs.pc);
|
i = GET_INT8(regs.pc);
|
||||||
JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
|
JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
|
||||||
if (i == JSProto_Array) {
|
obj = (i == JSProto_Array)
|
||||||
obj = js_NewArrayObject(cx, 0, NULL);
|
? js_NewArrayObject(cx, 0, NULL)
|
||||||
if (!obj)
|
: js_NewObject(cx, &js_ObjectClass, NULL, NULL);
|
||||||
goto error;
|
if (!obj)
|
||||||
} else {
|
goto error;
|
||||||
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));
|
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||||
fp->sharpDepth++;
|
fp->sharpDepth++;
|
||||||
CHECK_INTERRUPT_HANDLER();
|
CHECK_INTERRUPT_HANDLER();
|
||||||
@ -6486,8 +6401,6 @@ js_Interpret(JSContext *cx)
|
|||||||
END_CASE(JSOP_ENDINIT)
|
END_CASE(JSOP_ENDINIT)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_INITPROP)
|
BEGIN_CASE(JSOP_INITPROP)
|
||||||
BEGIN_CASE(JSOP_INITMETHOD)
|
|
||||||
do_initprop:
|
|
||||||
/* Load the property's initial value into rval. */
|
/* Load the property's initial value into rval. */
|
||||||
JS_ASSERT(regs.sp - StackBase(fp) >= 2);
|
JS_ASSERT(regs.sp - StackBase(fp) >= 2);
|
||||||
rval = FETCH_OPND(-1);
|
rval = FETCH_OPND(-1);
|
||||||
@ -6508,7 +6421,6 @@ js_Interpret(JSContext *cx)
|
|||||||
|
|
||||||
JS_LOCK_OBJ(cx, obj);
|
JS_LOCK_OBJ(cx, obj);
|
||||||
scope = OBJ_SCOPE(obj);
|
scope = OBJ_SCOPE(obj);
|
||||||
JS_ASSERT(scope->object == obj);
|
|
||||||
JS_ASSERT(!scope->sealed());
|
JS_ASSERT(!scope->sealed());
|
||||||
kshape = scope->shape;
|
kshape = scope->shape;
|
||||||
cache = &JS_PROPERTY_CACHE(cx);
|
cache = &JS_PROPERTY_CACHE(cx);
|
||||||
@ -6538,6 +6450,14 @@ js_Interpret(JSContext *cx)
|
|||||||
if (!SPROP_HAS_STUB_SETTER(sprop))
|
if (!SPROP_HAS_STUB_SETTER(sprop))
|
||||||
goto do_initprop_miss;
|
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
|
* Detect a repeated property name and force a miss to
|
||||||
* share the strict warning code and cope with complexity
|
* share the strict warning code and cope with complexity
|
||||||
@ -6588,11 +6508,7 @@ js_Interpret(JSContext *cx)
|
|||||||
scope->lastProp = sprop;
|
scope->lastProp = sprop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, rval);
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
TRACE_2(SetPropHit, entry, sprop);
|
TRACE_2(SetPropHit, entry, sprop);
|
||||||
LOCKED_OBJ_SET_SLOT(obj, slot, rval);
|
LOCKED_OBJ_SET_SLOT(obj, slot, rval);
|
||||||
JS_UNLOCK_SCOPE(cx, scope);
|
JS_UNLOCK_SCOPE(cx, scope);
|
||||||
@ -6613,16 +6529,12 @@ js_Interpret(JSContext *cx)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintN defineHow = (op == JSOP_INITMETHOD)
|
|
||||||
? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD
|
|
||||||
: JSDNP_CACHE_RESULT;
|
|
||||||
if (!(JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
|
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,
|
: js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
|
||||||
JSPROP_ENUMERATE, 0, 0, NULL,
|
JSPROP_ENUMERATE, 0, 0, NULL,
|
||||||
defineHow))) {
|
JSDNP_CACHE_RESULT)))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
/* Common tail for property cache hit and miss cases. */
|
/* 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);
|
*vp = OBJECT_TO_JSVAL(iterobj);
|
||||||
} else {
|
} else {
|
||||||
atom = cx->runtime->atomState.iteratorAtom;
|
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;
|
goto bad;
|
||||||
if (JSVAL_IS_VOID(*vp)) {
|
if (JSVAL_IS_VOID(*vp)) {
|
||||||
default_iter:
|
default_iter:
|
||||||
|
121
js/src/jsobj.cpp
121
js/src/jsobj.cpp
@ -418,7 +418,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
|||||||
JSScopeProperty *sprop = (JSScopeProperty *) prop;
|
JSScopeProperty *sprop = (JSScopeProperty *) prop;
|
||||||
val = JSVAL_NULL;
|
val = JSVAL_NULL;
|
||||||
if (attrs & JSPROP_GETTER)
|
if (attrs & JSPROP_GETTER)
|
||||||
val = sprop->getterValue();
|
val = js_CastAsObjectJSVal(sprop->getter);
|
||||||
if (attrs & JSPROP_SETTER) {
|
if (attrs & JSPROP_SETTER) {
|
||||||
if (val != JSVAL_NULL) {
|
if (val != JSVAL_NULL) {
|
||||||
/* Mark the getter, then set val to setter. */
|
/* Mark the getter, then set val to setter. */
|
||||||
@ -426,7 +426,7 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
|||||||
NULL)
|
NULL)
|
||||||
!= NULL);
|
!= NULL);
|
||||||
}
|
}
|
||||||
val = sprop->setterValue();
|
val = js_CastAsObjectJSVal(sprop->setter);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ok = OBJ_GET_PROPERTY(cx, obj, id, &val);
|
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))) {
|
(attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
|
||||||
JSScopeProperty *sprop = (JSScopeProperty *) prop;
|
JSScopeProperty *sprop = (JSScopeProperty *) prop;
|
||||||
if (attrs & JSPROP_GETTER) {
|
if (attrs & JSPROP_GETTER) {
|
||||||
val[valcnt] = sprop->getterValue();
|
val[valcnt] = js_CastAsObjectJSVal(sprop->getter);
|
||||||
gsopold[valcnt] =
|
gsopold[valcnt] =
|
||||||
ATOM_TO_STRING(cx->runtime->atomState.getterAtom);
|
ATOM_TO_STRING(cx->runtime->atomState.getterAtom);
|
||||||
gsop[valcnt] =
|
gsop[valcnt] =
|
||||||
@ -791,7 +791,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
valcnt++;
|
valcnt++;
|
||||||
}
|
}
|
||||||
if (attrs & JSPROP_SETTER) {
|
if (attrs & JSPROP_SETTER) {
|
||||||
val[valcnt] = sprop->setterValue();
|
val[valcnt] = js_CastAsObjectJSVal(sprop->setter);
|
||||||
gsopold[valcnt] =
|
gsopold[valcnt] =
|
||||||
ATOM_TO_STRING(cx->runtime->atomState.setterAtom);
|
ATOM_TO_STRING(cx->runtime->atomState.setterAtom);
|
||||||
gsop[valcnt] =
|
gsop[valcnt] =
|
||||||
@ -1905,7 +1905,7 @@ obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
if (OBJ_IS_NATIVE(pobj)) {
|
if (OBJ_IS_NATIVE(pobj)) {
|
||||||
sprop = (JSScopeProperty *) prop;
|
sprop = (JSScopeProperty *) prop;
|
||||||
if (sprop->attrs & JSPROP_GETTER)
|
if (sprop->attrs & JSPROP_GETTER)
|
||||||
*vp = sprop->getterValue();
|
*vp = js_CastAsObjectJSVal(sprop->getter);
|
||||||
}
|
}
|
||||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||||
}
|
}
|
||||||
@ -1930,7 +1930,7 @@ obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
if (OBJ_IS_NATIVE(pobj)) {
|
if (OBJ_IS_NATIVE(pobj)) {
|
||||||
sprop = (JSScopeProperty *) prop;
|
sprop = (JSScopeProperty *) prop;
|
||||||
if (sprop->attrs & JSPROP_SETTER)
|
if (sprop->attrs & JSPROP_SETTER)
|
||||||
*vp = sprop->setterValue();
|
*vp = js_CastAsObjectJSVal(sprop->setter);
|
||||||
}
|
}
|
||||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||||
}
|
}
|
||||||
@ -3557,8 +3557,6 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
|
|||||||
JSScope *scope;
|
JSScope *scope;
|
||||||
JSScopeProperty *sprop;
|
JSScopeProperty *sprop;
|
||||||
|
|
||||||
JS_ASSERT(!(flags & SPROP_IS_METHOD));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Purge the property cache of now-shadowed id in obj's scope chain. Do
|
* Purge the property cache of now-shadowed id in obj's scope chain. Do
|
||||||
* this optimistically (assuming no failure below) before locking obj, so
|
* 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;
|
JSScopeProperty *sprop;
|
||||||
JSBool added;
|
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);
|
js_LeaveTraceIfGlobalObject(cx, obj);
|
||||||
|
|
||||||
/* Convert string indices to integers if appropriate. */
|
/* 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. */
|
/* Use the object's class getter and setter by default. */
|
||||||
clasp = LOCKED_OBJ_GET_CLASS(obj);
|
clasp = LOCKED_OBJ_GET_CLASS(obj);
|
||||||
if (!(defineHow & JSDNP_SET_METHOD)) {
|
if (!getter)
|
||||||
if (!getter)
|
getter = clasp->getProperty;
|
||||||
getter = clasp->getProperty;
|
if (!setter)
|
||||||
if (!setter)
|
setter = clasp->setProperty;
|
||||||
setter = clasp->setProperty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get obj's own scope if it has one, or create a new one for obj. */
|
/* Get obj's own scope if it has one, or create a new one for obj. */
|
||||||
scope = js_GetMutableScope(cx, 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. */
|
/* Add a new property, or replace an existing one of the same id. */
|
||||||
if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)
|
if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)
|
||||||
attrs |= JSPROP_SHARED;
|
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,
|
sprop = scope->add(cx, id, getter, setter, SPROP_INVALID_SLOT, attrs,
|
||||||
flags, shortid);
|
flags, shortid);
|
||||||
if (!sprop)
|
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. */
|
/* Store value before calling addProperty, in case the latter GC's. */
|
||||||
if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
if (SPROP_HAS_VALID_SLOT(sprop, scope))
|
||||||
if (added)
|
LOCKED_OBJ_WRITE_SLOT(cx, obj, sprop->slot, value);
|
||||||
LOCKED_OBJ_SET_SLOT(obj, sprop->slot, value);
|
|
||||||
else
|
|
||||||
LOCKED_OBJ_WRITE_BARRIER(cx, obj, sprop->slot, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXXbe called with lock held */
|
/* XXXbe called with lock held */
|
||||||
ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, &value,
|
ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, &value,
|
||||||
@ -4156,7 +4138,7 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
|
|||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
|
js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
|
||||||
JSScopeProperty *sprop, uintN getHow, jsval *vp)
|
JSScopeProperty *sprop, jsval *vp)
|
||||||
{
|
{
|
||||||
js_LeaveTraceIfGlobalObject(cx, pobj);
|
js_LeaveTraceIfGlobalObject(cx, pobj);
|
||||||
|
|
||||||
@ -4175,20 +4157,17 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
|
|||||||
? LOCKED_OBJ_GET_SLOT(pobj, slot)
|
? LOCKED_OBJ_GET_SLOT(pobj, slot)
|
||||||
: JSVAL_VOID;
|
: JSVAL_VOID;
|
||||||
if (SPROP_HAS_STUB_GETTER(sprop))
|
if (SPROP_HAS_STUB_GETTER(sprop))
|
||||||
return true;
|
return JS_TRUE;
|
||||||
|
|
||||||
if (JS_UNLIKELY(sprop->isMethod()) && !(getHow & JSGET_METHOD_BARRIER))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
sample = cx->runtime->propertyRemovals;
|
sample = cx->runtime->propertyRemovals;
|
||||||
JS_UNLOCK_SCOPE(cx, scope);
|
JS_UNLOCK_SCOPE(cx, scope);
|
||||||
JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);
|
JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);
|
||||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, pobj, &tvr2);
|
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, &tvr2);
|
||||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
return false;
|
return JS_FALSE;
|
||||||
|
|
||||||
JS_LOCK_SCOPE(cx, scope);
|
JS_LOCK_SCOPE(cx, scope);
|
||||||
if (SLOT_IN_SCOPE(slot, 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);
|
LOCKED_OBJ_SET_SLOT(pobj, slot, *vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
@ -4241,7 +4220,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp)
|
|||||||
sample = cx->runtime->propertyRemovals;
|
sample = cx->runtime->propertyRemovals;
|
||||||
JS_UNLOCK_SCOPE(cx, scope);
|
JS_UNLOCK_SCOPE(cx, scope);
|
||||||
JS_PUSH_TEMP_ROOT_SPROP(cx, sprop, &tvr);
|
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);
|
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
@ -4258,7 +4237,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
|
||||||
jsval *vp)
|
jsval *vp)
|
||||||
{
|
{
|
||||||
JSObject *aobj, *obj2;
|
JSObject *aobj, *obj2;
|
||||||
@ -4266,8 +4245,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
|||||||
JSProperty *prop;
|
JSProperty *prop;
|
||||||
JSScopeProperty *sprop;
|
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. */
|
/* Convert string indices to integers if appropriate. */
|
||||||
id = js_CheckForStringIndex(id);
|
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))
|
if (!OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, ID_TO_VALUE(id), vp))
|
||||||
return JS_FALSE;
|
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
|
* 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;
|
sprop = (JSScopeProperty *) prop;
|
||||||
|
|
||||||
if (getHow & JSGET_CACHE_RESULT) {
|
if (cacheResult) {
|
||||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||||
js_FillPropertyCache(cx, aobj, 0, protoIndex, obj2, sprop, false);
|
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;
|
return JS_FALSE;
|
||||||
|
|
||||||
JS_UNLOCK_OBJ(cx, obj2);
|
JS_UNLOCK_OBJ(cx, obj2);
|
||||||
@ -4358,19 +4336,20 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
|||||||
JSBool
|
JSBool
|
||||||
js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
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
|
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);
|
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
|
||||||
|
|
||||||
if (obj->map->ops == &js_ObjectOps ||
|
if (obj->map->ops == &js_ObjectOps ||
|
||||||
obj->map->ops->getProperty == js_GetProperty) {
|
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 JS_HAS_XML_SUPPORT
|
||||||
if (OBJECT_IS_XML(cx, obj))
|
if (OBJECT_IS_XML(cx, obj))
|
||||||
return js_GetXMLMethod(cx, obj, id, vp);
|
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
|
* Note: all non-error exits in this function must notify the tracer using
|
||||||
* SetPropHit when called from the interpreter, which is detected by testing
|
* SetPropHit when called from the interpreter loop (cacheResult is true).
|
||||||
* (defineHow & JSDNP_CACHE_RESULT).
|
|
||||||
*/
|
*/
|
||||||
JSBool
|
JSBool
|
||||||
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
|
||||||
jsval *vp)
|
jsval *vp)
|
||||||
{
|
{
|
||||||
int protoIndex;
|
int protoIndex;
|
||||||
@ -4419,8 +4397,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||||||
JSPropertyOp getter, setter;
|
JSPropertyOp getter, setter;
|
||||||
bool added;
|
bool added;
|
||||||
|
|
||||||
JS_ASSERT((defineHow & ~(JSDNP_CACHE_RESULT | JSDNP_SET_METHOD)) == 0);
|
if (cacheResult)
|
||||||
if (defineHow & JSDNP_CACHE_RESULT)
|
|
||||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||||
|
|
||||||
/* Convert string indices to integers if appropriate. */
|
/* 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 (attrs & JSPROP_READONLY) {
|
||||||
if (!JS_HAS_STRICT_OPTION(cx)) {
|
if (!JS_HAS_STRICT_OPTION(cx)) {
|
||||||
/* Just return true per ECMA if not in strict mode. */
|
/* Just return true per ECMA if not in strict mode. */
|
||||||
PCMETER((defineHow & JSDNP_CACHE_RESULT) && JS_PROPERTY_CACHE(cx).rofills++);
|
PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).rofills++);
|
||||||
if (defineHow & JSDNP_CACHE_RESULT)
|
if (cacheResult)
|
||||||
TRACE_2(SetPropHit, JS_NO_PROP_CACHE_FILL, sprop);
|
TRACE_2(SetPropHit, JS_NO_PROP_CACHE_FILL, sprop);
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
error: // TRACE_2 jumps here in case of error.
|
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;
|
goto read_only_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pobj == obj) {
|
if (pobj != obj) {
|
||||||
if (!(defineHow & JSDNP_SET_METHOD) != !sprop->isMethod())
|
|
||||||
sprop = NULL;
|
|
||||||
} else {
|
|
||||||
/*
|
/*
|
||||||
* We found id in a prototype object: prepare to share or shadow.
|
* 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. */
|
/* Don't clone a shared prototype property. */
|
||||||
if (attrs & JSPROP_SHARED) {
|
if (attrs & JSPROP_SHARED) {
|
||||||
if (defineHow & JSDNP_CACHE_RESULT) {
|
if (cacheResult) {
|
||||||
JSPropCacheEntry *entry;
|
JSPropCacheEntry *entry;
|
||||||
entry = js_FillPropertyCache(cx, obj, 0, protoIndex, pobj, sprop, false);
|
entry = js_FillPropertyCache(cx, obj, 0, protoIndex, pobj, sprop, false);
|
||||||
TRACE_2(SetPropHit, entry, sprop);
|
TRACE_2(SetPropHit, entry, sprop);
|
||||||
@ -4533,7 +4507,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||||||
return JS_TRUE;
|
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. */
|
/* 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);
|
JS_UNLOCK_OBJ(cx, obj);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)
|
if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)
|
||||||
attrs |= JSPROP_SHARED;
|
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,
|
sprop = scope->add(cx, id, getter, setter, SPROP_INVALID_SLOT, attrs,
|
||||||
flags, shortid);
|
flags, shortid);
|
||||||
if (!sprop) {
|
if (!sprop) {
|
||||||
@ -4620,7 +4579,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
|||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defineHow & JSDNP_CACHE_RESULT) {
|
if (cacheResult) {
|
||||||
JSPropCacheEntry *entry;
|
JSPropCacheEntry *entry;
|
||||||
entry = js_FillPropertyCache(cx, obj, 0, 0, obj, sprop, added);
|
entry = js_FillPropertyCache(cx, obj, 0, 0, obj, sprop, added);
|
||||||
TRACE_2(SetPropHit, entry, sprop);
|
TRACE_2(SetPropHit, entry, sprop);
|
||||||
@ -4799,7 +4758,7 @@ js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sprop &&
|
if (sprop &&
|
||||||
SPROP_HAS_STUB_GETTER_OR_IS_METHOD(sprop) &&
|
SPROP_HAS_STUB_GETTER(sprop) &&
|
||||||
SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
||||||
jsval fval = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
|
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);
|
older = JS_SetErrorReporter(cx, NULL);
|
||||||
id = ATOM_TO_JSID(atom);
|
id = ATOM_TO_JSID(atom);
|
||||||
fval = JSVAL_VOID;
|
fval = JSVAL_VOID;
|
||||||
ok = js_GetMethod(cx, obj, id, 0, &fval);
|
ok = js_GetMethod(cx, obj, id, false, &fval);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
JS_ClearPendingException(cx);
|
JS_ClearPendingException(cx);
|
||||||
JS_SetErrorReporter(cx, older);
|
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_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */
|
||||||
const uintN JSDNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */
|
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
|
extern JSBool
|
||||||
js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||||
@ -715,17 +712,6 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id);
|
|||||||
extern JSObject *
|
extern JSObject *
|
||||||
js_FindVariableScope(JSContext *cx, JSFunction **funp);
|
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
|
* 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
|
* (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
|
extern JSBool
|
||||||
js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
|
js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj,
|
||||||
JSScopeProperty *sprop, uintN getHow, jsval *vp);
|
JSScopeProperty *sprop, jsval *vp);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp);
|
js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
|
||||||
jsval *vp);
|
jsval *vp);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
|
js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
|
||||||
|
|
||||||
extern JSBool
|
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
|
* 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);
|
js_CheckUndeclaredVarAssignment(JSContext *cx);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
|
||||||
jsval *vp);
|
jsval *vp);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
|
@ -3823,7 +3823,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
goto do_getprop;
|
goto do_getprop;
|
||||||
|
|
||||||
case JSOP_SETPROP:
|
case JSOP_SETPROP:
|
||||||
case JSOP_SETMETHOD:
|
|
||||||
LOAD_ATOM(0);
|
LOAD_ATOM(0);
|
||||||
GET_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval);
|
GET_QUOTE_AND_FMT("%s[%s] %s= %s", "%s.%s %s= %s", xval);
|
||||||
rval = POP_STR();
|
rval = POP_STR();
|
||||||
@ -4485,7 +4484,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case JSOP_INITPROP:
|
case JSOP_INITPROP:
|
||||||
case JSOP_INITMETHOD:
|
|
||||||
LOAD_ATOM(0);
|
LOAD_ATOM(0);
|
||||||
xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),
|
xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),
|
||||||
(jschar)
|
(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)
|
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_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_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_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_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)
|
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_type = TOK_SEMI;
|
||||||
pn->pn_pos = pn2->pn_pos;
|
pn->pn_pos = pn2->pn_pos;
|
||||||
pn->pn_kid = pn2;
|
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;
|
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. */
|
/* Accumulate from least to most random so the low bits are most random. */
|
||||||
hash = 0;
|
hash = 0;
|
||||||
JS_ASSERT_IF(sprop->isMethod(), !sprop->setter);
|
|
||||||
gsop = sprop->getter;
|
gsop = sprop->getter;
|
||||||
if (gsop)
|
if (gsop)
|
||||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsword(gsop);
|
hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsword)gsop;
|
||||||
gsop = sprop->setter;
|
gsop = sprop->setter;
|
||||||
if (gsop)
|
if (gsop)
|
||||||
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsword(gsop);
|
hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsword)gsop;
|
||||||
|
|
||||||
hash = JS_ROTATE_LEFT32(hash, 4)
|
hash = JS_ROTATE_LEFT32(hash, 4)
|
||||||
^ (sprop->flags & ~SPROP_FLAGS_NOT_MATCHED);
|
^ (sprop->flags & ~SPROP_FLAGS_NOT_MATCHED);
|
||||||
@ -1055,9 +1054,6 @@ JSScope::add(JSContext *cx, jsid id,
|
|||||||
JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, this));
|
JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, this));
|
||||||
CHECK_ANCESTOR_LINE(this, true);
|
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
|
* 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
|
* 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
|
* Normalize stub getter and setter values for faster is-stub testing in
|
||||||
* the SPROP_CALL_[GS]ETTER macros.
|
* the SPROP_CALL_[GS]ETTER macros.
|
||||||
*/
|
*/
|
||||||
|
if (getter == JS_PropertyStub)
|
||||||
|
getter = NULL;
|
||||||
if (setter == JS_PropertyStub)
|
if (setter == JS_PropertyStub)
|
||||||
setter = NULL;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search for id in order to claim its entry, allocating a property tree
|
* 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))
|
if (js_IdIsIndex(sprop->id, &index))
|
||||||
setIndexedProperties();
|
setIndexedProperties();
|
||||||
|
|
||||||
if (sprop->isMethod())
|
|
||||||
setMethodBarrier();
|
|
||||||
|
|
||||||
METER(adds);
|
METER(adds);
|
||||||
return sprop;
|
return sprop;
|
||||||
|
|
||||||
@ -1669,11 +1655,11 @@ JSScopeProperty::trace(JSTracer *trc)
|
|||||||
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
|
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
|
||||||
if (attrs & JSPROP_GETTER) {
|
if (attrs & JSPROP_GETTER) {
|
||||||
JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, this, 0);
|
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) {
|
if (attrs & JSPROP_SETTER) {
|
||||||
JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, this, 1);
|
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 */
|
#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 -*-
|
/* -*- 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 *****
|
* ***** BEGIN LICENSE BLOCK *****
|
||||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
@ -286,13 +286,12 @@ struct JSScope {
|
|||||||
BRANDED = 0x0004,
|
BRANDED = 0x0004,
|
||||||
INDEXED_PROPERTIES = 0x0008,
|
INDEXED_PROPERTIES = 0x0008,
|
||||||
OWN_SHAPE = 0x0010,
|
OWN_SHAPE = 0x0010,
|
||||||
METHOD_BARRIER = 0x0020,
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This flag toggles with each shape-regenerating GC cycle.
|
* This flag toggles with each shape-regenerating GC cycle.
|
||||||
* See JSRuntime::gcRegenShapesScopeFlag.
|
* See JSRuntime::gcRegenShapesScopeFlag.
|
||||||
*/
|
*/
|
||||||
SHAPE_REGEN = 0x0040
|
SHAPE_REGEN = 0x0020
|
||||||
};
|
};
|
||||||
|
|
||||||
bool hadMiddleDelete() { return flags & MIDDLE_DELETE; }
|
bool hadMiddleDelete() { return flags & MIDDLE_DELETE; }
|
||||||
@ -323,42 +322,6 @@ struct JSScope {
|
|||||||
|
|
||||||
bool hasRegenFlag(uint8 regenFlag) { return (flags & SHAPE_REGEN) == regenFlag; }
|
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; }
|
bool owned() { return object != NULL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -400,8 +363,7 @@ js_CastAsPropertyOp(JSObject *object)
|
|||||||
struct JSScopeProperty {
|
struct JSScopeProperty {
|
||||||
jsid id; /* int-tagged jsval/untagged JSAtom* */
|
jsid id; /* int-tagged jsval/untagged JSAtom* */
|
||||||
JSPropertyOp getter; /* getter and setter hooks or objects */
|
JSPropertyOp getter; /* getter and setter hooks or objects */
|
||||||
JSPropertyOp setter; /* getter is JSObject* and setter is 0
|
JSPropertyOp setter;
|
||||||
if sprop->isMethod() */
|
|
||||||
uint32 slot; /* abstract index in object slots */
|
uint32 slot; /* abstract index in object slots */
|
||||||
uint8 attrs; /* attributes, see jsapi.h JSPROP_* */
|
uint8 attrs; /* attributes, see jsapi.h JSPROP_* */
|
||||||
uint8 flags; /* flags, see below for defines */
|
uint8 flags; /* flags, see below for defines */
|
||||||
@ -411,53 +373,6 @@ struct JSScopeProperty {
|
|||||||
to many-kids data structure */
|
to many-kids data structure */
|
||||||
uint32 shape; /* property cache shape identifier */
|
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);
|
void trace(JSTracer *trc);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -493,6 +408,12 @@ JSScope::has(JSScopeProperty *sprop)
|
|||||||
return lookup(sprop->id) == 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
|
* If SPROP_HAS_SHORTID is set in sprop->flags, we use sprop->shortid rather
|
||||||
* than id when calling sprop's getter or setter.
|
* 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_GETTER(sprop) (!(sprop)->getter)
|
||||||
#define SPROP_HAS_STUB_SETTER(sprop) (!(sprop)->setter)
|
#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
|
#ifndef JS_THREADSAFE
|
||||||
# define js_GenerateShape(cx, gcLocked) js_GenerateShape (cx)
|
# define js_GenerateShape(cx, gcLocked) js_GenerateShape (cx)
|
||||||
#endif
|
#endif
|
||||||
@ -633,47 +551,15 @@ JSScope::trace(JSTracer *trc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
static JS_INLINE bool
|
||||||
* Read barrier for deferred cloning of compiler-created function objects
|
js_GetSprop(JSContext* cx, JSScopeProperty* sprop, JSObject* obj, jsval* vp)
|
||||||
* optimized as typically non-escaping, ad-hoc methods in obj.
|
|
||||||
*/
|
|
||||||
JS_ALWAYS_INLINE bool
|
|
||||||
JSScopeProperty::methodBarrier(JSContext *cx, JSObject *obj, jsval *vp)
|
|
||||||
{
|
{
|
||||||
JSScope *scope = OBJ_SCOPE(obj);
|
JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop));
|
||||||
#ifdef JS_THREADSAFE
|
|
||||||
JS_ASSERT(scope->title.ownercx == cx);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (scope->hasMethodBarrier()) {
|
if (sprop->attrs & JSPROP_GETTER) {
|
||||||
JSObject *funobj = JSVAL_TO_OBJECT(*vp);
|
jsval fval = js_CastAsObjectJSVal(sprop->getter);
|
||||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
return js_InternalGetOrSet(cx, obj, sprop->id, fval, JSACC_READ,
|
||||||
|
0, 0, vp);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -684,28 +570,30 @@ JSScopeProperty::get(JSContext* cx, JSObject* obj, jsval* vp)
|
|||||||
*/
|
*/
|
||||||
if (STOBJ_GET_CLASS(obj) == &js_WithClass)
|
if (STOBJ_GET_CLASS(obj) == &js_WithClass)
|
||||||
obj = obj->map->ops->thisObject(cx, obj);
|
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
|
static JS_INLINE bool
|
||||||
JSScopeProperty::set(JSContext* cx, JSObject* obj, jsval* vp)
|
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) {
|
if (sprop->attrs & JSPROP_SETTER) {
|
||||||
jsval fval = setterValue();
|
jsval fval = js_CastAsObjectJSVal(sprop->setter);
|
||||||
return js_InternalGetOrSet(cx, obj, id, fval, JSACC_WRITE, 1, vp, vp);
|
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);
|
js_ReportGetterOnlyAssignment(cx);
|
||||||
return JS_FALSE;
|
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)
|
if (STOBJ_GET_CLASS(obj) == &js_WithClass)
|
||||||
obj = obj->map->ops->thisObject(cx, obj);
|
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. */
|
/* 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)
|
if (sprop->attrs & JSPROP_READONLY)
|
||||||
ABORT_TRACE_RV("writing to a read-only property", false);
|
ABORT_TRACE_RV("writing to a read-only property", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This check applies even when setflags == 0. */
|
/* 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);
|
ABORT_TRACE_RV("non-stub getter", false);
|
||||||
|
|
||||||
if (!SPROP_HAS_VALID_SLOT(sprop, scope))
|
if (!SPROP_HAS_VALID_SLOT(sprop, scope))
|
||||||
@ -4101,7 +4100,7 @@ TraceRecorder::hasMethod(JSObject* obj, jsid id)
|
|||||||
JSScope* scope = OBJ_SCOPE(pobj);
|
JSScope* scope = OBJ_SCOPE(pobj);
|
||||||
JSScopeProperty* sprop = (JSScopeProperty*) prop;
|
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)) {
|
SPROP_HAS_VALID_SLOT(sprop, scope)) {
|
||||||
jsval v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
|
jsval v = LOCKED_OBJ_GET_SLOT(pobj, sprop->slot);
|
||||||
if (VALUE_IS_FUNCTION(cx, v)) {
|
if (VALUE_IS_FUNCTION(cx, v)) {
|
||||||
@ -10486,33 +10485,32 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
|
|||||||
if (setflags && (sprop->attrs & JSPROP_READONLY))
|
if (setflags && (sprop->attrs & JSPROP_READONLY))
|
||||||
ABORT_TRACE("writing to a readonly property");
|
ABORT_TRACE("writing to a readonly property");
|
||||||
if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop)) {
|
if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop)) {
|
||||||
if (setflags == 0) {
|
// FIXME 450335: generalize this away from regexp built-in getters.
|
||||||
// FIXME 450335: generalize this away from regexp built-in getters.
|
if (setflags == 0 &&
|
||||||
if (sprop->getter == js_RegExpClass.getProperty &&
|
sprop->getter == js_RegExpClass.getProperty &&
|
||||||
sprop->shortid < 0) {
|
sprop->shortid < 0) {
|
||||||
if (sprop->shortid == REGEXP_LAST_INDEX)
|
if (sprop->shortid == REGEXP_LAST_INDEX)
|
||||||
ABORT_TRACE("can't trace RegExp.lastIndex yet");
|
ABORT_TRACE("can't trace RegExp.lastIndex yet");
|
||||||
LIns* args[] = { INS_CONSTPTR(sprop), obj_ins, cx_ins };
|
LIns* args[] = { INS_CONSTPTR(sprop), obj_ins, cx_ins };
|
||||||
v_ins = lir->insCall(&js_CallGetter_ci, args);
|
v_ins = lir->insCall(&js_CallGetter_ci, args);
|
||||||
guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT);
|
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
|
||||||
* 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.
|
||||||
* the value to the top of the stack is not the value we unbox.
|
*/
|
||||||
*/
|
unbox_jsval((sprop->shortid == REGEXP_SOURCE) ? JSVAL_STRING : JSVAL_BOOLEAN,
|
||||||
unbox_jsval((sprop->shortid == REGEXP_SOURCE) ? JSVAL_STRING : JSVAL_BOOLEAN,
|
v_ins,
|
||||||
v_ins,
|
snapshot(MISMATCH_EXIT));
|
||||||
snapshot(MISMATCH_EXIT));
|
return JSRS_CONTINUE;
|
||||||
return JSRS_CONTINUE;
|
}
|
||||||
}
|
if (setflags == 0 &&
|
||||||
if (sprop->getter == js_StringClass.getProperty &&
|
sprop->getter == js_StringClass.getProperty &&
|
||||||
sprop->id == ATOM_KEY(cx->runtime->atomState.lengthAtom)) {
|
sprop->id == ATOM_KEY(cx->runtime->atomState.lengthAtom)) {
|
||||||
if (!guardClass(obj, obj_ins, &js_StringClass, snapshot(MISMATCH_EXIT)))
|
if (!guardClass(obj, obj_ins, &js_StringClass, snapshot(MISMATCH_EXIT)))
|
||||||
ABORT_TRACE("can't trace String.length on non-String objects");
|
ABORT_TRACE("can't trace String.length on non-String objects");
|
||||||
LIns* str_ins = stobj_get_private(obj_ins, JSVAL_TAGMASK);
|
LIns* str_ins = stobj_get_private(obj_ins, JSVAL_TAGMASK);
|
||||||
v_ins = lir->ins1(LIR_i2f, getStringLength(str_ins));
|
v_ins = lir->ins1(LIR_i2f, getStringLength(str_ins));
|
||||||
return JSRS_CONTINUE;
|
return JSRS_CONTINUE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ABORT_TRACE("non-stub getter");
|
ABORT_TRACE("non-stub getter");
|
||||||
}
|
}
|
||||||
@ -11864,9 +11862,7 @@ TraceRecorder::record_JSOP_CALLPROP()
|
|||||||
} else if (JSVAL_TAG(l) == JSVAL_BOOLEAN) {
|
} else if (JSVAL_TAG(l) == JSVAL_BOOLEAN) {
|
||||||
if (l == JSVAL_VOID)
|
if (l == JSVAL_VOID)
|
||||||
ABORT_TRACE("callprop on void");
|
ABORT_TRACE("callprop on void");
|
||||||
guard(false,
|
guard(false, lir->ins2i(LIR_eq, get(&l), JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)), MISMATCH_EXIT);
|
||||||
lir->ins2i(LIR_eq, get(&l), JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)),
|
|
||||||
MISMATCH_EXIT);
|
|
||||||
i = JSProto_Boolean;
|
i = JSProto_Boolean;
|
||||||
debug_only_stmt(protoname = "Boolean.prototype";)
|
debug_only_stmt(protoname = "Boolean.prototype";)
|
||||||
} else {
|
} else {
|
||||||
@ -12378,18 +12374,6 @@ DBG_STUB(JSOP_DEFFUN_DBGFC)
|
|||||||
DBG_STUB(JSOP_DEFLOCALFUN_DBGFC)
|
DBG_STUB(JSOP_DEFLOCALFUN_DBGFC)
|
||||||
DBG_STUB(JSOP_LAMBDA_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
|
#ifdef JS_JIT_SPEW
|
||||||
/* Prints information about entry typemaps and unstable exits for all peers at a PC */
|
/* Prints information about entry typemaps and unstable exits for all peers at a PC */
|
||||||
void
|
void
|
||||||
|
@ -456,14 +456,6 @@ typedef JSUintPtr JSUword;
|
|||||||
# define JS_DATA_TO_FUNC_PTR(type, ptr) ((type) (void *) (ptr))
|
# define JS_DATA_TO_FUNC_PTR(type, ptr) ((type) (void *) (ptr))
|
||||||
#endif
|
#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
|
JS_END_EXTERN_C
|
||||||
|
|
||||||
#endif /* jstypes_h___ */
|
#endif /* jstypes_h___ */
|
||||||
|
@ -204,7 +204,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
|
|||||||
* before deserialization of bytecode. If the saved version does not match
|
* before deserialization of bytecode. If the saved version does not match
|
||||||
* the current version, abort deserialization and invalidate the file.
|
* the current version, abort deserialization and invalidate the file.
|
||||||
*/
|
*/
|
||||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 50)
|
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 49)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Library-private functions.
|
* Library-private functions.
|
||||||
|
Loading…
Reference in New Issue
Block a user