From c1f84d62850a5e83ec9728f8dfda051443387f48 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Sat, 29 Sep 2018 21:32:12 -0700 Subject: [PATCH] #392: prerequisite SetCanonicalName M1235656 M1236638 --- js/src/builtin/Array.js | 1 + js/src/builtin/Generator.js | 1 + js/src/builtin/Intl.js | 30 +++++----- js/src/builtin/Map.js | 3 +- js/src/builtin/RegExp.js | 2 + js/src/builtin/SelfHostingDefines.h | 5 ++ js/src/builtin/Set.js | 1 + js/src/builtin/String.js | 6 +- js/src/builtin/TypedArray.js | 1 + js/src/builtin/Utilities.js | 8 +-- js/src/frontend/Parser.cpp | 18 +++++- js/src/jsfun.h | 2 + js/src/vm/GlobalObject.cpp | 37 +++++++++--- js/src/vm/Runtime.h | 8 +++ js/src/vm/SelfHosting.cpp | 91 ++++++++++++++++++++++++++--- 15 files changed, 172 insertions(+), 42 deletions(-) diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 338eb7707..14eaa0980 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -732,6 +732,7 @@ function ArrayValuesAt(n) { function ArrayValues() { return CreateArrayIterator(this, ITEM_KIND_VALUE); } +_SetCanonicalName(ArrayValues, "values"); function ArrayEntries() { return CreateArrayIterator(this, ITEM_KIND_KEY_AND_VALUE); diff --git a/js/src/builtin/Generator.js b/js/src/builtin/Generator.js index b3758c609..bd1549660 100644 --- a/js/src/builtin/Generator.js +++ b/js/src/builtin/Generator.js @@ -88,6 +88,7 @@ function LegacyGeneratorNext(val) { throw e; } } +_SetCanonicalName(LegacyGeneratorNext, "next"); function LegacyGeneratorThrow(val) { if (!IsObject(this) || !IsLegacyGeneratorObject(this)) diff --git a/js/src/builtin/Intl.js b/js/src/builtin/Intl.js index d69fa4599..9f9190625 100644 --- a/js/src/builtin/Intl.js +++ b/js/src/builtin/Intl.js @@ -100,8 +100,8 @@ function removeUnicodeExtensions(locale) { if (pos < 0) pos = locale.length; - var left = callFunction(std_String_substring, locale, 0, pos); - var right = callFunction(std_String_substring, locale, pos); + var left = callFunction(String_substring, locale, 0, pos); + var right = callFunction(String_substring, locale, pos); var extensions; var unicodeLocaleExtensionSequenceRE = getUnicodeLocaleExtensionSequenceRE(); @@ -332,7 +332,7 @@ function IsStructurallyValidLanguageTag(locale) { return true; var pos = callFunction(std_String_indexOf, locale, "-x-"); if (pos !== -1) - locale = callFunction(std_String_substring, locale, 0, pos); + locale = callFunction(String_substring, locale, 0, pos); // Check for duplicate variant or singleton subtags. var duplicateVariantRE = getDuplicateVariantRE(); @@ -401,7 +401,7 @@ function CanonicalizeLanguageTag(locale) { // 4-character subtags are script codes; their first character // needs to be capitalized. "hans" -> "Hans" subtag = callFunction(std_String_toUpperCase, subtag[0]) + - callFunction(std_String_substring, subtag, 1); + callFunction(String_substring, subtag, 1); } else if (i !== 0 && subtag.length === 2) { // 2-character subtags that are not in initial position are region // codes; they need to be upper case. "bu" -> "BU" @@ -678,7 +678,7 @@ function CanonicalizeLocaleList(locales) { if (!IsStructurallyValidLanguageTag(tag)) ThrowRangeError(JSMSG_INVALID_LANGUAGE_TAG, tag); tag = CanonicalizeLanguageTag(tag); - if (callFunction(std_Array_indexOf, seen, tag) === -1) + if (callFunction(ArrayIndexOf, seen, tag) === -1) callFunction(std_Array_push, seen, tag); } k++; @@ -726,7 +726,7 @@ function BestAvailableLocaleHelper(availableLocales, locale, considerDefaultLoca if (pos >= 2 && candidate[pos - 2] === "-") pos -= 2; - candidate = callFunction(std_String_substring, candidate, 0, pos); + candidate = callFunction(String_substring, candidate, 0, pos); } } @@ -879,7 +879,7 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte // Step 11.g. if (extensionSubtags !== undefined) { // Step 11.g.i. - var keyPos = callFunction(std_Array_indexOf, extensionSubtags, key); + var keyPos = callFunction(ArrayIndexOf, extensionSubtags, key); // Step 11.g.ii. if (keyPos !== -1) { @@ -891,7 +891,7 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte var requestedValue = extensionSubtags[keyPos + 1]; // Step 11.g.ii.1.b. - valuePos = callFunction(std_Array_indexOf, keyLocaleData, requestedValue); + valuePos = callFunction(ArrayIndexOf, keyLocaleData, requestedValue); // Step 11.g.ii.1.c. if (valuePos !== -1) { @@ -905,7 +905,7 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte // and true is an allowed value, it's used. // Step 11.g.ii.2.a. - valuePos = callFunction(std_Array_indexOf, keyLocaleData, "true"); + valuePos = callFunction(ArrayIndexOf, keyLocaleData, "true"); // Step 11.g.ii.2.b. if (valuePos !== -1) @@ -921,7 +921,7 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte // Step 11.h, 11.h.ii. if (optionsValue !== undefined && - callFunction(std_Array_indexOf, keyLocaleData, optionsValue) !== -1) + callFunction(ArrayIndexOf, keyLocaleData, optionsValue) !== -1) { // Step 11.h.ii.1. if (optionsValue !== value) { @@ -938,8 +938,8 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte // Step 12. if (supportedExtension.length > 2) { - var preExtension = callFunction(std_String_substring, foundLocale, 0, extensionIndex); - var postExtension = callFunction(std_String_substring, foundLocale, extensionIndex); + var preExtension = callFunction(String_substring, foundLocale, 0, extensionIndex); + var postExtension = callFunction(String_substring, foundLocale, extensionIndex); foundLocale = preExtension + supportedExtension + postExtension; } @@ -1060,7 +1060,7 @@ function GetOption(options, property, type, values, fallback) { assert(false, "GetOption"); // Step 2.d. - if (values !== undefined && callFunction(std_Array_indexOf, values, value) === -1) + if (values !== undefined && callFunction(ArrayIndexOf, values, value) === -1) ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, property, value); // Step 2.e. @@ -2612,8 +2612,8 @@ function BasicFormatMatcher(options, formats) { score -= removalPenalty; } else { // Step 11.c.vi. - var optionsPropIndex = callFunction(std_Array_indexOf, values, optionsProp); - var formatPropIndex = callFunction(std_Array_indexOf, values, formatProp); + var optionsPropIndex = callFunction(ArrayIndexOf, values, optionsProp); + var formatPropIndex = callFunction(ArrayIndexOf, values, formatProp); var delta = std_Math_max(std_Math_min(formatPropIndex - optionsPropIndex, 2), -2); if (delta === 2) score -= longMorePenalty; diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js index 5442123cd..ec2d198b3 100644 --- a/js/src/builtin/Map.js +++ b/js/src/builtin/Map.js @@ -25,7 +25,7 @@ function MapForEach(callbackfn, thisArg = undefined) { /* Step 6-8. */ var entries = callFunction(std_Map_iterator, M); while (true) { - var result = callFunction(std_Map_iterator_next, entries); + var result = callFunction(MapIteratorNext, entries); if (result.done) break; var entry = result.value; @@ -88,3 +88,4 @@ function MapSpecies() { // Step 1. return this; } +_SetCanonicalName(MapSpecies, "get [Symbol.species]"); diff --git a/js/src/builtin/RegExp.js b/js/src/builtin/RegExp.js index 7b002dd47..25cc7cd34 100644 --- a/js/src/builtin/RegExp.js +++ b/js/src/builtin/RegExp.js @@ -35,6 +35,7 @@ function RegExpFlagsGetter() { // Step 19. return result; } +_SetCanonicalName(RegExpFlagsGetter, "get flags"); // ES6 draft rc1 21.2.5.14. function RegExpToString() @@ -53,3 +54,4 @@ function RegExpToString() // Step 7. return '/' + pattern + '/' + flags; } +_SetCanonicalName(RegExpToString, "toString"); diff --git a/js/src/builtin/SelfHostingDefines.h b/js/src/builtin/SelfHostingDefines.h index 8652ba048..d3c4afb89 100644 --- a/js/src/builtin/SelfHostingDefines.h +++ b/js/src/builtin/SelfHostingDefines.h @@ -34,6 +34,11 @@ // 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 private WeakMap slot used for WeakSets #define WEAKSET_MAP_SLOT 0 diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js index 64c0355ed..7ed34712b 100644 --- a/js/src/builtin/Set.js +++ b/js/src/builtin/Set.js @@ -38,3 +38,4 @@ function SetSpecies() { // Step 1. return this; } +_SetCanonicalName(SetSpecies, "get [Symbol.species]"); diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index c9a56ab3a..f0cee65bd 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -277,7 +277,7 @@ function StringIteratorNext() { } UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount); - result.value = callFunction(std_String_substring, S, index, index + charCount); + result.value = callFunction(String_substring, S, index, index + charCount); return result; } @@ -482,14 +482,14 @@ function EscapeAttributeValue(v) { var chunkStart = 0; for (var i = 0; i < inputLen; i++) { if (inputStr[i] === '"') { - outputStr += callFunction(std_String_substring, inputStr, chunkStart, i) + '"'; + outputStr += callFunction(String_substring, inputStr, chunkStart, i) + '"'; chunkStart = i + 1; } } if (chunkStart === 0) return inputStr; if (chunkStart < inputLen) - outputStr += callFunction(std_String_substring, inputStr, chunkStart); + outputStr += callFunction(String_substring, inputStr, chunkStart); return outputStr; } diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js index f872bd1f1..e3e76d51d 100644 --- a/js/src/builtin/TypedArray.js +++ b/js/src/builtin/TypedArray.js @@ -964,6 +964,7 @@ function TypedArrayValues() { // Step 7. return CreateArrayIterator(O, ITEM_KIND_VALUE); } +_SetCanonicalName(TypedArrayValues, "values"); // Proposed for ES7: // https://github.com/tc39/Array.prototype.includes/blob/7c023c19a0/spec.md diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index 8e232e8a0..b7aa56dd6 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -36,15 +36,13 @@ // code are installed via the std_functions JSFunctionSpec[] in // SelfHosting.cpp. // -// The few items below here are either self-hosted or installing them under a -// std_Foo name would require ugly contortions, so they just get aliased here. -var std_Array_indexOf = ArrayIndexOf; -var std_String_substring = String_substring; +// Do not create an alias to a self-hosted builtin, otherwise it will be cloned +// twice. +// // WeakMap is a bare constructor without properties or methods. var std_WeakMap = WeakMap; // StopIteration is a bare constructor without properties or methods. var std_StopIteration = StopIteration; -var std_Map_iterator_next = MapIteratorNext; /********** List specification type **********/ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 6e5fd4a77..5830e7d90 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -30,6 +30,7 @@ #include "asmjs/AsmJSValidate.h" #include "builtin/ModuleObject.h" +#include "builtin/SelfHostingDefines.h" #include "frontend/BytecodeCompiler.h" #include "frontend/FoldConstants.h" #include "frontend/ParseMaps.h" @@ -1619,6 +1620,9 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, gc::AllocKind allocKind = gc::AllocKind::FUNCTION; JSFunction::Flags flags; +#ifdef DEBUG + bool isGlobalSelfHostedBuiltin = false; +#endif switch (kind) { case Expression: flags = (generatorKind == NotGenerator @@ -1652,6 +1656,13 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, allocKind = gc::AllocKind::FUNCTION_EXTENDED; break; default: + MOZ_ASSERT(kind == Statement); +#ifdef DEBUG + if (options().selfHostingMode && !pc->sc->isFunctionBox()) { + isGlobalSelfHostedBuiltin = true; + allocKind = gc::AllocKind::FUNCTION_EXTENDED; + } +#endif flags = (generatorKind == NotGenerator ? JSFunction::INTERPRETED_NORMAL : JSFunction::INTERPRETED_GENERATOR); @@ -1661,8 +1672,13 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, allocKind, TenuredObject); if (!fun) return nullptr; - if (options().selfHostingMode) + 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/jsfun.h b/js/src/jsfun.h index 0b87ec411..606b77161 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -306,6 +306,8 @@ class JSFunction : public js::NativeObject void initAtom(JSAtom* atom) { atom_.init(atom); } + void setAtom(JSAtom* atom) { atom_ = atom; } + JSAtom* displayAtom() const { return atom_; } diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 685299dc2..fb54570d7 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -658,16 +658,37 @@ GlobalObject::getSelfHostedFunction(JSContext* cx, Handle global, HandlePropertyName selfHostedName, HandleAtom name, unsigned nargs, MutableHandleValue funVal) { - if (GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal)) - return true; + if (GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal)) { + RootedFunction fun(cx, &funVal.toObject().as()); + if (fun->atom() == name) + return true; - JSFunction* fun = - NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY, - name, gc::AllocKind::FUNCTION_EXTENDED, SingletonObject); - if (!fun) + if (fun->atom() == selfHostedName) { + // This function was initially cloned because it was called by + // other self-hosted code, so the clone kept its self-hosted name, + // instead of getting the name it's intended to have in content + // compartments. This can happen when a lazy builtin is initialized + // after self-hosted code for another builtin used the same + // function. In that case, we need to change the function's name, + // which is ok because it can't have been exposed to content + // before. + fun->initAtom(name); + return true; + } + + + // The function might be installed multiple times on the same or + // different builtins, under different property names, so its name + // might be neither "selfHostedName" nor "name". In that case, its + // canonical name must've been set using the `_SetCanonicalName` + // intrinsic. + cx->runtime()->assertSelfHostedFunctionHasCanonicalName(cx, selfHostedName); + return true; + } + + RootedFunction fun(cx); + if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, nargs, &fun)) return false; - fun->setIsSelfHostedBuiltin(); - fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(selfHostedName)); funVal.setObject(*fun); return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal); diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 3e75b3836..e7c8d187c 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -934,6 +934,10 @@ struct JSRuntime : public JS::shadow::Runtime, static js::GlobalObject* createSelfHostingGlobal(JSContext* cx); + bool getUnclonedSelfHostedValue(JSContext* cx, js::HandlePropertyName name, + js::MutableHandleValue vp); + JSFunction* getUnclonedSelfHostedFunction(JSContext* cx, js::HandlePropertyName name); + /* Space for interpreter frames. */ js::InterpreterStack interpreterStack_; @@ -974,10 +978,14 @@ struct JSRuntime : public JS::shadow::Runtime, } bool isSelfHostingCompartment(JSCompartment* comp) const; bool isSelfHostingZone(const JS::Zone* zone) const; + bool createLazySelfHostedFunctionClone(JSContext* cx, js::HandlePropertyName selfHostedName, + js::HandleAtom name, unsigned nargs, + js::MutableHandleFunction fun); bool cloneSelfHostedFunctionScript(JSContext* cx, js::Handle name, js::Handle targetFun); bool cloneSelfHostedValue(JSContext* cx, js::Handle name, js::MutableHandleValue vp); + void assertSelfHostedFunctionHasCanonicalName(JSContext* cx, js::HandlePropertyName name); //------------------------------------------------------------------------- // Locale information diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 683ed29d9..d4857f091 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -15,6 +15,7 @@ #include "jscompartment.h" #include "jsdate.h" #include "jsfriendapi.h" +#include "jsfun.h" #include "jshashutil.h" #include "jsweakmap.h" #include "jswrapper.h" @@ -573,6 +574,26 @@ intrinsic_ActiveFunction(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +intrinsic_SetCanonicalName(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 2); + + RootedFunction fun(cx, &args[0].toObject().as()); + MOZ_ASSERT(fun->isSelfHostedBuiltin()); + RootedAtom atom(cx, AtomizeString(cx, args[1].toString())); + if (!atom) + return false; + + fun->setAtom(atom); +#ifdef DEBUG + fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT, BooleanValue(true)); +#endif + args.rval().setUndefined(); + return true; +} + static bool intrinsic_StarGeneratorObjectIsClosed(JSContext* cx, unsigned argc, Value* vp) { @@ -1546,6 +1567,8 @@ static const JSFunctionSpec intrinsic_functions[] = { CallNonGenericSelfhostedMethod>, 2,0), JS_FN("ActiveFunction", intrinsic_ActiveFunction, 0,0), + JS_FN("_SetCanonicalName", intrinsic_SetCanonicalName, 2,0), + JS_INLINABLE_FN("IsArrayIterator", intrinsic_IsInstanceOfBuiltin, 1,0, IntrinsicIsArrayIterator), @@ -2005,8 +2028,10 @@ CloneObject(JSContext* cx, HandleNativeObject selfHostedObject) staticGlobalLexical, 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().setExtendedSlot(0, StringValue(selfHostedFunction->atom())); + if (clone && hasName) { + clone->as().setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, + StringValue(selfHostedFunction->atom())); + } } else if (selfHostedObject->is()) { RegExpObject& reobj = selfHostedObject->as(); RootedAtom source(cx, reobj.getSource()); @@ -2073,16 +2098,37 @@ CloneValue(JSContext* cx, HandleValue selfHostedValue, MutableHandleValue vp) return true; } +bool +JSRuntime::createLazySelfHostedFunctionClone(JSContext* cx, HandlePropertyName selfHostedName, + HandleAtom name, unsigned nargs, + MutableHandleFunction fun) +{ + RootedAtom funName(cx, name); + JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, selfHostedName); + if (!selfHostedFun) + return false; + + if (selfHostedFun->atom() != selfHostedName) { + MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean()); + funName = selfHostedFun->atom(); + } + + fun.set(NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY, + funName, gc::AllocKind::FUNCTION_EXTENDED, SingletonObject)); + if (!fun) + return false; + fun->setIsSelfHostedBuiltin(); + fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(selfHostedName)); + return true; +} + bool JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name, HandleFunction targetFun) { - RootedId id(cx, NameToId(name)); - RootedValue funVal(cx); - if (!GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_), id, &funVal)) + RootedFunction sourceFun(cx, getUnclonedSelfHostedFunction(cx, name)); + if (!sourceFun) return false; - - RootedFunction sourceFun(cx, &funVal.toObject().as()); // JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there // aren't any. MOZ_ASSERT(!sourceFun->isGenerator()); @@ -2112,11 +2158,28 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name, } bool -JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name, MutableHandleValue vp) +JSRuntime::getUnclonedSelfHostedValue(JSContext* cx, HandlePropertyName name, + MutableHandleValue vp) { RootedId id(cx, NameToId(name)); + return GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_), id, vp); +} + +JSFunction* +JSRuntime::getUnclonedSelfHostedFunction(JSContext* cx, HandlePropertyName name) +{ RootedValue selfHostedValue(cx); - if (!GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_), id, &selfHostedValue)) + if (!getUnclonedSelfHostedValue(cx, name, &selfHostedValue)) + return nullptr; + + return &selfHostedValue.toObject().as(); +} + +bool +JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name, MutableHandleValue vp) +{ + RootedValue selfHostedValue(cx); + if (!getUnclonedSelfHostedValue(cx, name, &selfHostedValue)) return false; /* @@ -2132,6 +2195,16 @@ JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name, MutableH return CloneValue(cx, selfHostedValue, vp); } +void +JSRuntime::assertSelfHostedFunctionHasCanonicalName(JSContext* cx, HandlePropertyName name) +{ +#ifdef DEBUG + JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, name); + MOZ_ASSERT(selfHostedFun); + MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean()); +#endif +} + JSFunction* js::SelfHostedFunction(JSContext* cx, HandlePropertyName propName) {