diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 283ed249ecf5..09d7b7e2649f 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -5493,18 +5493,18 @@ BytecodeEmitter::setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name, // Single node can be emitted multiple times if it appears in // array destructuring default. If function already has a name, // just return. - if (fun->hasCompileTimeName()) { + if (fun->hasInferredName()) { #ifdef DEBUG RootedFunction rootedFun(cx, fun); JSAtom* funName = NameToFunctionName(cx, name, prefixKind); if (!funName) return false; - MOZ_ASSERT(funName == rootedFun->compileTimeName()); + MOZ_ASSERT(funName == rootedFun->inferredName()); #endif return true; } - fun->setCompileTimeName(name); + fun->setInferredName(name); return true; } diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index 7e1838682ac3..0faaec9e6930 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -278,7 +278,11 @@ class NameResolver retAtom.set(buf.finishAtom()); if (!retAtom) return false; - fun->setGuessedAtom(retAtom); + + // Skip assigning the guessed name if the function has a (dynamically) + // computed inferred name. + if (!pn->isDirectRHSAnonFunction()) + fun->setGuessedAtom(retAtom); return true; } diff --git a/js/src/jit-test/tests/basic/functionnames.js b/js/src/jit-test/tests/basic/functionnames.js index 7fef872fcefe..6ab440fb410e 100644 --- a/js/src/jit-test/tests/basic/functionnames.js +++ b/js/src/jit-test/tests/basic/functionnames.js @@ -130,7 +130,7 @@ assertName(z[0], 'z<'); odeURIL:(function(){}) a = { 1: function () {} }; -assertName(a[1], 'a[1]'); +assertName(a[1], '1'); a = { "embedded spaces": function(){}, diff --git a/js/src/vm/AsyncFunction.cpp b/js/src/vm/AsyncFunction.cpp index 538d6a211b0a..1ae2bafbe100 100644 --- a/js/src/vm/AsyncFunction.cpp +++ b/js/src/vm/AsyncFunction.cpp @@ -138,8 +138,8 @@ js::WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleOb if (!wrapped) return nullptr; - if (unwrapped->hasCompileTimeName()) - wrapped->setCompileTimeName(unwrapped->compileTimeName()); + if (unwrapped->hasInferredName()) + wrapped->setInferredName(unwrapped->inferredName()); // Link them to each other to make GetWrappedAsyncFunction and // GetUnwrappedAsyncFunction work. diff --git a/js/src/vm/AsyncIteration.cpp b/js/src/vm/AsyncIteration.cpp index 2de4cc2139f5..dee53f31bb34 100644 --- a/js/src/vm/AsyncIteration.cpp +++ b/js/src/vm/AsyncIteration.cpp @@ -83,8 +83,8 @@ js::WrapAsyncGeneratorWithProto(JSContext* cx, HandleFunction unwrapped, HandleO if (!wrapped) return nullptr; - if (unwrapped->hasCompileTimeName()) - wrapped->setCompileTimeName(unwrapped->compileTimeName()); + if (unwrapped->hasInferredName()) + wrapped->setInferredName(unwrapped->inferredName()); // Link them to each other to make GetWrappedAsyncGenerator and // GetUnwrappedAsyncGenerator work. diff --git a/js/src/vm/JSFunction.cpp b/js/src/vm/JSFunction.cpp index 82ed67440225..0ad1b9abd7c7 100644 --- a/js/src/vm/JSFunction.cpp +++ b/js/src/vm/JSFunction.cpp @@ -590,7 +590,7 @@ js::XDRInterpretedFunction(XDRState* xdr, HandleScope enclosingScope, if (!fun->isInterpreted()) return xdr->fail(JS::TranscodeResult_Failure_NotInterpretedFun); - if (fun->explicitName() || fun->hasCompileTimeName() || fun->hasGuessedAtom()) + if (fun->explicitName() || fun->hasInferredName() || fun->hasGuessedAtom()) firstword |= HasAtom; if (fun->isGenerator() || fun->isAsync()) @@ -1327,12 +1327,8 @@ JSFunction::getUnresolvedName(JSContext* cx, HandleFunction fun, MutableHandleAt MOZ_ASSERT(!IsInternalFunctionObject(*fun)); MOZ_ASSERT(!fun->hasResolvedName()); - JSAtom* name = fun->explicitOrCompileTimeName(); + JSAtom* name = fun->explicitOrInferredName(); if (fun->isClassConstructor()) { - // It's impossible to have an empty named class expression. We use - // empty as a sentinel when creating default class constructors. - MOZ_ASSERT(name != cx->names().empty); - // Unnamed class expressions should not get a .name property at all. if (name) v.set(name); @@ -2307,9 +2303,8 @@ js::SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue na if (!funNameAtom) return false; - RootedValue funNameVal(cx, StringValue(funNameAtom)); - if (!NativeDefineDataProperty(cx, fun, cx->names().name, funNameVal, JSPROP_READONLY)) - return false; + MOZ_ASSERT(!fun->hasResolvedName()); + fun->setInferredName(funNameAtom); return true; } diff --git a/js/src/vm/JSFunction.h b/js/src/vm/JSFunction.h index 71723d1ff0a9..11819a0232c7 100644 --- a/js/src/vm/JSFunction.h +++ b/js/src/vm/JSFunction.h @@ -70,9 +70,9 @@ class JSFunction : public js::NativeObject function-statement) */ SELF_HOSTED = 0x0080, /* function is self-hosted builtin and must not be decompilable nor constructible. */ - HAS_COMPILE_TIME_NAME = 0x0100, /* function had no explicit name, but a - name was set by SetFunctionName - at compile time */ + HAS_INFERRED_NAME = 0x0100, /* function had no explicit name, but a name was + set by SetFunctionName at compile time or + SetFunctionNameIfNoOwnName at runtime. */ INTERPRETED_LAZY = 0x0200, /* function is interpreted but doesn't have a script yet */ RESOLVED_LENGTH = 0x0400, /* f.length has been resolved (see fun_resolve). */ RESOLVED_NAME = 0x0800, /* f.name has been resolved (see fun_resolve). */ @@ -106,8 +106,7 @@ class JSFunction : public js::NativeObject INTERPRETED_GENERATOR_OR_ASYNC = INTERPRETED, NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME, - STABLE_ACROSS_CLONES = CONSTRUCTOR | LAMBDA | SELF_HOSTED | HAS_COMPILE_TIME_NAME | - FUNCTION_KIND_MASK + STABLE_ACROSS_CLONES = CONSTRUCTOR | LAMBDA | SELF_HOSTED | FUNCTION_KIND_MASK }; static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS, @@ -205,7 +204,7 @@ class JSFunction : public js::NativeObject /* Possible attributes of an interpreted function: */ bool isBoundFunction() const { return flags() & BOUND_FUN; } - bool hasCompileTimeName() const { return flags() & HAS_COMPILE_TIME_NAME; } + bool hasInferredName() const { return flags() & HAS_INFERRED_NAME; } bool hasGuessedAtom() const { static_assert(HAS_GUESSED_ATOM == HAS_BOUND_FUNCTION_NAME_PREFIX, "HAS_GUESSED_ATOM is unused for bound functions"); @@ -259,7 +258,7 @@ class JSFunction : public js::NativeObject } bool isNamedLambda() const { - return isLambda() && displayAtom() && !hasCompileTimeName() && !hasGuessedAtom(); + return isLambda() && displayAtom() && !hasInferredName() && !hasGuessedAtom(); } bool hasLexicalThis() const { @@ -346,9 +345,9 @@ class JSFunction : public js::NativeObject js::MutableHandleAtom v); JSAtom* explicitName() const { - return (hasCompileTimeName() || hasGuessedAtom()) ? nullptr : atom_.get(); + return (hasInferredName() || hasGuessedAtom()) ? nullptr : atom_.get(); } - JSAtom* explicitOrCompileTimeName() const { + JSAtom* explicitOrInferredName() const { return hasGuessedAtom() ? nullptr : atom_.get(); } @@ -366,16 +365,21 @@ class JSFunction : public js::NativeObject return atom_; } - void setCompileTimeName(JSAtom* atom) { + void setInferredName(JSAtom* atom) { MOZ_ASSERT(!atom_); MOZ_ASSERT(atom); MOZ_ASSERT(!hasGuessedAtom()); - MOZ_ASSERT(!isClassConstructor()); setAtom(atom); - flags_ |= HAS_COMPILE_TIME_NAME; + flags_ |= HAS_INFERRED_NAME; } - JSAtom* compileTimeName() const { - MOZ_ASSERT(hasCompileTimeName()); + void clearInferredName() { + MOZ_ASSERT(hasInferredName()); + MOZ_ASSERT(atom_); + setAtom(nullptr); + flags_ &= ~HAS_INFERRED_NAME; + } + JSAtom* inferredName() const { + MOZ_ASSERT(hasInferredName()); MOZ_ASSERT(atom_); return atom_; } @@ -383,7 +387,7 @@ class JSFunction : public js::NativeObject void setGuessedAtom(JSAtom* atom) { MOZ_ASSERT(!atom_); MOZ_ASSERT(atom); - MOZ_ASSERT(!hasCompileTimeName()); + MOZ_ASSERT(!hasInferredName()); MOZ_ASSERT(!hasGuessedAtom()); MOZ_ASSERT(!isBoundFunction()); setAtom(atom); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 0f55d8e95d6d..79b7ca724fbb 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -480,10 +480,10 @@ intrinsic_MakeDefaultConstructor(JSContext* cx, unsigned argc, Value* vp) // Because self-hosting code does not allow top-level lexicals, // class constructors are class expressions in top-level vars. - // Because of this, we give them a guessed atom. Since they + // Because of this, we give them an inferred atom. Since they // will always be cloned, and given an explicit atom, instead // overrule that. - ctor->clearGuessedAtom(); + ctor->clearInferredName(); args.rval().setUndefined(); return true;