Bug 1169639 - Make intrinsicsHolder-accesses fallible, now that it's possible to access it without having previously gone through intrinsics-object creation code to ensure its existence. r=shu

This commit is contained in:
Jeff Walden 2015-06-08 10:55:53 -07:00
parent c848a1cba8
commit 2d503d3ff8
10 changed files with 132 additions and 81 deletions

View File

@ -1128,39 +1128,25 @@ CreateObjectPrototype(JSContext* cx, JSProtoKey key)
static bool
FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
{
Rooted<GlobalObject*> self(cx, cx->global());
Rooted<GlobalObject*> global(cx, cx->global());
/* ES5 15.1.2.1. */
RootedId evalId(cx, NameToId(cx->names().eval));
JSObject* evalobj = DefineFunction(cx, self, evalId, IndirectEval, 1,
JSObject* evalobj = DefineFunction(cx, global, evalId, IndirectEval, 1,
JSFUN_STUB_GSOPS | JSPROP_RESOLVING);
if (!evalobj)
return false;
self->setOriginalEval(evalobj);
global->setOriginalEval(evalobj);
RootedObject intrinsicsHolder(cx);
bool isSelfHostingGlobal = cx->runtime()->isSelfHostingGlobal(self);
if (isSelfHostingGlobal) {
intrinsicsHolder = self;
} else {
intrinsicsHolder = NewObjectWithGivenProto<PlainObject>(cx, proto, TenuredObject);
if (!intrinsicsHolder)
return false;
}
self->setIntrinsicsHolder(intrinsicsHolder);
/* Define a property 'global' with the current global as its value. */
RootedValue global(cx, ObjectValue(*self));
if (!DefineProperty(cx, intrinsicsHolder, cx->names().global, global,
nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY))
{
Rooted<NativeObject*> holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
if (!holder)
return false;
}
/*
* Define self-hosted functions after setting the intrinsics holder
* (which is needed to define self-hosted functions)
*/
if (!isSelfHostingGlobal) {
if (!cx->runtime()->isSelfHostingGlobal(global)) {
if (!JS_DefineFunctions(cx, ctor, object_static_methods, OnlyDefineLateProperties))
return false;
if (!JS_DefineFunctions(cx, proto, object_methods, OnlyDefineLateProperties))
@ -1176,8 +1162,10 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro
* only set the [[Prototype]] if it hasn't already been set.
*/
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
if (self->shouldSplicePrototype(cx) && !self->splicePrototype(cx, self->getClass(), tagged))
return false;
if (global->shouldSplicePrototype(cx)) {
if (!global->splicePrototype(cx, global->getClass(), tagged))
return false;
}
return true;
}

View File

@ -100,3 +100,8 @@ function primitiveThisTests()
if (primitiveThisSupported())
primitiveThisTests();
// Ensure the internal implementation of destructuring object pattern
// assignment -- using a self-hosted intrinsic function -- works even when lazy
// standard class initialization hasn't occurred. Unfortunately we can't use
// |newGlobal()| because that method eagerly initializes standard classes.
evalcx("({} = 1);", evalcx("lazy"));

View File

@ -7663,9 +7663,10 @@ IonBuilder::jsop_intrinsic(PropertyName* name)
return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
}
// Bake in the intrinsic. Make sure that TI agrees with us on the type.
Value vp;
JS_ALWAYS_TRUE(script()->global().maybeGetIntrinsicValue(name, &vp));
// Bake in the intrinsic, guaranteed to exist because a non-empty typeset
// means the intrinsic was successfully gotten in the VM call above.
// Assert that TI agrees with us on the type.
Value vp = script()->global().existingIntrinsicValue(name);
MOZ_ASSERT(types->hasType(TypeSet::GetValueType(vp)));
pushConstant(vp);

View File

@ -2482,30 +2482,38 @@ DefineSelfHostedProperty(JSContext* cx, HandleObject obj, HandleId id,
const char* getterName, const char* setterName,
unsigned attrs, unsigned flags)
{
RootedAtom getterNameAtom(cx, Atomize(cx, getterName, strlen(getterName)));
JSAtom* getterNameAtom = Atomize(cx, getterName, strlen(getterName));
if (!getterNameAtom)
return false;
RootedPropertyName getterNameName(cx, getterNameAtom->asPropertyName());
RootedAtom name(cx, IdToFunctionName(cx, id));
if (!name)
return false;
RootedValue getterValue(cx);
if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, name, 0, &getterValue))
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), getterNameName, name, 0,
&getterValue))
{
return false;
}
MOZ_ASSERT(getterValue.isObject() && getterValue.toObject().is<JSFunction>());
RootedFunction getterFunc(cx, &getterValue.toObject().as<JSFunction>());
JSNative getterOp = JS_DATA_TO_FUNC_PTR(JSNative, getterFunc.get());
RootedFunction setterFunc(cx);
if (setterName) {
RootedAtom setterNameAtom(cx, Atomize(cx, setterName, strlen(setterName)));
JSAtom* setterNameAtom = Atomize(cx, setterName, strlen(setterName));
if (!setterNameAtom)
return false;
RootedPropertyName setterNameName(cx, setterNameAtom->asPropertyName());
RootedValue setterValue(cx);
if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, name, 0, &setterValue))
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), setterNameName, name, 0,
&setterValue))
{
return false;
}
MOZ_ASSERT(setterValue.isObject() && setterValue.toObject().is<JSFunction>());
setterFunc = &getterValue.toObject().as<JSFunction>();
}
@ -3289,11 +3297,12 @@ JS::GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id
if (!name)
return nullptr;
RootedAtom shName(cx, Atomize(cx, selfHostedName, strlen(selfHostedName)));
if (!shName)
JSAtom* shAtom = Atomize(cx, selfHostedName, strlen(selfHostedName));
if (!shAtom)
return nullptr;
RootedPropertyName shName(cx, shAtom->asPropertyName());
RootedValue funVal(cx);
if (!cx->global()->getSelfHostedFunction(cx, shName, name, nargs, &funVal))
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, nargs, &funVal))
return nullptr;
return &funVal.toObject().as<JSFunction>();
}
@ -3590,15 +3599,19 @@ JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
MOZ_ASSERT(!fs->call.op);
MOZ_ASSERT(!fs->call.info);
RootedAtom shName(cx, Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName)));
if (!shName)
JSAtom* shAtom = Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName));
if (!shAtom)
return false;
RootedPropertyName shName(cx, shAtom->asPropertyName());
RootedAtom name(cx, IdToFunctionName(cx, id));
if (!name)
return false;
RootedValue funVal(cx);
if (!cx->global()->getSelfHostedFunction(cx, shName, name, fs->nargs, &funVal))
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, fs->nargs,
&funVal))
{
return false;
}
if (!DefineProperty(cx, obj, id, funVal, nullptr, nullptr, flags))
return false;
} else {

View File

@ -21,6 +21,7 @@
macro(ArrayIteratorNext, ArrayIteratorNext, "ArrayIteratorNext") \
macro(ArrayType, ArrayType, "ArrayType") \
macro(ArrayValues, ArrayValues, "ArrayValues") \
macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
macro(Async, Async, "Async") \
macro(breakdown, breakdown, "breakdown") \
macro(buffer, buffer, "buffer") \

View File

@ -170,14 +170,9 @@ ForOfIterator::materializeArrayIterator()
{
MOZ_ASSERT(index != NOT_ARRAY);
const char* nameString = "ArrayValuesAt";
RootedAtom name(cx_, Atomize(cx_, nameString, strlen(nameString)));
if (!name)
return false;
HandlePropertyName name = cx_->names().ArrayValuesAt;
RootedValue val(cx_);
if (!cx_->global()->getSelfHostedFunction(cx_, name, name, 1, &val))
if (!GlobalObject::getSelfHostedFunction(cx_, cx_->global(), name, name, 1, &val))
return false;
InvokeArgs args(cx_);

View File

@ -602,14 +602,44 @@ GlobalObject::getAlreadyCreatedRegExpStatics() const
return static_cast<RegExpStatics*>(val.toObject().as<RegExpStaticsObject>().getPrivate(/* nfixed = */ 1));
}
bool
GlobalObject::getSelfHostedFunction(JSContext* cx, HandleAtom selfHostedName, HandleAtom name,
/* static */ NativeObject*
GlobalObject::getIntrinsicsHolder(JSContext* cx, Handle<GlobalObject*> global)
{
Value slot = global->getReservedSlot(INTRINSICS);
MOZ_ASSERT(slot.isUndefined() || slot.isObject());
if (slot.isObject())
return &slot.toObject().as<NativeObject>();
Rooted<NativeObject*> intrinsicsHolder(cx);
bool isSelfHostingGlobal = cx->runtime()->isSelfHostingGlobal(global);
if (isSelfHostingGlobal) {
intrinsicsHolder = global;
} else {
intrinsicsHolder = NewObjectWithGivenProto<PlainObject>(cx, nullptr, TenuredObject);
if (!intrinsicsHolder)
return nullptr;
}
/* Define a property 'global' with the current global as its value. */
RootedValue globalValue(cx, ObjectValue(*global));
if (!DefineProperty(cx, intrinsicsHolder, cx->names().global, globalValue,
nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY))
{
return nullptr;
}
// Install the intrinsics holder in the intrinsics.
global->setReservedSlot(INTRINSICS, ObjectValue(*intrinsicsHolder));
return intrinsicsHolder;
}
/* static */ bool
GlobalObject::getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
HandlePropertyName selfHostedName, HandleAtom name,
unsigned nargs, MutableHandleValue funVal)
{
RootedId shId(cx, AtomToId(selfHostedName));
RootedObject holder(cx, cx->global()->intrinsicsHolder());
if (cx->global()->maybeGetIntrinsicValue(shId, funVal.address()))
if (GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal))
return true;
JSFunction* fun =
@ -621,18 +651,22 @@ GlobalObject::getSelfHostedFunction(JSContext* cx, HandleAtom selfHostedName, Ha
fun->setExtendedSlot(0, StringValue(selfHostedName));
funVal.setObject(*fun);
return cx->global()->addIntrinsicValue(cx, shId, funVal);
return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal);
}
bool
GlobalObject::addIntrinsicValue(JSContext* cx, HandleId id, HandleValue value)
/* static */ bool
GlobalObject::addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
HandlePropertyName name, HandleValue value)
{
RootedNativeObject holder(cx, intrinsicsHolder());
RootedNativeObject holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
if (!holder)
return false;
uint32_t slot = holder->slotSpan();
RootedShape last(cx, holder->lastProperty());
Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
RootedId id(cx, NameToId(name));
StackShape child(base, id, slot, 0, 0);
Shape* shape = cx->compartment()->propertyTree.getChild(cx, last, child);
if (!shape)

View File

@ -148,11 +148,6 @@ class GlobalObject : public NativeObject
setSlot(EVAL, ObjectValue(*evalobj));
}
void setIntrinsicsHolder(JSObject* obj) {
MOZ_ASSERT(getSlotRef(INTRINSICS).isUndefined());
setSlot(INTRINSICS, ObjectValue(*obj));
}
Value getConstructor(JSProtoKey key) const {
MOZ_ASSERT(key <= JSProto_LIMIT);
return getSlot(APPLICATION_SLOTS + key);
@ -604,48 +599,61 @@ class GlobalObject : public NativeObject
return &self->getPrototype(JSProto_DataView).toObject();
}
NativeObject* intrinsicsHolder() {
MOZ_ASSERT(!getSlot(INTRINSICS).isUndefined());
return &getSlot(INTRINSICS).toObject().as<NativeObject>();
static NativeObject* getIntrinsicsHolder(JSContext* cx, Handle<GlobalObject*> global);
Value existingIntrinsicValue(PropertyName* name) {
Value slot = getReservedSlot(INTRINSICS);
MOZ_ASSERT(slot.isObject(), "intrinsics holder must already exist");
NativeObject* holder = &slot.toObject().as<NativeObject>();
Shape* shape = holder->lookupPure(name);
MOZ_ASSERT(shape, "intrinsic must already have been added to holder");
return holder->getSlot(shape->slot());
}
bool maybeGetIntrinsicValue(jsid id, Value* vp) {
NativeObject* holder = intrinsicsHolder();
static bool
maybeGetIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global, Handle<PropertyName*> name,
MutableHandleValue vp)
{
NativeObject* holder = getIntrinsicsHolder(cx, global);
if (!holder)
return false;
if (Shape* shape = holder->lookupPure(id)) {
*vp = holder->getSlot(shape->slot());
if (Shape* shape = holder->lookupPure(name)) {
vp.set(holder->getSlot(shape->slot()));
return true;
}
return false;
}
bool maybeGetIntrinsicValue(PropertyName* name, Value* vp) {
return maybeGetIntrinsicValue(NameToId(name), vp);
}
static bool getIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
HandlePropertyName name, MutableHandleValue value)
{
if (global->maybeGetIntrinsicValue(name, value.address()))
if (GlobalObject::maybeGetIntrinsicValue(cx, global, name, value))
return true;
if (!cx->runtime()->cloneSelfHostedValue(cx, name, value))
return false;
RootedId id(cx, NameToId(name));
return global->addIntrinsicValue(cx, id, value);
return GlobalObject::addIntrinsicValue(cx, global, name, value);
}
bool addIntrinsicValue(JSContext* cx, HandleId id, HandleValue value);
static bool addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName name,
HandleValue value);
bool setIntrinsicValue(JSContext* cx, PropertyName* name, HandleValue value) {
#ifdef DEBUG
RootedObject self(cx, this);
MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(self));
#endif
RootedObject holder(cx, intrinsicsHolder());
static bool setIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global, PropertyName* name,
HandleValue value)
{
MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(global));
RootedObject holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
if (!holder)
return false;
return SetProperty(cx, holder, name, value);
}
bool getSelfHostedFunction(JSContext* cx, HandleAtom selfHostedName, HandleAtom name,
unsigned nargs, MutableHandleValue funVal);
static bool getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
HandlePropertyName selfHostedName, HandleAtom name,
unsigned nargs, MutableHandleValue funVal);
bool hasRegExpStatics() const;
RegExpStatics* getRegExpStatics(ExclusiveContext* cx) const;

View File

@ -246,7 +246,7 @@ inline bool
SetIntrinsicOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleValue val)
{
RootedPropertyName name(cx, script->getName(pc));
return cx->global()->setIntrinsicValue(cx, name, val);
return GlobalObject::setIntrinsicValue(cx, cx->global(), name, val);
}
inline void

View File

@ -2310,7 +2310,13 @@ CASE(JSOP_SETCONST)
END_CASE(JSOP_SETCONST)
CASE(JSOP_BINDINTRINSIC)
PUSH_OBJECT(*cx->global()->intrinsicsHolder());
{
NativeObject* holder = GlobalObject::getIntrinsicsHolder(cx, cx->global());
if (!holder)
goto error;
PUSH_OBJECT(*holder);
}
END_CASE(JSOP_BINDINTRINSIC)
CASE(JSOP_BINDGNAME)