From 75db97cb3772fc0693947ec17c5954a04cb234a8 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 19 Mar 2018 14:48:24 +0100 Subject: Bug 1320388: Move JSFunction::HAS_REST to JSScript and LazyScript Issue #78 [Depends on] Bug 883377: Implement ES6 function "name" property semantics --- js/src/jsfun.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'js/src/jsfun.cpp') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 1e1b76d5d..2359e28a2 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1329,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; } @@ -1620,7 +1619,7 @@ 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 }; -- cgit v1.2.3 From 6822460d3b0d4609ee5d4e1ab4b093799ed06580 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 19 Mar 2018 15:18:37 +0100 Subject: Bug 1317309: Throw a TypeError when passing a Symbol value to ToAtom Issue #78 [Depends on] Bug 883377: Implement ES6 function "name" property semantics --- js/src/jsfun.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'js/src/jsfun.cpp') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 2359e28a2..1d44f0ea0 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -2131,9 +2131,10 @@ 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 */) @@ -2141,7 +2142,11 @@ js::IdToFunctionName(JSContext* cx, HandleId id, const char* prefix /* = nullptr if (JSID_IS_ATOM(id) && !prefix) return JSID_TO_ATOM(id); - if (JSID_IS_SYMBOL(id) && !prefix) { + // Step 3. + MOZ_ASSERT_IF(prefix, !JSID_IS_SYMBOL(id)); + + // Step 4. + if (JSID_IS_SYMBOL(id)) { RootedAtom desc(cx, JSID_TO_SYMBOL(id)->description()); StringBuffer sb(cx); if (!sb.append('[') || !sb.append(desc) || !sb.append(']')) @@ -2149,6 +2154,7 @@ js::IdToFunctionName(JSContext* cx, HandleId id, const char* prefix /* = nullptr return sb.finishAtom(); } + // Step 5. RootedValue idv(cx, IdToValue(id)); if (!prefix) return ToAtom(cx, idv); -- cgit v1.2.3 From 5ef44cf6484b9dfd49c0174ac2969a29587a1bbd Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 19 Mar 2018 15:47:10 +0100 Subject: Part 1: Implement ES6 function name property semantics Issue #78 --- js/src/jsfun.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 17 deletions(-) (limited to 'js/src/jsfun.cpp') diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 1d44f0ea0..bcb0da80b 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -562,7 +562,7 @@ js::XDRInterpretedFunction(XDRState* xdr, HandleScope enclosingScope, return false; } - if (fun->name() || fun->hasGuessedAtom()) + if (fun->explicitName() || fun->hasCompileTimeName() || fun->hasGuessedAtom()) firstword |= HasAtom; if (fun->isStarGenerator()) @@ -1042,8 +1042,8 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) if (!ok) return nullptr; } - if (fun->name()) { - if (!out.append(fun->name())) + if (fun->explicitName()) { + if (!out.append(fun->explicitName())) return nullptr; } @@ -1364,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& @@ -2137,34 +2137,109 @@ js::CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject enclo * 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); - // Step 3. - MOZ_ASSERT_IF(prefix, !JSID_IS_SYMBOL(id)); + // 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(); } - // Step 5. RootedValue idv(cx, IdToValue(id)); - if (!prefix) - return ToAtom(cx, idv); + RootedAtom name(cx, ToAtom(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(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(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 */) -- cgit v1.2.3