diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index aa2b0c562f37..28890f51e433 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3315,22 +3315,6 @@ JS_NewFunction(JSContext* cx, JSNative native, unsigned nargs, unsigned flags, : 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::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(); } +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(); + } + + 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 CreateNonSyntacticScopeChain(JSContext* cx, AutoObjectVector& scopeChain, MutableHandleObject dynamicScopeObj, @@ -3576,6 +3606,59 @@ GenericNativeMethodDispatcher(JSContext* cx, unsigned argc, Value* 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(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_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, PropertyDefinitionBehavior behavior) @@ -3585,11 +3668,7 @@ JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - RootedId id(cx); for (; fs->name; fs++) { - if (!PropertySpecNameToId(cx, fs->name, &id)) - return false; - unsigned flags = fs->flags; switch (behavior) { case DefineAllProperties: @@ -3603,67 +3682,9 @@ JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, if (flags & JSPROP_DEFINE_LATE) continue; } - flags &= ~JSPROP_DEFINE_LATE; - /* - * 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(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); - } + if (!DefineFunctionFromSpec(cx, obj, fs, flags & ~JSPROP_DEFINE_LATE)) + return false; } return true; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 6ac756166442..04f073181fdb 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3124,20 +3124,23 @@ extern JS_PUBLIC_API(JSFunction*) JS_NewFunction(JSContext* cx, JSNative call, unsigned nargs, unsigned flags, 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 id); - namespace JS { extern JS_PUBLIC_API(JSFunction*) -GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, JS::Handle id, +GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id, 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 */ extern JS_PUBLIC_API(JSObject*) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 8bcc000f89e0..ec2563f8d71d 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -2223,8 +2223,7 @@ js::IdToFunctionName(JSContext* cx, HandleId id) JSFunction* js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native, - unsigned nargs, unsigned flags, AllocKind allocKind /* = AllocKind::FUNCTION */, - NewObjectKind newKind /* = GenericObject */) + unsigned nargs, unsigned flags, AllocKind allocKind /* = AllocKind::FUNCTION */) { GetterOp gop; SetterOp sop; @@ -2253,11 +2252,11 @@ js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native, if (!native) fun = NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY, atom, - allocKind, newKind, obj); + allocKind, GenericObject, obj); else if (flags & JSFUN_CONSTRUCTOR) - fun = NewNativeConstructor(cx, native, nargs, atom, allocKind, newKind); + fun = NewNativeConstructor(cx, native, nargs, atom, allocKind); else - fun = NewNativeFunction(cx, native, nargs, atom, allocKind, newKind); + fun = NewNativeFunction(cx, native, nargs, atom, allocKind); if (!fun) return nullptr; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 90c91a0f7198..cde4e2ee88c9 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -636,8 +636,7 @@ IdToFunctionName(JSContext* cx, HandleId id); extern JSFunction* DefineFunction(JSContext* cx, HandleObject obj, HandleId id, JSNative native, unsigned nargs, unsigned flags, - gc::AllocKind allocKind = gc::AllocKind::FUNCTION, - NewObjectKind newKind = GenericObject); + gc::AllocKind allocKind = gc::AllocKind::FUNCTION); bool FunctionHasResolveHook(const JSAtomState& atomState, jsid id); diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index eae06fb7ca98..95698e67af81 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -518,12 +518,7 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, } if (fsMatch) { // Generate an Xrayed version of the method. - RootedFunction fun(cx); - if (fsMatch->selfHostedName) { - fun = JS::GetSelfHostedFunction(cx, fsMatch->selfHostedName, id, fsMatch->nargs); - } else { - fun = JS_NewFunctionById(cx, fsMatch->call.op, fsMatch->nargs, 0, id); - } + RootedFunction fun(cx, JS::NewFunctionFromSpec(cx, fsMatch, id)); if (!fun) return false;