diff options
-rw-r--r-- | js/src/builtin/SelfHostingDefines.h | 5 | ||||
-rw-r--r-- | js/src/frontend/Parser.cpp | 10 | ||||
-rw-r--r-- | js/src/jsapi.cpp | 21 | ||||
-rw-r--r-- | js/src/jsfun.cpp | 106 | ||||
-rw-r--r-- | js/src/jsfun.h | 6 | ||||
-rw-r--r-- | js/src/vm/Interpreter.cpp | 8 | ||||
-rw-r--r-- | js/src/vm/SelfHosting.cpp | 89 | ||||
-rw-r--r-- | js/src/vm/SelfHosting.h | 13 | ||||
-rw-r--r-- | js/src/wasm/AsmJS.cpp | 4 | ||||
-rw-r--r-- | js/src/wasm/AsmJS.h | 3 |
10 files changed, 160 insertions, 105 deletions
diff --git a/js/src/builtin/SelfHostingDefines.h b/js/src/builtin/SelfHostingDefines.h index 987351815c..9a93a2c795 100644 --- a/js/src/builtin/SelfHostingDefines.h +++ b/js/src/builtin/SelfHostingDefines.h @@ -52,11 +52,6 @@ // stored. #define LAZY_FUNCTION_NAME_SLOT 0 -// The extended slot which contains a boolean value that indicates whether -// that the canonical name of the self-hosted builtins is set in self-hosted -// global. This slot is used only in debug build. -#define HAS_SELFHOSTED_CANONICAL_NAME_SLOT 0 - // Stores the length for bound functions, so the .length property doesn't need // to be resolved eagerly. #define BOUND_FUN_LENGTH_SLOT 1 diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index d617941503..a1b669bf91 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2807,9 +2807,6 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind, gc::AllocKind allocKind = gc::AllocKind::FUNCTION; JSFunction::Flags flags; -#ifdef DEBUG - bool isGlobalSelfHostedBuiltin = false; -#endif switch (kind) { case FunctionSyntaxKind::Expression: flags = (generatorKind == NotGenerator && asyncKind == SyncFunction @@ -2846,12 +2843,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind, break; default: MOZ_ASSERT(kind == FunctionSyntaxKind::Statement); -#ifdef DEBUG if (options().selfHostingMode && !pc->isFunctionBox()) { - isGlobalSelfHostedBuiltin = true; allocKind = gc::AllocKind::FUNCTION_EXTENDED; } -#endif flags = (generatorKind == NotGenerator && asyncKind == SyncFunction ? JSFunction::INTERPRETED_NORMAL : JSFunction::INTERPRETED_GENERATOR_OR_ASYNC); @@ -2867,10 +2861,6 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind, return nullptr; if (options().selfHostingMode) { fun->setIsSelfHostedBuiltin(); -#ifdef DEBUG - if (isGlobalSelfHostedBuiltin) - fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT, BooleanValue(false)); -#endif } return fun; } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 9e5853b454..0e29f02176 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3530,9 +3530,6 @@ CreateNonSyntacticEnvironmentChain(JSContext* cx, AutoObjectVector& envChain, static bool IsFunctionCloneable(HandleFunction fun) { - if (!fun->isInterpreted()) - return true; - // If a function was compiled with non-global syntactic environments on // the environment chain, we could have baked in EnvironmentCoordinates // into the script. We cannot clone it without breaking the compiler's @@ -3570,27 +3567,17 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject env, Handle return nullptr; } - if (!IsFunctionCloneable(fun)) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_CLONE_FUNOBJ_SCOPE); - return nullptr; - } - - if (fun->isBoundFunction()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT); - return nullptr; - } - - if (IsAsmJSModule(fun)) { + if (fun->isNative()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT); return nullptr; } - if (IsWrappedAsyncFunction(fun)) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT); + if (!IsFunctionCloneable(fun)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_CLONE_FUNOBJ_SCOPE); return nullptr; } - if (IsWrappedAsyncGenerator(fun)) { + if (fun->isBoundFunction()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT); return nullptr; } diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 67df78c2f1..5255aebbfc 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -50,6 +50,7 @@ #include "vm/StringBuffer.h" #include "vm/WrapperObject.h" #include "vm/Xdr.h" +#include "wasm/AsmJS.h" #include "jsscriptinlines.h" @@ -1250,7 +1251,7 @@ JSFunction::infallibleIsDefaultClassConstructor(JSContext* cx) const bool isDefault = false; if (isInterpretedLazy()) { - JSAtom* name = &getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).toString()->asAtom(); + JSAtom* name = GetSelfHostedFunctionName(const_cast<JSFunction*>(this)); isDefault = name == cx->names().DefaultDerivedClassConstructor || name == cx->names().DefaultBaseClassConstructor; } else { @@ -1270,7 +1271,7 @@ JSFunction::isDerivedClassConstructor() // There is only one plausible lazy self-hosted derived // constructor. if (isSelfHostedBuiltin()) { - JSAtom* name = &getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).toString()->asAtom(); + JSAtom* name = GetSelfHostedFunctionName(this); // This function is called from places without access to a // JSContext. Trace some plumbing to get what we want. @@ -1529,7 +1530,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti /* Lazily cloned self-hosted script. */ MOZ_ASSERT(fun->isSelfHostedBuiltin()); - RootedAtom funAtom(cx, &fun->getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).toString()->asAtom()); + RootedAtom funAtom(cx, GetSelfHostedFunctionName(fun)); if (!funAtom) return false; Rooted<PropertyName*> funName(cx, funAtom->asPropertyName()); @@ -1568,9 +1569,7 @@ JSFunction::maybeRelazify(JSRuntime* rt) return; // To delazify self-hosted builtins we need the name of the function - // to clone. This name is stored in the first extended slot. Since - // that slot is sometimes also used for other purposes, make sure it - // contains a string. + // to clone. This name is stored in the first extended slot. if (isSelfHostedBuiltin() && (!isExtended() || !getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).isString())) { @@ -1588,7 +1587,7 @@ JSFunction::maybeRelazify(JSRuntime* rt) } else { MOZ_ASSERT(isSelfHostedBuiltin()); MOZ_ASSERT(isExtended()); - MOZ_ASSERT(getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).toString()->isAtom()); + MOZ_ASSERT(GetSelfHostedFunctionName(this)); } comp->scheduleDelazificationForDebugger(); @@ -2026,6 +2025,8 @@ bool js::CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun, HandleObject newParent) { + MOZ_ASSERT(fun->isInterpreted()); + if (compartment != fun->compartment() || fun->isSingleton() || ObjectGroup::useSingletonForClone(fun)) @@ -2044,12 +2045,11 @@ js::CanReuseScriptForClone(JSCompartment* compartment, HandleFunction fun, if (IsSyntacticEnvironment(newParent)) return true; - // We need to clone the script if we're interpreted and not already marked - // as having a non-syntactic scope. If we're lazy, go ahead and clone the - // script; see the big comment at the end of CopyScriptInternal for the - // explanation of what's going on there. - return !fun->isInterpreted() || - (fun->hasScript() && fun->nonLazyScript()->hasNonSyntacticScope()); + // We need to clone the script if we're not already marked as having a + // non-syntactic scope. If we're lazy, go ahead and clone the script; see + // the big comment at the end of CopyScriptInternal for the explanation of + // what's going on there. + return fun->hasScript() && fun->nonLazyScript()->hasNonSyntacticScope(); } static inline JSFunction* @@ -2096,6 +2096,7 @@ js::CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject enc HandleObject proto /* = nullptr */) { MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv)); + MOZ_ASSERT(fun->isInterpreted()); MOZ_ASSERT(!fun->isBoundFunction()); MOZ_ASSERT(CanReuseScriptForClone(cx->compartment(), fun, enclosingEnv)); @@ -2106,13 +2107,12 @@ js::CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject enc if (fun->hasScript()) { clone->initScript(fun->nonLazyScript()); clone->initEnvironment(enclosingEnv); - } else if (fun->isInterpretedLazy()) { + } else { + MOZ_ASSERT(fun->isInterpretedLazy()); MOZ_ASSERT(fun->compartment() == clone->compartment()); LazyScript* lazy = fun->lazyScriptOrNull(); clone->initLazyScript(lazy); clone->initEnvironment(enclosingEnv); - } else { - clone->initNative(fun->native(), fun->jitInfo()); } /* @@ -2130,25 +2130,19 @@ js::CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject enclo HandleObject proto /* = nullptr */) { MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv)); + MOZ_ASSERT(fun->isInterpreted()); MOZ_ASSERT(!fun->isBoundFunction()); - JSScript::AutoDelazify funScript(cx); - if (fun->isInterpreted()) { - funScript = fun; - if (!funScript) - return nullptr; - } + JSScript::AutoDelazify funScript(cx, fun); + if (!funScript) + return nullptr; RootedFunction clone(cx, NewFunctionClone(cx, fun, SingletonObject, allocKind, proto)); if (!clone) return nullptr; - if (fun->hasScript()) { - clone->initScript(nullptr); - clone->initEnvironment(enclosingEnv); - } else { - clone->initNative(fun->native(), fun->jitInfo()); - } + clone->initScript(nullptr); + clone->initEnvironment(enclosingEnv); /* * Across compartments or if we have to introduce a non-syntactic scope we @@ -2165,18 +2159,54 @@ js::CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject enclo newScope->hasOnChain(ScopeKind::NonSyntactic)); #endif - if (clone->isInterpreted()) { - RootedScript script(cx, fun->nonLazyScript()); - MOZ_ASSERT(script->compartment() == fun->compartment()); - MOZ_ASSERT(cx->compartment() == clone->compartment(), - "Otherwise we could relazify clone below!"); + RootedScript script(cx, fun->nonLazyScript()); + MOZ_ASSERT(script->compartment() == fun->compartment()); + MOZ_ASSERT(cx->compartment() == clone->compartment(), + "Otherwise we could relazify clone below!"); - RootedScript clonedScript(cx, CloneScriptIntoFunction(cx, newScope, clone, script)); - if (!clonedScript) - return nullptr; - Debugger::onNewScript(cx, clonedScript); - } + RootedScript clonedScript(cx, CloneScriptIntoFunction(cx, newScope, clone, script)); + if (!clonedScript) + return nullptr; + Debugger::onNewScript(cx, clonedScript); + + return clone; +} + +JSFunction* +js::CloneAsmJSModuleFunction(JSContext* cx, HandleFunction fun) +{ + MOZ_ASSERT(fun->isNative()); + MOZ_ASSERT(IsAsmJSModule(fun)); + MOZ_ASSERT(fun->isExtended()); + MOZ_ASSERT(cx->compartment() == fun->compartment()); + + JSFunction* clone = NewFunctionClone(cx, fun, GenericObject, AllocKind::FUNCTION_EXTENDED, + /* proto = */ nullptr); + if (!clone) + return nullptr; + + MOZ_ASSERT(fun->native() == InstantiateAsmJS); + MOZ_ASSERT(!fun->jitInfo()); + clone->initNative(InstantiateAsmJS, nullptr); + + clone->setGroup(fun->group()); + return clone; +} + +JSFunction* +js::CloneSelfHostingIntrinsic(JSContext* cx, HandleFunction fun) +{ + MOZ_ASSERT(fun->isNative()); + MOZ_ASSERT(fun->compartment()->isSelfHosting); + MOZ_ASSERT(!fun->isExtended()); + MOZ_ASSERT(cx->compartment() != fun->compartment()); + + JSFunction* clone = NewFunctionClone(cx, fun, SingletonObject, AllocKind::FUNCTION, + /* proto = */ nullptr); + if (!clone) + return nullptr; + clone->initNative(fun->native(), fun->jitInfo()); return clone; } diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 1833aaeea5..49aac71654 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -824,6 +824,12 @@ CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent, gc::AllocKind kind = gc::AllocKind::FUNCTION, HandleObject proto = nullptr); +extern JSFunction* +CloneAsmJSModuleFunction(JSContext* cx, HandleFunction fun); + +extern JSFunction* +CloneSelfHostingIntrinsic(JSContext* cx, HandleFunction fun); + } // namespace js inline js::FunctionExtended* diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index d7c1b8e84a..3515a9336b 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -4302,7 +4302,13 @@ js::Lambda(JSContext* cx, HandleFunction fun, HandleObject parent) { MOZ_ASSERT(!fun->isArrow()); - RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent)); + JSFunction* clone; + if (fun->isNative()) { + MOZ_ASSERT(IsAsmJSModule(fun)); + clone = CloneAsmJSModuleFunction(cx, fun); + } else { + clone = CloneFunctionObjectIfNotSingleton(cx, fun, parent); + } if (!clone) return nullptr; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 357e151bde..de497d02e1 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -903,6 +903,22 @@ intrinsic_NewRegExpStringIterator(JSContext* cx, unsigned argc, Value* vp) return true; } +JSAtom* +js::GetSelfHostedFunctionName(JSFunction* fun) +{ + Value name = fun->getExtendedSlot(LAZY_FUNCTION_NAME_SLOT); + if (!name.isString()) { + return nullptr; + } + return &name.toString()->asAtom(); +} + +static void +SetSelfHostedFunctionName(JSFunction* fun, JSAtom* name) +{ + fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(name)); +} + static bool intrinsic_SetCanonicalName(JSContext* cx, unsigned argc, Value* vp) { @@ -915,10 +931,18 @@ intrinsic_SetCanonicalName(JSContext* cx, unsigned argc, Value* vp) if (!atom) return false; + // _SetCanonicalName can only be called on top-level function declarations. + MOZ_ASSERT(fun->kind() == JSFunction::NormalFunction); + MOZ_ASSERT(!fun->isLambda()); + + // It's an error to call _SetCanonicalName multiple times. + MOZ_ASSERT(!GetSelfHostedFunctionName(fun)); + + // Set the lazy function name so we can later retrieve the script from the + // self-hosting global. + SetSelfHostedFunctionName(fun, fun->explicitName()); fun->setAtom(atom); -#ifdef DEBUG - fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT, BooleanValue(true)); -#endif + args.rval().setUndefined(); return true; } @@ -2909,23 +2933,33 @@ CloneObject(JSContext* cx, HandleNativeObject selfHostedObject) RootedObject clone(cx); if (selfHostedObject->is<JSFunction>()) { RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>()); - bool hasName = selfHostedFunction->explicitName() != nullptr; - - // Arrow functions use the first extended slot for their lexical |this| value. - MOZ_ASSERT(!selfHostedFunction->isArrow()); - js::gc::AllocKind kind = hasName - ? gc::AllocKind::FUNCTION_EXTENDED - : selfHostedFunction->getAllocKind(); - MOZ_ASSERT(!CanReuseScriptForClone(cx->compartment(), selfHostedFunction, cx->global())); - Rooted<LexicalEnvironmentObject*> globalLexical(cx, &cx->global()->lexicalEnvironment()); - RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope()); - clone = CloneFunctionAndScript(cx, selfHostedFunction, globalLexical, emptyGlobalScope, - kind); - // To be able to re-lazify the cloned function, its name in the - // self-hosting compartment has to be stored on the clone. - if (clone && hasName) { - clone->as<JSFunction>().setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, - StringValue(selfHostedFunction->explicitName())); + if (selfHostedFunction->isInterpreted()) { + // Arrow functions use the first extended slot for their lexical |this| value. + // And methods use the first extended slot for their home-object. + // We only expect to see normal functions here. + MOZ_ASSERT(selfHostedFunction->kind() == JSFunction::NormalFunction); + js::gc::AllocKind kind = selfHostedFunction->getAllocKind(); + + Handle<GlobalObject*> global = cx->global(); + Rooted<LexicalEnvironmentObject*> globalLexical(cx, &global->lexicalEnvironment()); + RootedScope emptyGlobalScope(cx, &global->emptyGlobalScope()); + MOZ_ASSERT(!CanReuseScriptForClone(cx->compartment(), selfHostedFunction, global)); + clone = CloneFunctionAndScript(cx, selfHostedFunction, globalLexical, emptyGlobalScope, + kind); + // To be able to re-lazify the cloned function, its name in the + // self-hosting compartment has to be stored on the clone. Re-lazification + // is only possible if this isn't a function expression. + if (clone && !selfHostedFunction->isLambda()) { + // If |_SetCanonicalName| was called on the function, the self-hosted + // name is stored in the extended slot. + JSAtom* name = GetSelfHostedFunctionName(selfHostedFunction); + if (!name) { + name = selfHostedFunction->explicitName(); + } + SetSelfHostedFunctionName(&clone->as<JSFunction>(), name); + } + } else { + clone = CloneSelfHostingIntrinsic(cx, selfHostedFunction); } } else if (selfHostedObject->is<RegExpObject>()) { RegExpObject& reobj = selfHostedObject->as<RegExpObject>(); @@ -3010,7 +3044,7 @@ JSRuntime::createLazySelfHostedFunctionClone(JSContext* cx, HandlePropertyName s if (!selfHostedFun->isClassConstructor() && !selfHostedFun->hasGuessedAtom() && selfHostedFun->explicitName() != selfHostedName) { - MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean()); + MOZ_ASSERT(GetSelfHostedFunctionName(selfHostedFun) == selfHostedName); funName = selfHostedFun->explicitName(); } @@ -3019,7 +3053,7 @@ JSRuntime::createLazySelfHostedFunctionClone(JSContext* cx, HandlePropertyName s if (!fun) return false; fun->setIsSelfHostedBuiltin(); - fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(selfHostedName)); + SetSelfHostedFunctionName(fun, selfHostedName); return true; } @@ -3105,7 +3139,7 @@ JSRuntime::assertSelfHostedFunctionHasCanonicalName(JSContext* cx, HandlePropert #ifdef DEBUG JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, name); MOZ_ASSERT(selfHostedFun); - MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean()); + MOZ_ASSERT(GetSelfHostedFunctionName(selfHostedFun) == name); #endif } @@ -3127,15 +3161,6 @@ js::IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name) return fun->isSelfHostedBuiltin() && GetSelfHostedFunctionName(fun) == name; } -JSAtom* -js::GetSelfHostedFunctionName(JSFunction* fun) -{ - Value name = fun->getExtendedSlot(LAZY_FUNCTION_NAME_SLOT); - if (!name.isString()) - return nullptr; - return &name.toString()->asAtom(); -} - static_assert(JSString::MAX_LENGTH <= INT32_MAX, "StringIteratorNext in builtin/String.js assumes the stored index " "into the string is an Int32Value"); diff --git a/js/src/vm/SelfHosting.h b/js/src/vm/SelfHosting.h index 6b1a03e851..04962f4445 100644 --- a/js/src/vm/SelfHosting.h +++ b/js/src/vm/SelfHosting.h @@ -22,6 +22,19 @@ namespace js { bool IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name); +/* + * Returns the name of the function's binding in the self-hosted global. + * + * This returns a non-null value only when: + * * This is a top level function declaration in the self-hosted global. + * * And either: + * * This function is not cloned and `_SetCanonicalName` has been called to + * set a different function name. + * * This function is cloned. + * + * For functions not cloned and not `_SetCanonicalName`ed, use + * `fun->explicitName()` instead. + */ JSAtom* GetSelfHostedFunctionName(JSFunction* fun); diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 4e00a25206..a91b0e804d 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -8101,8 +8101,8 @@ AsmJSModuleFunctionToModule(JSFunction* fun) } // Implements the semantics of an asm.js module function that has been successfully validated. -static bool -InstantiateAsmJS(JSContext* cx, unsigned argc, JS::Value* vp) +bool +js::InstantiateAsmJS(JSContext* cx, unsigned argc, JS::Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); diff --git a/js/src/wasm/AsmJS.h b/js/src/wasm/AsmJS.h index a38b204a8b..296617c79b 100644 --- a/js/src/wasm/AsmJS.h +++ b/js/src/wasm/AsmJS.h @@ -56,6 +56,9 @@ IsAsmJSFunction(JSFunction* fun); extern bool IsAsmJSStrictModeModuleOrFunction(JSFunction* fun); +extern bool +InstantiateAsmJS(JSContext* cx, unsigned argc, JS::Value* vp); + // asm.js testing natives: extern bool |