Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2022-07-03 06:56:10 +08:00
commit 15c528d694
28 changed files with 210 additions and 175 deletions

View file

@ -682,7 +682,7 @@ DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
// funToString ObjectOps member for interface objects.
JSString*
InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
unsigned /* indent */)
bool /* isToSource */)
{
const js::Class* clasp = js::GetObjectClass(aObject);
MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));

View file

@ -459,7 +459,7 @@ typedef bool
* that object. A null return value means OOM.
*/
typedef JSString*
(* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, unsigned indent);
(* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, bool isToSource);
/**
* Resolve a lazy property named by id in obj by defining it directly in obj.

View file

@ -326,7 +326,7 @@ class JS_FRIEND_API(BaseProxyHandler)
ESClass* cls) const;
virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const;
virtual const char* className(JSContext* cx, HandleObject proxy) const;
virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const;
virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, bool isToSource) const;
virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const;
virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const;
virtual void trace(JSTracer* trc, JSObject* proxy) const;

View file

@ -0,0 +1,15 @@
// Source string has balanced parentheses even when the source code was discarded.
setDiscardSource(true);
eval("var f = function() { return 0; };");
assertEq(f.toSource(), "(function() {\n [sourceless code]\n})");
// Source string has balanced parentheses even when the source code was discarded.
setDiscardSource(true);
eval("var f = function() { return 0; };");
assertEq(f.toSource(), "(function() {\n [sourceless code]\n})");
// Source string has balanced parentheses even when the source code was discarded.
setDiscardSource(true);
eval("var f = function() { return 0; };");
assertEq(f.toSource(), "(function() {\n [sourceless code]\n})");

View file

@ -3,12 +3,7 @@ var functionProxy = new Proxy(function() {}, {});
assertEq(Object.prototype.toString.call(objectProxy), '[object Object]');
assertEq(Object.prototype.toString.call(functionProxy), '[object Function]');
try {
Function.prototype.toString.call(functionProxy);
assertEq(true, false);
} catch (e) {
assertEq(!!/incompatible/.exec(e), true);
}
try {
Function.prototype.toString.call(objectProxy);
assertEq(true, false);

View file

@ -1,10 +1,10 @@
load(libdir + 'asserts.js');
// Function.prototype.toString doesn't accept ES6 proxies.
var nativeCode = "function () {\n [native code]\n}";
var proxy = new Proxy(function() {}, {});
assertThrowsInstanceOf(() => Function.prototype.toString.call(proxy), TypeError);
assertEq(Function.prototype.toString.call(proxy), nativeCode);
var o = Proxy.revocable(function() {}, {});
assertThrowsInstanceOf(() => Function.prototype.toString.call(o.proxy), TypeError);
assertEq(Function.prototype.toString.call(o.proxy), nativeCode);
o.revoke();
assertThrowsInstanceOf(() => Function.prototype.toString.call(o.proxy), TypeError);
assertEq(Function.prototype.toString.call(o.proxy), nativeCode);

View file

@ -115,7 +115,7 @@ BEGIN_TEST(testXDR_source)
CHECK(script);
script = FreezeThaw(cx, script);
CHECK(script);
JSString* out = JS_DecompileScript(cx, script, "testing", 0);
JSString* out = JS_DecompileScript(cx, script);
CHECK(out);
bool equal;
CHECK(JS_StringEqualsAscii(cx, out, *s, &equal));

View file

@ -4438,7 +4438,7 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
}
JS_PUBLIC_API(JSString*)
JS_DecompileScript(JSContext* cx, HandleScript script, const char* name, unsigned indent)
JS_DecompileScript(JSContext* cx, HandleScript script)
{
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
@ -4447,7 +4447,7 @@ JS_DecompileScript(JSContext* cx, HandleScript script, const char* name, unsigne
script->ensureNonLazyCanonicalFunction();
RootedFunction fun(cx, script->functionNonDelazifying());
if (fun)
return JS_DecompileFunction(cx, fun, indent);
return JS_DecompileFunction(cx, fun);
bool haveSource = script->scriptSource()->hasSourceData();
if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
return nullptr;
@ -4456,13 +4456,13 @@ JS_DecompileScript(JSContext* cx, HandleScript script, const char* name, unsigne
}
JS_PUBLIC_API(JSString*)
JS_DecompileFunction(JSContext* cx, HandleFunction fun, unsigned indent)
JS_DecompileFunction(JSContext* cx, HandleFunction fun)
{
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, fun);
return FunctionToString(cx, fun, !(indent & JS_DONT_PRETTY_PRINT));
return FunctionToString(cx, fun, /* isToSource = */ false);
}
MOZ_NEVER_INLINE static bool

View file

@ -4200,16 +4200,10 @@ CompileFunction(JSContext* cx, AutoObjectVector& envChain,
} /* namespace JS */
extern JS_PUBLIC_API(JSString*)
JS_DecompileScript(JSContext* cx, JS::Handle<JSScript*> script, const char* name, unsigned indent);
/*
* API extension: OR this into indent to avoid pretty-printing the decompiled
* source resulting from JS_DecompileFunction.
*/
#define JS_DONT_PRETTY_PRINT ((unsigned)0x8000)
JS_DecompileScript(JSContext* cx, JS::Handle<JSScript*> script);
extern JS_PUBLIC_API(JSString*)
JS_DecompileFunction(JSContext* cx, JS::Handle<JSFunction*> fun, unsigned indent);
JS_DecompileFunction(JSContext* cx, JS::Handle<JSFunction*> fun);
/*

View file

@ -377,7 +377,7 @@ extern JS_FRIEND_API(bool)
proxy_GetElements(JSContext* cx, JS::HandleObject proxy, uint32_t begin, uint32_t end,
ElementAdder* adder);
extern JS_FRIEND_API(JSString*)
proxy_FunToString(JSContext* cx, JS::HandleObject proxy, unsigned indent);
proxy_FunToString(JSContext* cx, JS::HandleObject proxy, bool isToSource);
/**
* A class of objects that return source code on demand.

View file

@ -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,30 +995,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
return nullptr;
}
auto AppendPrelude = [&out, &fun]() {
if (fun->isAsync()) {
if (!out.append("async "))
return false;
}
if (!fun->isArrow()) {
if (!out.append("function"))
return false;
if (fun->isStarGenerator()) {
if (!out.append('*'))
return false;
}
}
if (fun->explicitName()) {
if (!out.append(' '))
return false;
if (!out.append(fun->explicitName()))
return false;
}
return true;
};
if (addParentheses) {
if (!out.append('('))
return nullptr;
}
if (haveSource) {
Rooted<JSFlatString*> src(cx, JSScript::sourceDataForToString(cx, script));
@ -1029,53 +1007,70 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
if (!out.append(src))
return nullptr;
if (!prettyPrint && funIsNonArrowLambda) {
if (!out.append(")"))
} else {
if (fun->isAsync()) {
if (!out.append("async "))
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}"))
{
return nullptr;
if (!fun->isArrow()) {
if (!out.append("function"))
return nullptr;
if (fun->isStarGenerator()) {
if (!out.append('*'))
return nullptr;
}
}
} else {
if (!AppendPrelude() ||
!out.append("() {\n "))
return nullptr;
if (fun->explicitName()) {
if (!out.append(' '))
return nullptr;
if (fun->isBoundFunction() && !fun->hasBoundFunctionNamePrefix()) {
if (!out.append(cx->names().boundWithSpace))
return nullptr;
}
if (!out.append(fun->explicitName()))
return nullptr;
}
if (!out.append("[native code]"))
return nullptr;
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 (!out.append("\n}"))
if (!out.append("() {\n [sourceless code]\n}"))
return nullptr;
} else {
if (!out.append("() {\n [native code]\n}"))
return nullptr;
}
}
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;
}
return explicitOrCompileTimeName() != nullptr ? explicitOrCompileTimeName()
: cx->names().empty;
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);
}
v.set(name != nullptr ? name : cx->names().empty);
return true;
}
static const js::Value&

View file

@ -59,6 +59,9 @@ class JSFunction : public js::NativeObject
BOUND_FUN = 0x0008, /* function was created with Function.prototype.bind. */
HAS_GUESSED_ATOM = 0x0020, /* function had no explicit name, but a
name was guessed for it anyway */
HAS_BOUND_FUNCTION_NAME_PREFIX = 0x0020, /* bound functions reuse the HAS_GUESSED_ATOM
flag to track if atom_ already contains the
"bound " function name prefix */
LAMBDA = 0x0040, /* function comes from a FunctionExpression, ArrowFunction, or
Function() call (not a FunctionDeclaration or nonstandard
function-statement) */
@ -99,8 +102,8 @@ class JSFunction : public js::NativeObject
INTERPRETED_GENERATOR_OR_ASYNC = INTERPRETED,
NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
STABLE_ACROSS_CLONES = CONSTRUCTOR | HAS_GUESSED_ATOM | LAMBDA |
SELF_HOSTED | HAS_COMPILE_TIME_NAME | FUNCTION_KIND_MASK
STABLE_ACROSS_CLONES = CONSTRUCTOR | LAMBDA | SELF_HOSTED | HAS_COMPILE_TIME_NAME |
FUNCTION_KIND_MASK
};
static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS,
@ -186,10 +189,20 @@ class JSFunction : public js::NativeObject
bool isAsmJSNative() const { return kind() == AsmJS; }
/* Possible attributes of an interpreted function: */
bool hasCompileTimeName() const { return flags() & HAS_COMPILE_TIME_NAME; }
bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; }
bool isLambda() const { return flags() & LAMBDA; }
bool isBoundFunction() const { return flags() & BOUND_FUN; }
bool hasCompileTimeName() const { return flags() & HAS_COMPILE_TIME_NAME; }
bool hasGuessedAtom() const {
static_assert(HAS_GUESSED_ATOM == HAS_BOUND_FUNCTION_NAME_PREFIX,
"HAS_GUESSED_ATOM is unused for bound functions");
return (flags() & (HAS_GUESSED_ATOM | BOUND_FUN)) == HAS_GUESSED_ATOM;
}
bool hasBoundFunctionNamePrefix() const {
static_assert(HAS_BOUND_FUNCTION_NAME_PREFIX == HAS_GUESSED_ATOM,
"HAS_BOUND_FUNCTION_NAME_PREFIX is only used for bound functions");
MOZ_ASSERT(isBoundFunction());
return flags() & HAS_BOUND_FUNCTION_NAME_PREFIX;
}
bool isLambda() const { return flags() & LAMBDA; }
bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; }
bool hasScript() const { return flags() & INTERPRETED; }
@ -310,7 +323,8 @@ class JSFunction : public js::NativeObject
static bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun,
js::MutableHandleValue v);
JSAtom* getUnresolvedName(JSContext* cx);
static bool getUnresolvedName(JSContext* cx, js::HandleFunction fun,
js::MutableHandleAtom v);
JSAtom* explicitName() const {
return (hasCompileTimeName() || hasGuessedAtom()) ? nullptr : atom_.get();
@ -346,16 +360,26 @@ class JSFunction : public js::NativeObject
MOZ_ASSERT(atom);
MOZ_ASSERT(!hasCompileTimeName());
MOZ_ASSERT(!hasGuessedAtom());
MOZ_ASSERT(!isBoundFunction());
MOZ_ASSERT(js::AtomIsMarked(zone(), atom));
atom_ = atom;
flags_ |= HAS_GUESSED_ATOM;
}
void clearGuessedAtom() {
MOZ_ASSERT(hasGuessedAtom());
MOZ_ASSERT(!isBoundFunction());
MOZ_ASSERT(atom_);
atom_ = nullptr;
flags_ &= ~HAS_GUESSED_ATOM;
}
void setPrefixedBoundFunctionName(JSAtom* atom) {
MOZ_ASSERT(!hasBoundFunctionNamePrefix());
MOZ_ASSERT(atom);
flags_ |= HAS_BOUND_FUNCTION_NAME_PREFIX;
atom_ = atom;
}
/* uint16_t representation bounds number of call object dynamic slots. */
enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
@ -646,7 +670,7 @@ static_assert(sizeof(JSFunction) == sizeof(js::shadow::Function),
"shadow interface must match actual interface");
extern JSString*
fun_toStringHelper(JSContext* cx, js::HandleObject obj, unsigned indent);
fun_toStringHelper(JSContext* cx, js::HandleObject obj, bool isToSource);
namespace js {
@ -851,7 +875,7 @@ JSFunction::getExtendedSlot(size_t which) const
namespace js {
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPring);
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource);
template<XDRMode mode>
bool

View file

@ -863,7 +863,7 @@ ToDisassemblySource(JSContext* cx, HandleValue v, JSAutoByteString* bytes)
if (obj.is<JSFunction>()) {
RootedFunction fun(cx, &obj.as<JSFunction>());
JSString* str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
JSString* str = JS_DecompileFunction(cx, fun);
if (!str)
return false;
return bytes->encodeLatin1(cx, str);
@ -1972,7 +1972,7 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf)
if (!AppendJSONProperty(buf, "text", NO_COMMA))
return false;
JSString* str = JS_DecompileScript(cx, script, nullptr, 0);
JSString* str = JS_DecompileScript(cx, script);
if (!str || !(str = StringToSource(cx, str)))
return false;

View file

@ -115,7 +115,7 @@ class JS_FRIEND_API(Wrapper) : public BaseProxyHandler
JS::IsArrayAnswer* answer) const override;
virtual const char* className(JSContext* cx, HandleObject proxy) const override;
virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
unsigned indent) const override;
bool isToSource) const override;
virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
RegExpGuard* g) const override;
virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
@ -210,7 +210,7 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
bool* bp) const override;
virtual const char* className(JSContext* cx, HandleObject proxy) const override;
virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
unsigned indent) const override;
bool isToSource) const override;
virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override;
virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override;
@ -272,7 +272,8 @@ class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrap
virtual bool hasInstance(JSContext* cx, HandleObject wrapper,
MutableHandleValue v, bool* bp) const override;
virtual const char* className(JSContext* cx, HandleObject wrapper) const override;
virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override;
virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
bool isToSource) const override;
static const OpaqueCrossCompartmentWrapper singleton;
};

View file

@ -315,12 +315,13 @@ BaseProxyHandler::className(JSContext* cx, HandleObject proxy) const
}
JSString*
BaseProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
BaseProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource) const
{
if (proxy->isCallable())
return JS_NewStringCopyZ(cx, "function () {\n [native code]\n}");
RootedValue v(cx, ObjectValue(*proxy));
ReportIsNotFunction(cx, v);
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
js_Function_str, js_toString_str, "object");
return nullptr;
}

View file

@ -422,12 +422,12 @@ CrossCompartmentWrapper::className(JSContext* cx, HandleObject wrapper) const
}
JSString*
CrossCompartmentWrapper::fun_toString(JSContext* cx, HandleObject wrapper, unsigned indent) const
CrossCompartmentWrapper::fun_toString(JSContext* cx, HandleObject wrapper, bool isToSource) const
{
RootedString str(cx);
{
AutoCompartment call(cx, wrappedObject(wrapper));
str = Wrapper::fun_toString(cx, wrapper, indent);
str = Wrapper::fun_toString(cx, wrapper, isToSource);
if (!str)
return nullptr;
}

View file

@ -135,7 +135,7 @@ DeadObjectProxy::className(JSContext* cx, HandleObject wrapper) const
}
JSString*
DeadObjectProxy::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
DeadObjectProxy::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource) const
{
ReportDead(cx);
return nullptr;

View file

@ -47,7 +47,8 @@ class DeadObjectProxy : public BaseProxyHandler
virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const override;
virtual const char* className(JSContext* cx, HandleObject proxy) const override;
virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override;
virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
bool isToSource) const override;
virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override;
virtual bool isCallable(JSObject* obj) const override;

View file

@ -191,7 +191,7 @@ OpaqueCrossCompartmentWrapper::className(JSContext* cx,
JSString*
OpaqueCrossCompartmentWrapper::fun_toString(JSContext* cx, HandleObject proxy,
unsigned indent) const
bool isToSource) const
{
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
js_Function_str, js_toString_str, "object");

View file

@ -475,7 +475,7 @@ Proxy::className(JSContext* cx, HandleObject proxy)
}
JSString*
Proxy::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent)
Proxy::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource)
{
JS_CHECK_RECURSION(cx, return nullptr);
const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
@ -483,8 +483,8 @@ Proxy::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent)
BaseProxyHandler::GET, /* mayThrow = */ false);
// Do the safe thing if the policy rejects.
if (!policy.allowed())
return handler->BaseProxyHandler::fun_toString(cx, proxy, indent);
return handler->fun_toString(cx, proxy, indent);
return handler->BaseProxyHandler::fun_toString(cx, proxy, isToSource);
return handler->fun_toString(cx, proxy, isToSource);
}
bool
@ -691,9 +691,9 @@ js::proxy_GetElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_
}
JSString*
js::proxy_FunToString(JSContext* cx, HandleObject proxy, unsigned indent)
js::proxy_FunToString(JSContext* cx, HandleObject proxy, bool isToSource)
{
return Proxy::fun_toString(cx, proxy, indent);
return Proxy::fun_toString(cx, proxy, isToSource);
}
const ClassOps js::ProxyClassOps = {

View file

@ -60,7 +60,7 @@ class Proxy
static bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls);
static bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer);
static const char* className(JSContext* cx, HandleObject proxy);
static JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent);
static JSString* fun_toString(JSContext* cx, HandleObject proxy, bool isToSource);
static bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g);
static bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp);

View file

@ -1257,11 +1257,11 @@ ScriptedProxyHandler::className(JSContext* cx, HandleObject proxy) const
}
JSString*
ScriptedProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
ScriptedProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource) const
{
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
js_Function_str, js_toString_str, "object");
return nullptr;
// The BaseProxyHandler has the desired behavior: Throw for non-callable,
// otherwise return [native code].
return BaseProxyHandler::fun_toString(cx, proxy, isToSource);
}
bool

View file

@ -67,7 +67,7 @@ class ScriptedProxyHandler : public BaseProxyHandler
JS::IsArrayAnswer* answer) const override;
virtual const char* className(JSContext* cx, HandleObject proxy) const override;
virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
unsigned indent) const override;
bool isToSource) const override;
virtual bool regexp_toShared(JSContext* cx, HandleObject proxy,
RegExpGuard* g) const override;
virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,

View file

@ -259,11 +259,11 @@ Wrapper::className(JSContext* cx, HandleObject proxy) const
}
JSString*
Wrapper::fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const
Wrapper::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return fun_toStringHelper(cx, target, indent);
return fun_toStringHelper(cx, target, isToSource);
}
bool

View file

@ -4577,7 +4577,7 @@ DecompileFunction(JSContext* cx, unsigned argc, Value* vp)
return true;
}
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
JSString* result = JS_DecompileFunction(cx, fun, 0);
JSString* result = JS_DecompileFunction(cx, fun);
if (!result)
return false;
args.rval().setString(result);
@ -4599,7 +4599,7 @@ DecompileThisScript(JSContext* cx, unsigned argc, Value* vp)
JSAutoCompartment ac(cx, iter.script());
RootedScript script(cx, iter.script());
JSString* result = JS_DecompileScript(cx, script, "test", 0);
JSString* result = JS_DecompileScript(cx, script);
if (!result)
return false;

View file

@ -571,39 +571,31 @@ intrinsic_FinishBoundFunctionInit(JSContext* cx, unsigned argc, Value* vp)
bound->setExtendedSlot(BOUND_FUN_LENGTH_SLOT, NumberValue(length));
// Try to avoid invoking the resolve hook.
JSAtom* name = nullptr;
if (targetObj->is<JSFunction>() && !targetObj->as<JSFunction>().hasResolvedName())
name = targetObj->as<JSFunction>().getUnresolvedName(cx);
RootedAtom name(cx);
if (targetObj->is<JSFunction>() && !targetObj->as<JSFunction>().hasResolvedName()) {
if (!JSFunction::getUnresolvedName(cx, targetObj.as<JSFunction>(), &name))
return false;
}
RootedString rootedName(cx);
if (name) {
rootedName = name;
} else {
// 19.2.3.2 Function.prototype.bind, steps 9-11.
if (!name) {
// 19.2.3.2 Function.prototype.bind, step 9.
RootedValue targetName(cx);
if (!GetProperty(cx, targetObj, targetObj, cx->names().name, &targetName))
return false;
// 19.2.3.2 Function.prototype.bind, step 10.
if (targetName.isString())
rootedName = targetName.toString();
if (targetName.isString() && !targetName.toString()->empty()) {
name = AtomizeString(cx, targetName.toString());
if (!name)
return false;
} else {
name = cx->names().empty;
}
}
// 19.2.3.2 Function.prototype.bind, step 11 (Inlined SetFunctionName).
MOZ_ASSERT(!bound->hasGuessedAtom());
if (rootedName && !rootedName->empty()) {
StringBuffer sb(cx);
if (!sb.append(cx->names().boundWithSpace) || !sb.append(rootedName))
return false;
RootedAtom nameAtom(cx, sb.finishAtom());
if (!nameAtom)
return false;
bound->setAtom(nameAtom);
} else {
bound->setAtom(cx->names().boundWithSpace);
}
bound->setAtom(name);
args.rval().setUndefined();
return true;

View file

@ -8849,7 +8849,7 @@ js::IsAsmJSModuleLoadedFromCache(JSContext* cx, unsigned argc, Value* vp)
// asm.js toString/toSource support
JSString*
js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda)
js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool isToSource)
{
MOZ_ASSERT(IsAsmJSModule(fun));
@ -8860,7 +8860,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
StringBuffer out(cx);
if (addParenToLambda && fun->isLambda() && !out.append("("))
if (isToSource && fun->isLambda() && !out.append("("))
return nullptr;
bool haveSource = source->hasSourceData();
@ -8883,7 +8883,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda
return nullptr;
}
if (addParenToLambda && fun->isLambda() && !out.append(")"))
if (isToSource && fun->isLambda() && !out.append(")"))
return nullptr;
return out.finishString();

View file

@ -76,7 +76,7 @@ extern JSString*
AsmJSFunctionToString(JSContext* cx, HandleFunction fun);
extern JSString*
AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda);
AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool isToSource);
// asm.js heap: