mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 16:58:38 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
15c528d694
28 changed files with 210 additions and 175 deletions
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
15
js/src/jit-test/tests/basic/bug1380962.js
Normal file
15
js/src/jit-test/tests/basic/bug1380962.js
Normal 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})");
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
196
js/src/jsfun.cpp
196
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,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&
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue