summaryrefslogtreecommitdiffstats
path: root/js/src/jsfun.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsfun.cpp')
-rw-r--r--js/src/jsfun.cpp428
1 files changed, 197 insertions, 231 deletions
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index c952441ad..bcb0da80b 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -12,6 +12,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/CheckedInt.h"
+#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Range.h"
@@ -60,8 +61,10 @@ using namespace js::gc;
using namespace js::frontend;
using mozilla::ArrayLength;
+using mozilla::Maybe;
using mozilla::PodCopy;
using mozilla::RangedPtr;
+using mozilla::Some;
static bool
fun_enumerate(JSContext* cx, HandleObject obj)
@@ -559,7 +562,7 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
return false;
}
- if (fun->name() || fun->hasGuessedAtom())
+ if (fun->explicitName() || fun->hasCompileTimeName() || fun->hasGuessedAtom())
firstword |= HasAtom;
if (fun->isStarGenerator())
@@ -985,19 +988,19 @@ js::FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t*
}
JSString*
-js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
+js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
{
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
return nullptr;
if (IsAsmJSModule(fun))
- return AsmJSModuleToString(cx, fun, !lambdaParen);
+ return AsmJSModuleToString(cx, fun, !prettyPrint);
if (IsAsmJSFunction(fun))
return AsmJSFunctionToString(cx, fun);
if (IsWrappedAsyncFunction(fun)) {
RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
- return FunctionToString(cx, unwrapped, lambdaParen);
+ return FunctionToString(cx, unwrapped, prettyPrint);
}
StringBuffer out(cx);
@@ -1023,11 +1026,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
fun->isGetter() || fun->isSetter();
+ bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
// If we're not in pretty mode, put parentheses around lambda functions and methods.
- if (fun->isInterpreted() && !lambdaParen && funIsMethodOrNonArrowLambda &&
- !fun->isSelfHostedBuiltin())
- {
+ if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) {
if (!out.append("("))
return nullptr;
}
@@ -1040,12 +1042,11 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
if (!ok)
return nullptr;
}
- if (fun->name()) {
- if (!out.append(fun->name()))
+ if (fun->explicitName()) {
+ if (!out.append(fun->explicitName()))
return nullptr;
}
- bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
if (haveSource && !script->scriptSource()->hasSourceData() &&
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
{
@@ -1056,54 +1057,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
if (!src)
return nullptr;
- // The source data for functions created by calling the Function
- // constructor is only the function's body. This depends on the fact,
- // asserted below, that in Function("function f() {}"), the inner
- // function's sourceStart points to the '(', not the 'f'.
- bool funCon = !fun->isArrow() &&
- script->sourceStart() == 0 &&
- script->sourceEnd() == script->scriptSource()->length() &&
- script->scriptSource()->argumentsNotIncluded();
-
- // Functions created with the constructor can't be arrow functions or
- // expression closures.
- MOZ_ASSERT_IF(funCon, !fun->isArrow());
- MOZ_ASSERT_IF(funCon, !fun->isExprBody());
- MOZ_ASSERT_IF(!funCon && !fun->isArrow(),
- src->length() > 0 && src->latin1OrTwoByteChar(0) == '(');
-
- bool buildBody = funCon;
- if (buildBody) {
- // This function was created with the Function constructor. We don't
- // have source for the arguments, so we have to generate that. Part
- // of bug 755821 should be cobbling the arguments passed into the
- // Function constructor into the source string.
- if (!out.append("("))
- return nullptr;
-
- // Fish out the argument names.
- MOZ_ASSERT(script->numArgs() == fun->nargs());
-
- BindingIter bi(script);
- for (unsigned i = 0; i < fun->nargs(); i++, bi++) {
- MOZ_ASSERT(bi.argumentSlot() == i);
- if (i && !out.append(", "))
- return nullptr;
- if (i == unsigned(fun->nargs() - 1) && fun->hasRest() && !out.append("..."))
- return nullptr;
- if (!out.append(bi.name()))
- return nullptr;
- }
- if (!out.append(") {\n"))
- return nullptr;
- }
if (!out.append(src))
return nullptr;
- if (buildBody) {
- if (!out.append("\n}"))
- return nullptr;
- }
- if (!lambdaParen && funIsMethodOrNonArrowLambda) {
+
+ if (!prettyPrint && funIsMethodOrNonArrowLambda) {
if (!out.append(")"))
return nullptr;
}
@@ -1114,8 +1071,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
{
return nullptr;
}
- if (!lambdaParen && fun->isLambda() && !fun->isArrow() && !out.append(")"))
- return nullptr;
} else {
MOZ_ASSERT(!fun->isExprBody());
@@ -1374,8 +1329,7 @@ JSFunction::getLength(JSContext* cx, uint16_t* length)
if (self->isInterpretedLazy() && !self->getOrCreateScript(cx))
return false;
- *length = self->hasScript() ? self->nonLazyScript()->funLength()
- : (self->nargs() - self->hasRest());
+ *length = self->isNative() ? self->nargs() : self->nonLazyScript()->funLength();
return true;
}
@@ -1410,14 +1364,14 @@ JSFunction::getUnresolvedName(JSContext* cx)
if (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);
+ MOZ_ASSERT(explicitOrCompileTimeName() != cx->names().empty);
// Unnamed class expressions should not get a .name property at all.
- return name();
+ return explicitOrCompileTimeName();
}
- // Returns the empty string for unnamed functions (FIXME: bug 883377).
- return name() != nullptr ? name() : cx->names().empty;
+ return explicitOrCompileTimeName() != nullptr ? explicitOrCompileTimeName()
+ : cx->names().empty;
}
static const js::Value&
@@ -1657,17 +1611,6 @@ fun_isGenerator(JSContext* cx, unsigned argc, Value* vp)
return true;
}
-/*
- * Report "malformed formal parameter" iff no illegal char or similar scanner
- * error was already reported.
- */
-static bool
-OnBadFormal(JSContext* cx)
-{
- JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_FORMAL);
- return false;
-}
-
const JSFunctionSpec js::function_methods[] = {
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, fun_toSource, 0,0),
@@ -1676,18 +1619,17 @@ const JSFunctionSpec js::function_methods[] = {
JS_FN(js_apply_str, fun_apply, 2,0),
JS_FN(js_call_str, fun_call, 1,0),
JS_FN("isGenerator", fun_isGenerator,0,0),
- JS_SELF_HOSTED_FN("bind", "FunctionBind", 2, JSFUN_HAS_REST),
+ JS_SELF_HOSTED_FN("bind", "FunctionBind", 2, 0),
JS_SYM_FN(hasInstance, fun_symbolHasInstance, 1, JSPROP_READONLY | JSPROP_PERMANENT),
JS_FS_END
};
+// ES 2017 draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077 19.2.1.1.1.
static bool
-FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind generatorKind,
+FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
{
- CallArgs args = CallArgsFromVp(argc, vp);
-
- /* Block this call if security callbacks forbid it. */
+ // Block this call if security callbacks forbid it.
Rooted<GlobalObject*> global(cx, &args.callee().global());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
@@ -1719,82 +1661,65 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
introducerFilename = maybeScript->scriptSource()->introducerFilename();
CompileOptions options(cx);
+ // Use line 0 to make the function body starts from line 1.
options.setMutedErrors(mutedErrors)
- .setFileAndLine(filename, 1)
+ .setFileAndLine(filename, 0)
.setNoScriptRval(false)
.setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset);
- Vector<char16_t> paramStr(cx);
- RootedString bodyText(cx);
+ StringBuffer sb(cx);
- if (args.length() == 0) {
- bodyText = cx->names().empty;
- } else {
- // Collect the function-argument arguments into one string, separated
- // by commas, then make a tokenstream from that string, and scan it to
- // get the arguments. We need to throw the full scanner at the
- // problem because the argument string may contain comments, newlines,
- // destructuring arguments, and similar manner of insanities. ("I have
- // a feeling we're not in simple-comma-separated-parameters land any
- // more, Toto....")
- //
- // XXX It'd be better if the parser provided utility methods to parse
- // an argument list, and to parse a function body given a parameter
- // list. But our parser provides no such pleasant interface now.
- unsigned n = args.length() - 1;
+ if (!sb.append('('))
+ return false;
- // Convert the parameters-related arguments to strings, and determine
- // the length of the string containing the overall parameter list.
- mozilla::CheckedInt<uint32_t> paramStrLen = 0;
+ if (args.length() > 1) {
RootedString str(cx);
+
+ // Steps 5-6, 9.
+ unsigned n = args.length() - 1;
+
for (unsigned i = 0; i < n; i++) {
+ // Steps 9.a-b, 9.d.i-ii.
str = ToString<CanGC>(cx, args[i]);
if (!str)
return false;
- args[i].setString(str);
- paramStrLen += str->length();
- }
-
- // Tack in space for any combining commas.
- if (n > 0)
- paramStrLen += n - 1;
+ // Steps 9.b, 9.d.iii.
+ if (!sb.append(str))
+ return false;
- // Check for integer and string-size overflow.
- if (!paramStrLen.isValid() || paramStrLen.value() > JSString::MAX_LENGTH) {
- ReportAllocationOverflow(cx);
- return false;
+ if (i < args.length() - 2) {
+ // Step 9.d.iii.
+ if (!sb.append(", "))
+ return false;
+ }
}
+ }
- uint32_t paramsLen = paramStrLen.value();
-
- // Fill a vector with the comma-joined arguments. Careful! This
- // string is *not* null-terminated!
- MOZ_ASSERT(paramStr.length() == 0);
- if (!paramStr.growBy(paramsLen)) {
- ReportOutOfMemory(cx);
- return false;
- }
+ // Remember the position of ")".
+ Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
+ MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
- char16_t* cp = paramStr.begin();
- for (unsigned i = 0; i < n; i++) {
- JSLinearString* argLinear = args[i].toString()->ensureLinear(cx);
- if (!argLinear)
- return false;
+ if (!sb.append(FunctionConstructorMedialSigils))
+ return false;
- CopyChars(cp, *argLinear);
- cp += argLinear->length();
+ if (args.length() > 0) {
+ // Steps 7-8, 10.
+ RootedString body(cx, ToString<CanGC>(cx, args[args.length() - 1]));
+ if (!body || !sb.append(body))
+ return false;
+ }
- if (i + 1 < n)
- *cp++ = ',';
- }
+ if (!sb.append(FunctionConstructorFinalBrace))
+ return false;
- MOZ_ASSERT(cp == paramStr.end());
+ // The parser only accepts two byte strings.
+ if (!sb.ensureTwoByteChars())
+ return false;
- bodyText = ToString(cx, args[n]);
- if (!bodyText)
- return false;
- }
+ RootedString functionText(cx, sb.finishString());
+ if (!functionText)
+ return false;
/*
* NB: (new Function) is not lexically closed by its caller, it's just an
@@ -1803,18 +1728,23 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
* and so would a call to f from another top-level's script or function.
*/
RootedAtom anonymousAtom(cx, cx->names().anonymous);
+
+ // Step 24.
RootedObject proto(cx);
- if (isStarGenerator) {
- // Unwrapped function of async function should use GeneratorFunction,
- // while wrapped function isn't generator.
+ if (!isAsync) {
+ if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
+ return false;
+ }
+
+ // Step 4.d, use %Generator% as the fallback prototype.
+ // Also use %Generator% for the unwrapped function of async functions.
+ if (!proto && isStarGenerator) {
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
if (!proto)
return false;
- } else {
- if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
- return false;
}
+ // Step 25-32 (reordered).
RootedObject globalLexical(cx, &global->lexicalEnvironment());
AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
@@ -1827,81 +1757,11 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
if (!JSFunction::setTypeForScriptedFunction(cx, fun))
return false;
+ // Steps 2.a-b, 3.a-b, 4.a-b, 11-23.
AutoStableStringChars stableChars(cx);
- if (!stableChars.initTwoByte(cx, bodyText))
+ if (!stableChars.initTwoByte(cx, functionText))
return false;
- bool hasRest = false;
-
- Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
- if (args.length() > 1) {
- // Initialize a tokenstream to parse the new function's arguments. No
- // StrictModeGetter is needed because this TokenStream won't report any
- // strict mode errors. Strict mode errors that might be reported here
- // (duplicate argument names, etc.) will be detected when we compile
- // the function body.
- //
- // XXX Bug! We have to parse the body first to determine strictness.
- // We have to know strictness to parse arguments correctly, in case
- // arguments contains a strict mode violation. And we should be
- // using full-fledged arguments parsing here, in order to handle
- // destructuring and other exotic syntaxes.
- AutoKeepAtoms keepAtoms(cx->perThreadData);
- TokenStream ts(cx, options, paramStr.begin(), paramStr.length(),
- /* strictModeGetter = */ nullptr);
- bool yieldIsValidName = ts.versionNumber() < JSVERSION_1_7 && !isStarGenerator;
-
- // The argument string may be empty or contain no tokens.
- TokenKind tt;
- if (!ts.getToken(&tt))
- return false;
- if (tt != TOK_EOF) {
- while (true) {
- // Check that it's a name.
- if (hasRest) {
- ts.reportError(JSMSG_PARAMETER_AFTER_REST);
- return false;
- }
-
- if (tt == TOK_YIELD && yieldIsValidName)
- tt = TOK_NAME;
-
- if (tt != TOK_NAME) {
- if (tt == TOK_TRIPLEDOT) {
- hasRest = true;
- if (!ts.getToken(&tt))
- return false;
- if (tt == TOK_YIELD && yieldIsValidName)
- tt = TOK_NAME;
- if (tt != TOK_NAME) {
- ts.reportError(JSMSG_NO_REST_NAME);
- return false;
- }
- } else {
- return OnBadFormal(cx);
- }
- }
-
- if (!formals.append(ts.currentName()))
- return false;
-
- // Get the next token. Stop on end of stream. Otherwise
- // insist on a comma, get another name, and iterate.
- if (!ts.getToken(&tt))
- return false;
- if (tt == TOK_EOF)
- break;
- if (tt != TOK_COMMA)
- return OnBadFormal(cx);
- if (!ts.getToken(&tt))
- return false;
- }
- }
- }
-
- if (hasRest)
- fun->setHasRest();
-
mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
@@ -1909,11 +1769,13 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
bool ok;
SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
if (isAsync)
- ok = frontend::CompileAsyncFunctionBody(cx, &fun, options, formals, srcBuf);
+ ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd);
else if (isStarGenerator)
- ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
+ ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
else
- ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf);
+ ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
+
+ // Step 33.
args.rval().setObject(*fun);
return ok;
}
@@ -1921,24 +1783,47 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
bool
js::Function(JSContext* cx, unsigned argc, Value* vp)
{
- return FunctionConstructor(cx, argc, vp, NotGenerator, SyncFunction);
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return FunctionConstructor(cx, args, NotGenerator, SyncFunction);
}
bool
js::Generator(JSContext* cx, unsigned argc, Value* vp)
{
- return FunctionConstructor(cx, argc, vp, StarGenerator, SyncFunction);
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return FunctionConstructor(cx, args, StarGenerator, SyncFunction);
}
bool
js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- if (!FunctionConstructor(cx, argc, vp, StarGenerator, AsyncFunction))
+
+ // Save the callee before its reset in FunctionConstructor().
+ RootedObject newTarget(cx);
+ if (args.isConstructing())
+ newTarget = &args.newTarget().toObject();
+ else
+ newTarget = &args.callee();
+
+ if (!FunctionConstructor(cx, args, StarGenerator, AsyncFunction))
+ return false;
+
+ // ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077
+ // 19.2.1.1.1 Runtime Semantics: CreateDynamicFunction, step 24.
+ RootedObject proto(cx);
+ if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
return false;
+ // 19.2.1.1.1, step 4.d, use %AsyncFunctionPrototype% as the fallback.
+ if (!proto) {
+ proto = GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global());
+ if (!proto)
+ return false;
+ }
+
RootedFunction unwrapped(cx, &args.rval().toObject().as<JSFunction>());
- RootedObject wrapped(cx, WrapAsyncFunction(cx, unwrapped));
+ RootedObject wrapped(cx, WrapAsyncFunctionWithProto(cx, unwrapped, proto));
if (!wrapped)
return false;
@@ -2246,34 +2131,115 @@ js::CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject enclo
*
* Function names are always strings. If id is the well-known @@iterator
* symbol, this returns "[Symbol.iterator]". If a prefix is supplied the final
- * name is |prefix + " " + name|.
+ * name is |prefix + " " + name|. A prefix cannot be supplied if id is a
+ * symbol value.
*
- * Implements step 4 and 5 of SetFunctionName in ES 2016 draft Dec 20, 2015.
+ * Implements steps 3-5 of 9.2.11 SetFunctionName in ES2016.
*/
JSAtom*
-js::IdToFunctionName(JSContext* cx, HandleId id, const char* prefix /* = nullptr */)
+js::IdToFunctionName(JSContext* cx, HandleId id,
+ FunctionPrefixKind prefixKind /* = FunctionPrefixKind::None */)
{
- if (JSID_IS_ATOM(id) && !prefix)
+ // No prefix fastpath.
+ if (JSID_IS_ATOM(id) && prefixKind == FunctionPrefixKind::None)
return JSID_TO_ATOM(id);
- if (JSID_IS_SYMBOL(id) && !prefix) {
+ // Step 3 (implicit).
+
+ // Step 4.
+ if (JSID_IS_SYMBOL(id)) {
+ // Step 4.a.
RootedAtom desc(cx, JSID_TO_SYMBOL(id)->description());
+
+ // Step 4.b, no prefix fastpath.
+ if (!desc && prefixKind == FunctionPrefixKind::None)
+ return cx->names().empty;
+
+ // Step 5 (reordered).
StringBuffer sb(cx);
- if (!sb.append('[') || !sb.append(desc) || !sb.append(']'))
- return nullptr;
+ if (prefixKind == FunctionPrefixKind::Get) {
+ if (!sb.append("get "))
+ return nullptr;
+ } else if (prefixKind == FunctionPrefixKind::Set) {
+ if (!sb.append("set "))
+ return nullptr;
+ }
+
+ // Step 4.b.
+ if (desc) {
+ // Step 4.c.
+ if (!sb.append('[') || !sb.append(desc) || !sb.append(']'))
+ return nullptr;
+ }
return sb.finishAtom();
}
RootedValue idv(cx, IdToValue(id));
- if (!prefix)
- return ToAtom<CanGC>(cx, idv);
+ RootedAtom name(cx, ToAtom<CanGC>(cx, idv));
+ if (!name)
+ return nullptr;
+
+ // Step 5.
+ return NameToFunctionName(cx, name, prefixKind);
+}
+
+JSAtom*
+js::NameToFunctionName(ExclusiveContext* cx, HandleAtom name,
+ FunctionPrefixKind prefixKind /* = FunctionPrefixKind::None */)
+{
+ if (prefixKind == FunctionPrefixKind::None)
+ return name;
StringBuffer sb(cx);
- if (!sb.append(prefix, strlen(prefix)) || !sb.append(' ') || !sb.append(ToAtom<CanGC>(cx, idv)))
+ if (prefixKind == FunctionPrefixKind::Get) {
+ if (!sb.append("get "))
+ return nullptr;
+ } else {
+ if (!sb.append("set "))
+ return nullptr;
+ }
+ if (!sb.append(name))
return nullptr;
return sb.finishAtom();
}
+bool
+js::SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue name,
+ FunctionPrefixKind prefixKind)
+{
+ MOZ_ASSERT(name.isString() || name.isSymbol() || name.isNumber());
+
+ if (fun->isClassConstructor()) {
+ // A class may have static 'name' method or accessor.
+ RootedId nameId(cx, NameToId(cx->names().name));
+ bool result;
+ if (!HasOwnProperty(cx, fun, nameId, &result))
+ return false;
+
+ if (result)
+ return true;
+ } else {
+ // Anonymous function shouldn't have own 'name' property at this point.
+ MOZ_ASSERT(!fun->containsPure(cx->names().name));
+ }
+
+ RootedId id(cx);
+ if (!ValueToId<CanGC>(cx, name, &id))
+ return false;
+
+ RootedAtom funNameAtom(cx, IdToFunctionName(cx, id, prefixKind));
+ if (!funNameAtom)
+ return false;
+
+ RootedValue funNameVal(cx, StringValue(funNameAtom));
+ if (!NativeDefineProperty(cx, fun, cx->names().name, funNameVal, nullptr, nullptr,
+ JSPROP_READONLY))
+ {
+ return false;
+ }
+ return true;
+}
+
JSFunction*
js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native,
unsigned nargs, unsigned flags, AllocKind allocKind /* = AllocKind::FUNCTION */)