mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] Cache standard class objects earlier to avoid reentrant class construction, bug 646393.
This commit is contained in:
parent
cb84851874
commit
70ee8fa7f3
4
js/src/jit-test/tests/basic/bug646393.js
Normal file
4
js/src/jit-test/tests/basic/bug646393.js
Normal file
@ -0,0 +1,4 @@
|
||||
try {
|
||||
x.y;
|
||||
} catch(ex) {}
|
||||
x = Number(1);
|
@ -3865,6 +3865,9 @@ DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
|
||||
{
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
|
||||
if (!cx->addTypePropertyId(obj->getType(), id, v))
|
||||
return false;
|
||||
|
||||
if (key != JSProto_Null) {
|
||||
/*
|
||||
* Initializing an actual standard class on a global object. If the
|
||||
@ -3896,6 +3899,28 @@ DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
|
||||
|
||||
namespace js {
|
||||
|
||||
static bool
|
||||
SetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject *cobj, JSObject *proto)
|
||||
{
|
||||
JS_ASSERT(!obj->getParent());
|
||||
if (!obj->isGlobal())
|
||||
return true;
|
||||
|
||||
return js_SetReservedSlot(cx, obj, key, ObjectOrNullValue(cobj)) &&
|
||||
js_SetReservedSlot(cx, obj, JSProto_LIMIT + key, ObjectOrNullValue(proto));
|
||||
}
|
||||
|
||||
static void
|
||||
ClearClassObject(JSContext *cx, JSObject *obj, JSProtoKey key)
|
||||
{
|
||||
JS_ASSERT(!obj->getParent());
|
||||
if (!obj->isGlobal())
|
||||
return;
|
||||
|
||||
obj->setSlot(key, UndefinedValue());
|
||||
obj->setSlot(JSProto_LIMIT + key, UndefinedValue());
|
||||
}
|
||||
|
||||
JSObject *
|
||||
DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
|
||||
JSObject *protoProto, Class *clasp,
|
||||
@ -3955,6 +3980,7 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
|
||||
|
||||
JSObject *ctor;
|
||||
bool named = false;
|
||||
bool cached = false;
|
||||
if (!constructor) {
|
||||
/*
|
||||
* Lacking a constructor, name the prototype (e.g., Math) unless this
|
||||
@ -3966,8 +3992,6 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
|
||||
uint32 attrs = (clasp->flags & JSCLASS_IS_ANONYMOUS)
|
||||
? JSPROP_READONLY | JSPROP_PERMANENT
|
||||
: 0;
|
||||
if (!cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), ObjectValue(*proto)))
|
||||
goto bad;
|
||||
if (!DefineStandardSlot(cx, obj, key, atom, ObjectValue(*proto), attrs, named))
|
||||
goto bad;
|
||||
}
|
||||
@ -3979,9 +4003,20 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
|
||||
|
||||
JSFunction *fun = js_NewFunction(cx, NULL, constructor, nargs, JSFUN_CONSTRUCTOR, obj, atom,
|
||||
ctorHandler, clasp->name);
|
||||
if (!fun || !cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), ObjectValue(*fun)))
|
||||
if (!fun)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Set the class object early for standard class constructors. Type
|
||||
* inference may need to access these, and js_GetClassPrototype will
|
||||
* fail if it tries to do a reentrant reconstruction of the class.
|
||||
*/
|
||||
if (key != JSProto_Null && !(clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) &&
|
||||
!SetClassObject(cx, obj, key, fun, proto)) {
|
||||
goto bad;
|
||||
}
|
||||
cached = true;
|
||||
|
||||
AutoValueRooter tvr2(cx, ObjectValue(*fun));
|
||||
if (!DefineStandardSlot(cx, obj, key, atom, tvr2.value(), 0, named))
|
||||
goto bad;
|
||||
@ -4071,7 +4106,7 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
|
||||
}
|
||||
|
||||
/* If this is a standard class, cache its prototype. */
|
||||
if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor, proto))
|
||||
if (!cached && key != JSProto_Null && !SetClassObject(cx, obj, key, ctor, proto))
|
||||
goto bad;
|
||||
|
||||
return proto;
|
||||
@ -4081,6 +4116,8 @@ bad:
|
||||
Value rval;
|
||||
obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval, false);
|
||||
}
|
||||
if (cached)
|
||||
ClearClassObject(cx, obj, key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -4339,17 +4376,6 @@ js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_SetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject *cobj, JSObject *proto)
|
||||
{
|
||||
JS_ASSERT(!obj->getParent());
|
||||
if (!obj->isGlobal())
|
||||
return JS_TRUE;
|
||||
|
||||
return js_SetReservedSlot(cx, obj, key, ObjectOrNullValue(cobj)) &&
|
||||
js_SetReservedSlot(cx, obj, JSProto_LIMIT + key, ObjectOrNullValue(proto));
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
|
||||
Value *vp, Class *clasp)
|
||||
|
@ -1564,10 +1564,6 @@ extern JSBool
|
||||
js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
|
||||
JSObject **objp);
|
||||
|
||||
extern JSBool
|
||||
js_SetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
|
||||
JSObject *cobj, JSObject *prototype);
|
||||
|
||||
/*
|
||||
* If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
|
||||
* JSProto_Null, clasp must non-null.
|
||||
|
Loading…
Reference in New Issue
Block a user