summaryrefslogtreecommitdiff
path: root/js/src/jsfun.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsfun.cpp')
-rw-r--r--js/src/jsfun.cpp184
1 files changed, 98 insertions, 86 deletions
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index be1d39cd19..fc243fab66 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -339,11 +339,11 @@ CallerSetterImpl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsFunction(args.thisv()));
- // We just have to return |undefined|, but first we call CallerGetterImpl
- // because we need the same strict-mode and security checks.
-
+ // We just have to return |undefined|, but first we call CallerGetterImpl
+ // because we need the same strict-mode and security checks.
+
if (!CallerGetterImpl(cx, args)) {
- return false;
+ return false;
}
args.rval().setUndefined();
@@ -498,9 +498,12 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
if (fun->hasResolvedName())
return true;
+ RootedAtom name(cx);
+ if (!JSFunction::getUnresolvedName(cx, fun, &name))
+ return false;
+
// Don't define an own .name property for unnamed functions.
- JSAtom* name = fun->getUnresolvedName(cx);
- if (name == nullptr)
+ if (!name)
return true;
v.setString(name);
@@ -939,24 +942,24 @@ const Class JSFunction::class_ = {
const Class* const js::FunctionClassPtr = &JSFunction::class_;
JSString*
-js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
+js::FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource)
{
if (fun->isInterpretedLazy() && !JSFunction::getOrCreateScript(cx, fun))
return nullptr;
if (IsAsmJSModule(fun))
- return AsmJSModuleToString(cx, fun, !prettyPrint);
+ return AsmJSModuleToString(cx, fun, isToSource);
if (IsAsmJSFunction(fun))
return AsmJSFunctionToString(cx, fun);
if (IsWrappedAsyncFunction(fun)) {
RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
- return FunctionToString(cx, unwrapped, prettyPrint);
+ return FunctionToString(cx, unwrapped, isToSource);
}
if (IsWrappedAsyncGenerator(fun)) {
RootedFunction unwrapped(cx, GetUnwrappedAsyncGenerator(fun));
- return FunctionToString(cx, unwrapped, prettyPrint);
+ return FunctionToString(cx, unwrapped, isToSource);
}
StringBuffer out(cx);
@@ -975,8 +978,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
}
}
- bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow();
-
// Default class constructors are self-hosted, but have their source
// objects overridden to refer to the span of the class statement or
// expression. Non-default class constructors are never self-hosted. So,
@@ -984,12 +985,9 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
bool haveSource = fun->isInterpreted() && (fun->isClassConstructor() ||
!fun->isSelfHostedBuiltin());
- // If we're not in pretty mode, put parentheses around lambda functions
- // so that eval returns lambda, not function statement.
- if (haveSource && !prettyPrint && funIsNonArrowLambda) {
- if (!out.append("("))
- return nullptr;
- }
+ // If we're in toSource mode, put parentheses around lambda functions so
+ // that eval returns lambda, not function statement.
+ bool addParentheses = haveSource && isToSource && (fun->isLambda() && !fun->isArrow());
if (haveSource && !script->scriptSource()->hasSourceData() &&
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
@@ -997,85 +995,82 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
return nullptr;
}
- auto AppendPrelude = [&out, &fun]() {
+ if (addParentheses) {
+ if (!out.append('('))
+ return nullptr;
+ }
+
+ if (haveSource) {
+ Rooted<JSFlatString*> src(cx, JSScript::sourceDataForToString(cx, script));
+ if (!src)
+ return nullptr;
+
+ if (!out.append(src))
+ return nullptr;
+ } else {
if (fun->isAsync()) {
if (!out.append("async "))
- return false;
+ return nullptr;
}
if (!fun->isArrow()) {
if (!out.append("function"))
- return false;
+ return nullptr;
if (fun->isStarGenerator()) {
if (!out.append('*'))
- return false;
+ return nullptr;
}
}
if (fun->explicitName()) {
if (!out.append(' '))
- return false;
+ return nullptr;
+ if (fun->isBoundFunction() && !fun->hasBoundFunctionNamePrefix()) {
+ if (!out.append(cx->names().boundWithSpace))
+ return nullptr;
+ }
if (!out.append(fun->explicitName()))
- return false;
- }
- return true;
- };
-
- if (haveSource) {
- Rooted<JSFlatString*> src(cx, JSScript::sourceDataForToString(cx, script));
- if (!src)
- return nullptr;
-
- if (!out.append(src))
- return nullptr;
-
- if (!prettyPrint && funIsNonArrowLambda) {
- if (!out.append(")"))
return nullptr;
}
- } else if (fun->isInterpreted() &&
- (!fun->isSelfHostedBuiltin() ||
- fun->infallibleIsDefaultClassConstructor(cx)))
- {
- // Default class constructors should always haveSource except;
- //
- // 1. Source has been discarded for the whole compartment.
- //
- // 2. The source is marked as "lazy", i.e., retrieved on demand, and
- // the embedding has not provided a hook to retrieve sources.
- MOZ_ASSERT_IF(fun->infallibleIsDefaultClassConstructor(cx),
- !cx->runtime()->sourceHook ||
- !script->scriptSource()->sourceRetrievable() ||
- fun->compartment()->behaviors().discardSource());
- if (!AppendPrelude() ||
- !out.append("() {\n ") ||
- !out.append("[sourceless code]") ||
- !out.append("\n}"))
+
+ if (fun->isInterpreted() &&
+ (!fun->isSelfHostedBuiltin() ||
+ fun->infallibleIsDefaultClassConstructor(cx)))
{
- return nullptr;
+ // Default class constructors should always haveSource except;
+ //
+ // 1. Source has been discarded for the whole compartment.
+ //
+ // 2. The source is marked as "lazy", i.e., retrieved on demand, and
+ // the embedding has not provided a hook to retrieve sources.
+ MOZ_ASSERT_IF(fun->infallibleIsDefaultClassConstructor(cx),
+ !cx->runtime()->sourceHook ||
+ !script->scriptSource()->sourceRetrievable() ||
+ fun->compartment()->behaviors().discardSource());
+
+ if (!out.append("() {\n [sourceless code]\n}"))
+ return nullptr;
+ } else {
+ if (!out.append("() {\n [native code]\n}"))
+ return nullptr;
}
- } else {
-
- if (!AppendPrelude() ||
- !out.append("() {\n "))
- return nullptr;
-
- if (!out.append("[native code]"))
- return nullptr;
+ }
- if (!out.append("\n}"))
+ if (addParentheses) {
+ if (!out.append(')'))
return nullptr;
}
+
return out.finishString();
}
JSString*
-fun_toStringHelper(JSContext* cx, HandleObject obj, unsigned indent)
+fun_toStringHelper(JSContext* cx, HandleObject obj, bool isToSource)
{
if (!obj->is<JSFunction>()) {
if (JSFunToStringOp op = obj->getOpsFunToString())
- return op(cx, obj, indent);
+ return op(cx, obj, isToSource);
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_INCOMPATIBLE_PROTO,
@@ -1084,7 +1079,7 @@ fun_toStringHelper(JSContext* cx, HandleObject obj, unsigned indent)
}
RootedFunction fun(cx, &obj->as<JSFunction>());
- return FunctionToString(cx, fun, indent != JS_DONT_PRETTY_PRINT);
+ return FunctionToString(cx, fun, isToSource);
}
bool
@@ -1107,16 +1102,11 @@ js::fun_toString(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(IsFunctionObject(args.calleev()));
- uint32_t indent = 0;
-
- if (args.length() != 0 && !ToUint32(cx, args[0], &indent))
- return false;
-
RootedObject obj(cx, ToObject(cx, args.thisv()));
if (!obj)
return false;
- RootedString str(cx, fun_toStringHelper(cx, obj, indent));
+ JSString* str = fun_toStringHelper(cx, obj, /* isToSource = */ false);
if (!str)
return false;
@@ -1137,12 +1127,12 @@ fun_toSource(JSContext* cx, unsigned argc, Value* vp)
RootedString str(cx);
if (obj->isCallable())
- str = fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT);
+ str = fun_toStringHelper(cx, obj, /* isToSource = */ true);
else
str = ObjectToSource(cx, obj);
-
if (!str)
return false;
+
args.rval().setString(str);
return true;
}
@@ -1327,23 +1317,45 @@ JSFunction::getUnresolvedLength(JSContext* cx, HandleFunction fun, MutableHandle
return true;
}
-JSAtom*
-JSFunction::getUnresolvedName(JSContext* cx)
+/* static */ bool
+JSFunction::getUnresolvedName(JSContext* cx, HandleFunction fun, MutableHandleAtom v)
{
- MOZ_ASSERT(!IsInternalFunctionObject(*this));
- MOZ_ASSERT(!hasResolvedName());
+ MOZ_ASSERT(!IsInternalFunctionObject(*fun));
+ MOZ_ASSERT(!fun->hasResolvedName());
- if (isClassConstructor()) {
+ JSAtom* name = fun->explicitOrCompileTimeName();
+ 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(explicitOrCompileTimeName() != cx->names().empty);
+ MOZ_ASSERT(name != cx->names().empty);
// Unnamed class expressions should not get a .name property at all.
- return explicitOrCompileTimeName();
+ if (name)
+ v.set(name);
+ return true;
+ }
+
+ if (fun->isBoundFunction() && !fun->hasBoundFunctionNamePrefix()) {
+ // Bound functions are never unnamed.
+ MOZ_ASSERT(name);
+
+ if (name->length() > 0) {
+ StringBuffer sb(cx);
+ if (!sb.append(cx->names().boundWithSpace) || !sb.append(name))
+ return false;
+
+ name = sb.finishAtom();
+ if (!name)
+ return false;
+ } else {
+ name = cx->names().boundWithSpace;
+ }
+
+ fun->setPrefixedBoundFunctionName(name);
}
- return explicitOrCompileTimeName() != nullptr ? explicitOrCompileTimeName()
- : cx->names().empty;
+ v.set(name != nullptr ? name : cx->names().empty);
+ return true;
}
static const js::Value&