Merge tracemonkey to mozilla-central.
This commit is contained in:
305
js/src/jsobj.cpp
305
js/src/jsobj.cpp
@@ -321,23 +321,6 @@ js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj)
|
||||
}
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Maintain the "any Array prototype has indexed properties hazard" flag by
|
||||
* conservatively setting it. We simply don't know what pobj has in the way
|
||||
* of indexed properties, either directly or along its prototype chain, and
|
||||
* we won't expend effort here to find out. We do know that if obj is not
|
||||
* an array or a prototype (delegate), then we're ok. And, of course, pobj
|
||||
* must be non-null.
|
||||
*
|
||||
* This pessimistic approach could be improved, but setting __proto__ is
|
||||
* quite rare and arguably deserving of deoptimization.
|
||||
*/
|
||||
if (slot == JSSLOT_PROTO &&
|
||||
pobj &&
|
||||
(OBJ_IS_ARRAY(cx, obj) || OBJ_IS_DELEGATE(cx, obj))) {
|
||||
rt->anyArrayProtoHasElement = JS_TRUE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@@ -2021,6 +2004,91 @@ js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#ifdef JS_TRACER
|
||||
|
||||
static inline JSObject*
|
||||
NewNativeObject(JSContext* cx, JSObject* proto, JSObject *parent)
|
||||
{
|
||||
JS_ASSERT(JS_ON_TRACE(cx));
|
||||
JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
obj->classword = jsuword(&js_ObjectClass);
|
||||
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
||||
obj->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent);
|
||||
for (unsigned i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
|
||||
obj->fslots[i] = JSVAL_VOID;
|
||||
|
||||
JS_ASSERT(!OBJ_GET_CLASS(cx, proto)->getObjectOps);
|
||||
JS_ASSERT(proto->map->ops == &js_ObjectOps);
|
||||
obj->map = js_HoldObjectMap(cx, proto->map);
|
||||
obj->dslots = NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSObject* FASTCALL
|
||||
js_Object_tn(JSContext* cx, JSObject* proto)
|
||||
{
|
||||
return NewNativeObject(cx, proto, JSVAL_TO_OBJECT(proto->fslots[JSSLOT_PARENT]));
|
||||
}
|
||||
|
||||
JS_DEFINE_TRCINFO_1(js_Object,
|
||||
(2, (extern, CONSTRUCTOR_RETRY, js_Object_tn, CONTEXT, CALLEE_PROTOTYPE, 0, 0)))
|
||||
|
||||
JSObject* FASTCALL
|
||||
js_NewInstance(JSContext* cx, JSObject *ctor)
|
||||
{
|
||||
JS_ASSERT(HAS_FUNCTION_CLASS(ctor));
|
||||
#ifdef DEBUG
|
||||
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, ctor);
|
||||
JS_ASSERT(FUN_INTERPRETED(fun));
|
||||
#endif
|
||||
|
||||
JSAtom* atom = cx->runtime->atomState.classPrototypeAtom;
|
||||
|
||||
JS_LOCK_OBJ(cx, ctor);
|
||||
JSScope *scope = OBJ_SCOPE(ctor);
|
||||
if (scope->object != ctor) {
|
||||
scope = js_GetMutableScope(cx, ctor);
|
||||
if (!scope)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSScopeProperty* sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
|
||||
jsval pval = sprop ? LOCKED_OBJ_GET_SLOT(ctor, sprop->slot) : JSVAL_HOLE;
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
|
||||
JSObject* proto;
|
||||
if (!JSVAL_IS_PRIMITIVE(pval)) {
|
||||
/* An object in ctor.prototype, let's use it as the new instance's proto. */
|
||||
proto = JSVAL_TO_OBJECT(pval);
|
||||
} else if (pval == JSVAL_HOLE) {
|
||||
/* No ctor.prototype yet, inline and optimize fun_resolve's prototype code. */
|
||||
proto = js_NewObject(cx, &js_ObjectClass, NULL, OBJ_GET_PARENT(cx, ctor), 0);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
if (!js_SetClassPrototype(cx, ctor, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT))
|
||||
return NULL;
|
||||
} else {
|
||||
/* Primitive value in .prototype means we use Object.prototype for proto. */
|
||||
if (!js_GetClassPrototype(cx, JSVAL_TO_OBJECT(ctor->fslots[JSSLOT_PARENT]),
|
||||
INT_TO_JSID(JSProto_Object), &proto)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NewNativeObject(cx, proto, JSVAL_TO_OBJECT(ctor->fslots[JSSLOT_PARENT]));
|
||||
}
|
||||
|
||||
JS_DEFINE_CALLINFO_2(extern, CONSTRUCTOR_RETRY, js_NewInstance, CONTEXT, CALLEE_PROTOTYPE, 0, 0)
|
||||
|
||||
#else /* !JS_TRACER */
|
||||
|
||||
# define js_Object_trcinfo NULL
|
||||
|
||||
#endif /* !JS_TRACER */
|
||||
|
||||
/*
|
||||
* Given pc pointing after a property accessing bytecode, return true if the
|
||||
* access is "object-detecting" in the sense used by web scripts, e.g., when
|
||||
@@ -2593,9 +2661,157 @@ js_InitEval(JSContext *cx, JSObject *obj)
|
||||
JSObject *
|
||||
js_InitObjectClass(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
return JS_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1,
|
||||
object_props, object_methods, NULL,
|
||||
object_static_methods);
|
||||
return js_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1,
|
||||
object_props, object_methods, NULL, object_static_methods,
|
||||
js_Object_trcinfo);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
|
||||
JSClass *clasp, JSNative constructor, uintN nargs,
|
||||
JSPropertySpec *ps, JSFunctionSpec *fs,
|
||||
JSPropertySpec *static_ps, JSFunctionSpec *static_fs,
|
||||
JSTraceableNative *trcinfo)
|
||||
{
|
||||
JSAtom *atom;
|
||||
JSProtoKey key;
|
||||
JSObject *proto, *ctor;
|
||||
JSTempValueRooter tvr;
|
||||
jsval cval, rval;
|
||||
JSBool named;
|
||||
JSFunction *fun;
|
||||
|
||||
atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
|
||||
if (!atom)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* When initializing a standard class, if no parent_proto (grand-proto of
|
||||
* instances of the class, parent-proto of the class's prototype object)
|
||||
* is given, we must use Object.prototype if it is available. Otherwise,
|
||||
* we could look up the wrong binding for a class name in obj. Example:
|
||||
*
|
||||
* String = Array;
|
||||
* print("hi there".join);
|
||||
*
|
||||
* should print undefined, not Array.prototype.join. This is required by
|
||||
* ECMA-262, alas. It might have been better to make String readonly and
|
||||
* permanent in the global object, instead -- but that's too big a change
|
||||
* to swallow at this point.
|
||||
*/
|
||||
key = JSCLASS_CACHED_PROTO_KEY(clasp);
|
||||
if (key != JSProto_Null &&
|
||||
!parent_proto &&
|
||||
!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
|
||||
&parent_proto)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create a prototype object for this class. */
|
||||
proto = js_NewObject(cx, clasp, parent_proto, obj, 0);
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
/* After this point, control must exit via label bad or out. */
|
||||
JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr);
|
||||
|
||||
if (!constructor) {
|
||||
JS_ASSERT(!trcinfo);
|
||||
|
||||
/*
|
||||
* Lacking a constructor, name the prototype (e.g., Math) unless this
|
||||
* class (a) is anonymous, i.e. for internal use only; (b) the class
|
||||
* of obj (the global object) is has a reserved slot indexed by key;
|
||||
* and (c) key is not the null key.
|
||||
*/
|
||||
if ((clasp->flags & JSCLASS_IS_ANONYMOUS) &&
|
||||
(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) &&
|
||||
key != JSProto_Null) {
|
||||
named = JS_FALSE;
|
||||
} else {
|
||||
named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
|
||||
OBJECT_TO_JSVAL(proto),
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
(clasp->flags & JSCLASS_IS_ANONYMOUS)
|
||||
? JSPROP_READONLY | JSPROP_PERMANENT
|
||||
: 0,
|
||||
NULL);
|
||||
if (!named)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
ctor = proto;
|
||||
} else {
|
||||
/* Define the constructor function in obj's scope. */
|
||||
fun = js_DefineFunction(cx, obj, atom, constructor, nargs,
|
||||
JSFUN_STUB_GSOPS);
|
||||
named = (fun != NULL);
|
||||
if (!fun)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Remember the class this function is a constructor for so that
|
||||
* we know to create an object of this class when we call the
|
||||
* constructor.
|
||||
*/
|
||||
FUN_CLASP(fun) = clasp;
|
||||
|
||||
/*
|
||||
* If we have a traceable native constructor, update the function to
|
||||
* point at the given trcinfo and flag it.
|
||||
*/
|
||||
if (trcinfo) {
|
||||
fun->u.n.trcinfo = trcinfo;
|
||||
fun->flags |= JSFUN_TRACEABLE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Optionally construct the prototype object, before the class has
|
||||
* been fully initialized. Allow the ctor to replace proto with a
|
||||
* different object, as is done for operator new -- and as at least
|
||||
* XML support requires.
|
||||
*/
|
||||
ctor = FUN_OBJECT(fun);
|
||||
if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
|
||||
cval = OBJECT_TO_JSVAL(ctor);
|
||||
if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval))
|
||||
goto bad;
|
||||
if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto)
|
||||
proto = JSVAL_TO_OBJECT(rval);
|
||||
}
|
||||
|
||||
/* Connect constructor and prototype by named properties. */
|
||||
if (!js_SetClassPrototype(cx, ctor, proto,
|
||||
JSPROP_READONLY | JSPROP_PERMANENT)) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
|
||||
if (OBJ_GET_CLASS(cx, ctor) == clasp)
|
||||
OBJ_SET_PROTO(cx, ctor, proto);
|
||||
}
|
||||
|
||||
/* Add properties and methods to the prototype and the constructor. */
|
||||
if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
|
||||
(fs && !JS_DefineFunctions(cx, proto, fs)) ||
|
||||
(static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
|
||||
(static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* If this is a standard class, cache its prototype. */
|
||||
if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor))
|
||||
goto bad;
|
||||
|
||||
out:
|
||||
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||
return proto;
|
||||
|
||||
bad:
|
||||
if (named)
|
||||
(void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval);
|
||||
proto = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2877,7 +3093,7 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
|
||||
STOBJ_SET_PARENT(obj, parent);
|
||||
|
||||
/* Initialize the remaining fixed slots. */
|
||||
for (i = JSSLOT_PRIVATE; i != JS_INITIAL_NSLOTS; ++i)
|
||||
for (i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
|
||||
obj->fslots[i] = JSVAL_VOID;
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -2971,6 +3187,28 @@ earlybad:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, uint32 slot)
|
||||
{
|
||||
JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
obj->classword = jsuword(clasp);
|
||||
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
||||
obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
|
||||
|
||||
JS_ASSERT(slot > JSSLOT_PARENT);
|
||||
while (slot < JS_INITIAL_NSLOTS)
|
||||
obj->fslots[slot++] = JSVAL_VOID;
|
||||
|
||||
JS_ASSERT(!clasp->getObjectOps);
|
||||
JS_ASSERT(proto->map->ops == &js_ObjectOps);
|
||||
obj->map = js_HoldObjectMap(cx, proto->map);
|
||||
obj->dslots = NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
static JSObject *
|
||||
@@ -3343,11 +3581,10 @@ PurgeProtoChain(JSContext *cx, JSObject *obj, jsid id)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id)
|
||||
void
|
||||
js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id)
|
||||
{
|
||||
if (!OBJ_IS_DELEGATE(cx, obj))
|
||||
return;
|
||||
JS_ASSERT(OBJ_IS_DELEGATE(cx, obj));
|
||||
|
||||
/*
|
||||
* All scope chains end in a global object, so this will change the global
|
||||
@@ -3376,7 +3613,7 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
|
||||
* this optimistically (assuming no failure below) before locking obj, so
|
||||
* we can lock the shadowed scope.
|
||||
*/
|
||||
PurgeScopeChain(cx, obj, id);
|
||||
js_PurgeScopeChain(cx, obj, id);
|
||||
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
scope = js_GetMutableScope(cx, obj);
|
||||
@@ -3441,8 +3678,6 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
LOCKED_OBJ_WRITE_BARRIER(cx, obj, (sprop)->slot, *(vp)); \
|
||||
} \
|
||||
} \
|
||||
if (STOBJ_IS_DELEGATE(obj) && JSID_IS_INT(sprop->id)) \
|
||||
cx->runtime->anyArrayProtoHasElement = JS_TRUE; \
|
||||
JS_END_MACRO
|
||||
|
||||
JSBool
|
||||
@@ -3510,7 +3745,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
* Purge the property cache of now-shadowed id in obj's scope chain.
|
||||
* Do this early, before locking obj to avoid nesting locks.
|
||||
*/
|
||||
PurgeScopeChain(cx, obj, id);
|
||||
js_PurgeScopeChain(cx, obj, id);
|
||||
|
||||
/* Lock if object locking is required by this implementation. */
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
@@ -3985,9 +4220,9 @@ JSBool
|
||||
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
|
||||
JSPropCacheEntry **entryp)
|
||||
{
|
||||
JSObject *aobj, *obj2;
|
||||
uint32 shape;
|
||||
int protoIndex;
|
||||
JSObject *obj2;
|
||||
JSProperty *prop;
|
||||
JSScopeProperty *sprop;
|
||||
|
||||
@@ -3995,8 +4230,9 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
|
||||
/* Convert string indices to integers if appropriate. */
|
||||
CHECK_FOR_STRING_INDEX(id);
|
||||
|
||||
shape = OBJ_SHAPE(obj);
|
||||
protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
|
||||
aobj = js_GetProtoIfDenseArray(cx, obj);
|
||||
shape = OBJ_SHAPE(aobj);
|
||||
protoIndex = js_LookupPropertyWithFlags(cx, aobj, id, cx->resolveFlags,
|
||||
&obj2, &prop);
|
||||
if (protoIndex < 0)
|
||||
return JS_FALSE;
|
||||
@@ -4074,7 +4310,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
|
||||
|
||||
if (entryp) {
|
||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||
js_FillPropertyCache(cx, obj, shape, 0, protoIndex, obj2, sprop, entryp);
|
||||
js_FillPropertyCache(cx, aobj, shape, 0, protoIndex, obj2, sprop, entryp);
|
||||
}
|
||||
JS_UNLOCK_OBJ(cx, obj2);
|
||||
return JS_TRUE;
|
||||
@@ -4241,7 +4477,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
|
||||
* Purge the property cache of now-shadowed id in obj's scope chain.
|
||||
* Do this early, before locking obj to avoid nesting locks.
|
||||
*/
|
||||
PurgeScopeChain(cx, obj, id);
|
||||
js_PurgeScopeChain(cx, obj, id);
|
||||
|
||||
/* Find or make a property descriptor with the right heritage. */
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
@@ -5592,6 +5828,7 @@ js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
|
||||
scope->map.freeslot = slot + 1;
|
||||
|
||||
STOBJ_SET_SLOT(obj, slot, v);
|
||||
GC_POKE(cx, JS_NULL);
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user