summaryrefslogtreecommitdiffstats
path: root/js/src/jsfun.cpp
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-03-20 10:08:54 +0100
committerwolfbeast <mcwerewolf@gmail.com>2018-03-20 10:10:12 +0100
commit893a886ea38853a1a3e97bcf135ea3cb616cd69a (patch)
tree5188f8895ce513381917d37115b50f72fb4e64a9 /js/src/jsfun.cpp
parent7197b308fb97cd8ab7a972df6a3a17a7a265b594 (diff)
parent6085bfdcecc2529c1037f813e70583c2a776677d (diff)
downloadUXP-893a886ea38853a1a3e97bcf135ea3cb616cd69a.tar
UXP-893a886ea38853a1a3e97bcf135ea3cb616cd69a.tar.gz
UXP-893a886ea38853a1a3e97bcf135ea3cb616cd69a.tar.lz
UXP-893a886ea38853a1a3e97bcf135ea3cb616cd69a.tar.xz
UXP-893a886ea38853a1a3e97bcf135ea3cb616cd69a.zip
Add support for the function `name` property.
This resolves #78. Merged remote-tracking branch 'janek/js_function_name_1'
Diffstat (limited to 'js/src/jsfun.cpp')
-rw-r--r--js/src/jsfun.cpp120
1 files changed, 100 insertions, 20 deletions
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index 1e1b76d5d..bcb0da80b 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -562,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())
@@ -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;
}
@@ -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;
}
@@ -1365,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&
@@ -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
};
@@ -2132,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 */)