Bug 1054756, part 1 - Support symbol-keyed properties in JSXrayTraits::resolveOwnProperty(). r=jandem.

--HG--
extra : commitid : Iw7k8V0s8vH
extra : rebase_source : 47344f609f8282df5cfe30ccb89792e3b26e5d3c
This commit is contained in:
Jason Orendorff 2015-07-07 19:22:20 -05:00
Родитель 15a26cce97
Коммит cba3fb8913
5 изменённых файлов: 119 добавлений и 102 удалений

Просмотреть файл

@ -3315,22 +3315,6 @@ JS_NewFunction(JSContext* cx, JSNative native, unsigned nargs, unsigned flags,
: NewNativeFunction(cx, native, nargs, atom); : NewNativeFunction(cx, native, nargs, atom);
} }
JS_PUBLIC_API(JSFunction*)
JS_NewFunctionById(JSContext* cx, JSNative native, unsigned nargs, unsigned flags,
HandleId id)
{
MOZ_ASSERT(JSID_IS_STRING(id));
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
MOZ_ASSERT(native);
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
RootedAtom name(cx, JSID_TO_ATOM(id));
return (flags & JSFUN_CONSTRUCTOR)
? NewNativeConstructor(cx, native, nargs, name)
: NewNativeFunction(cx, native, nargs, name);
}
JS_PUBLIC_API(JSFunction*) JS_PUBLIC_API(JSFunction*)
JS::GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id, unsigned nargs) JS::GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id, unsigned nargs)
{ {
@ -3352,6 +3336,52 @@ JS::GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id
return &funVal.toObject().as<JSFunction>(); return &funVal.toObject().as<JSFunction>();
} }
JS_PUBLIC_API(JSFunction*)
JS::NewFunctionFromSpec(JSContext* cx, const JSFunctionSpec* fs, HandleId id)
{
// Delay cloning self-hosted functions until they are called. This is
// achieved by passing DefineFunction a nullptr JSNative which produces an
// interpreted JSFunction where !hasScript. Interpreted call paths then
// call InitializeLazyFunctionScript if !hasScript.
if (fs->selfHostedName) {
MOZ_ASSERT(!fs->call.op);
MOZ_ASSERT(!fs->call.info);
JSAtom* shAtom = Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName));
if (!shAtom)
return nullptr;
RootedPropertyName shName(cx, shAtom->asPropertyName());
RootedAtom name(cx, IdToFunctionName(cx, id));
if (!name)
return nullptr;
RootedValue funVal(cx);
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, fs->nargs,
&funVal))
{
return nullptr;
}
return &funVal.toObject().as<JSFunction>();
}
RootedAtom atom(cx, IdToFunctionName(cx, id));
if (!atom)
return nullptr;
JSFunction* fun;
if (!fs->call.op)
fun = NewScriptedFunction(cx, fs->nargs, JSFunction::INTERPRETED_LAZY, atom);
else if (fs->flags & JSFUN_CONSTRUCTOR)
fun = NewNativeConstructor(cx, fs->call.op, fs->nargs, atom);
else
fun = NewNativeFunction(cx, fs->call.op, fs->nargs, atom);
if (!fun)
return nullptr;
if (fs->call.info)
fun->setJitInfo(fs->call.info);
return fun;
}
static bool static bool
CreateNonSyntacticScopeChain(JSContext* cx, AutoObjectVector& scopeChain, CreateNonSyntacticScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
MutableHandleObject dynamicScopeObj, MutableHandleObject dynamicScopeObj,
@ -3576,6 +3606,59 @@ GenericNativeMethodDispatcher(JSContext* cx, unsigned argc, Value* vp)
return fs->call.op(cx, argc, vp); return fs->call.op(cx, argc, vp);
} }
static bool
DefineFunctionFromSpec(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, unsigned flags)
{
GetterOp gop;
SetterOp sop;
if (flags & JSFUN_STUB_GSOPS) {
// JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
// the defined property's attributes.
flags &= ~JSFUN_STUB_GSOPS;
gop = nullptr;
sop = nullptr;
} else {
gop = obj->getClass()->getProperty;
sop = obj->getClass()->setProperty;
MOZ_ASSERT(gop != JS_PropertyStub);
MOZ_ASSERT(sop != JS_StrictPropertyStub);
}
RootedId id(cx);
if (!PropertySpecNameToId(cx, fs->name, &id))
return false;
// Define a generic arity N+1 static method for the arity N prototype
// method if flags contains JSFUN_GENERIC_NATIVE.
if (flags & JSFUN_GENERIC_NATIVE) {
// We require that any consumers using JSFUN_GENERIC_NATIVE stash
// the prototype and constructor in the global slots before invoking
// JS_DefineFunctions on the proto.
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
MOZ_ASSERT(obj == &obj->global().getPrototype(key).toObject());
RootedObject ctor(cx, &obj->global().getConstructor(key).toObject());
flags &= ~JSFUN_GENERIC_NATIVE;
JSFunction* fun = DefineFunction(cx, ctor, id,
GenericNativeMethodDispatcher,
fs->nargs + 1, flags,
gc::AllocKind::FUNCTION_EXTENDED);
if (!fun)
return false;
// As jsapi.h notes, fs must point to storage that lives as long
// as fun->object lives.
fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs)));
}
JSFunction* fun = NewFunctionFromSpec(cx, fs, id);
if (!fun)
return false;
RootedValue funVal(cx, ObjectValue(*fun));
return DefineProperty(cx, obj, id, funVal, gop, sop, flags & ~JSFUN_FLAGS_MASK);
}
JS_PUBLIC_API(bool) JS_PUBLIC_API(bool)
JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
PropertyDefinitionBehavior behavior) PropertyDefinitionBehavior behavior)
@ -3585,11 +3668,7 @@ JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
assertSameCompartment(cx, obj); assertSameCompartment(cx, obj);
RootedId id(cx);
for (; fs->name; fs++) { for (; fs->name; fs++) {
if (!PropertySpecNameToId(cx, fs->name, &id))
return false;
unsigned flags = fs->flags; unsigned flags = fs->flags;
switch (behavior) { switch (behavior) {
case DefineAllProperties: case DefineAllProperties:
@ -3603,67 +3682,9 @@ JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
if (flags & JSPROP_DEFINE_LATE) if (flags & JSPROP_DEFINE_LATE)
continue; continue;
} }
flags &= ~JSPROP_DEFINE_LATE;
/* if (!DefineFunctionFromSpec(cx, obj, fs, flags & ~JSPROP_DEFINE_LATE))
* Define a generic arity N+1 static method for the arity N prototype return false;
* method if flags contains JSFUN_GENERIC_NATIVE.
*/
if (flags & JSFUN_GENERIC_NATIVE) {
// We require that any consumers using JSFUN_GENERIC_NATIVE stash
// the prototype and constructor in the global slots before invoking
// JS_DefineFunctions on the proto.
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
MOZ_ASSERT(obj == &obj->global().getPrototype(key).toObject());
RootedObject ctor(cx, &obj->global().getConstructor(key).toObject());
flags &= ~JSFUN_GENERIC_NATIVE;
JSFunction* fun = DefineFunction(cx, ctor, id,
GenericNativeMethodDispatcher,
fs->nargs + 1, flags,
gc::AllocKind::FUNCTION_EXTENDED);
if (!fun)
return false;
/*
* As jsapi.h notes, fs must point to storage that lives as long
* as fun->object lives.
*/
fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs)));
}
/*
* Delay cloning self-hosted functions until they are called. This is
* achieved by passing DefineFunction a nullptr JSNative which
* produces an interpreted JSFunction where !hasScript. Interpreted
* call paths then call InitializeLazyFunctionScript if !hasScript.
*/
if (fs->selfHostedName) {
MOZ_ASSERT(!fs->call.op);
MOZ_ASSERT(!fs->call.info);
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 (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, fs->nargs,
&funVal))
{
return false;
}
if (!DefineProperty(cx, obj, id, funVal, nullptr, nullptr, flags))
return false;
} else {
JSFunction* fun = DefineFunction(cx, obj, id, fs->call.op, fs->nargs, flags);
if (!fun)
return false;
if (fs->call.info)
fun->setJitInfo(fs->call.info);
}
} }
return true; return true;
} }

Просмотреть файл

@ -3124,20 +3124,23 @@ extern JS_PUBLIC_API(JSFunction*)
JS_NewFunction(JSContext* cx, JSNative call, unsigned nargs, unsigned flags, JS_NewFunction(JSContext* cx, JSNative call, unsigned nargs, unsigned flags,
const char* name); const char* name);
/*
* Create the function with the name given by the id. JSID_IS_STRING(id) must
* be true.
*/
extern JS_PUBLIC_API(JSFunction*)
JS_NewFunctionById(JSContext* cx, JSNative call, unsigned nargs, unsigned flags,
JS::Handle<jsid> id);
namespace JS { namespace JS {
extern JS_PUBLIC_API(JSFunction*) extern JS_PUBLIC_API(JSFunction*)
GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, JS::Handle<jsid> id, GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id,
unsigned nargs); unsigned nargs);
/**
* Create a new function based on the given JSFunctionSpec, *fs.
* id is the result of a successful call to
* `PropertySpecNameToPermanentId(cx, fs->name, &id)`.
*
* Unlike JS_DefineFunctions, this does not treat fs as an array.
* *fs must not be JS_FS_END.
*/
extern JS_PUBLIC_API(JSFunction*)
NewFunctionFromSpec(JSContext* cx, const JSFunctionSpec* fs, HandleId id);
} /* namespace JS */ } /* namespace JS */
extern JS_PUBLIC_API(JSObject*) extern JS_PUBLIC_API(JSObject*)

Просмотреть файл

@ -2223,8 +2223,7 @@ js::IdToFunctionName(JSContext* cx, HandleId id)
JSFunction* JSFunction*
js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native, js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native,
unsigned nargs, unsigned flags, AllocKind allocKind /* = AllocKind::FUNCTION */, unsigned nargs, unsigned flags, AllocKind allocKind /* = AllocKind::FUNCTION */)
NewObjectKind newKind /* = GenericObject */)
{ {
GetterOp gop; GetterOp gop;
SetterOp sop; SetterOp sop;
@ -2253,11 +2252,11 @@ js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native,
if (!native) if (!native)
fun = NewScriptedFunction(cx, nargs, fun = NewScriptedFunction(cx, nargs,
JSFunction::INTERPRETED_LAZY, atom, JSFunction::INTERPRETED_LAZY, atom,
allocKind, newKind, obj); allocKind, GenericObject, obj);
else if (flags & JSFUN_CONSTRUCTOR) else if (flags & JSFUN_CONSTRUCTOR)
fun = NewNativeConstructor(cx, native, nargs, atom, allocKind, newKind); fun = NewNativeConstructor(cx, native, nargs, atom, allocKind);
else else
fun = NewNativeFunction(cx, native, nargs, atom, allocKind, newKind); fun = NewNativeFunction(cx, native, nargs, atom, allocKind);
if (!fun) if (!fun)
return nullptr; return nullptr;

Просмотреть файл

@ -636,8 +636,7 @@ IdToFunctionName(JSContext* cx, HandleId id);
extern JSFunction* extern JSFunction*
DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native, DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native,
unsigned nargs, unsigned flags, unsigned nargs, unsigned flags,
gc::AllocKind allocKind = gc::AllocKind::FUNCTION, gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
NewObjectKind newKind = GenericObject);
bool bool
FunctionHasResolveHook(const JSAtomState& atomState, jsid id); FunctionHasResolveHook(const JSAtomState& atomState, jsid id);

Просмотреть файл

@ -518,12 +518,7 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper,
} }
if (fsMatch) { if (fsMatch) {
// Generate an Xrayed version of the method. // Generate an Xrayed version of the method.
RootedFunction fun(cx); RootedFunction fun(cx, JS::NewFunctionFromSpec(cx, fsMatch, id));
if (fsMatch->selfHostedName) {
fun = JS::GetSelfHostedFunction(cx, fsMatch->selfHostedName, id, fsMatch->nargs);
} else {
fun = JS_NewFunctionById(cx, fsMatch->call.op, fsMatch->nargs, 0, id);
}
if (!fun) if (!fun)
return false; return false;