Bug 1606084 - ValueToSource should be able to handle wrapped objects. r=jwalden

Differential Revision: https://phabricator.services.mozilla.com/D60312

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Tom Schuster 2020-01-23 11:23:42 +00:00
parent 99f4d7d6d8
commit b464660235
5 changed files with 50 additions and 39 deletions

View File

@ -942,6 +942,7 @@ enum class ESClass {
Arguments,
Error,
BigInt,
Function, // Note: Only JSFunction objects.
/** None of the above. */
Other

View File

@ -1,29 +1,31 @@
// |jit-test| --disable-tosource
const TEST_CASES = [
[undefined, "(void 0)"],
[null, "null"],
[true, "true"],
[Symbol("abc"), `Symbol("abc")`],
[15, "15"],
[-0, "-0"],
["abc", `"abc"`],
[function a() { return 1; }, `(function a() { return 1; })`],
[[1, 2, 3], `[1, 2, 3]`],
[[1, {a: 0, b: 0}, 2], `[1, {a:0, b:0}, 2]`],
[{a: [1, 2, 3]}, `({a:[1, 2, 3]})`],
[new Error("msg", "file", 1), `(new Error("msg", "file", 1))`],
[new TypeError("msg", "file", 1), `(new TypeError("msg", "file", 1))`],
[new class X extends Error {
[`undefined`, "(void 0)"],
[`null`, "null"],
[`true`, "true"],
[`Symbol("abc")`, `Symbol("abc")`],
[`15`, "15"],
[`-0`, "-0"],
[`"abc"`, `"abc"`],
[`(function a() { return 1; })`, `(function a() { return 1; })`],
[`[1, 2, 3]`, `[1, 2, 3]`],
[`[1, {a: 0, b: 0}, 2]`, `[1, {a:0, b:0}, 2]`],
[`({a: [1, 2, 3]})`, `({a:[1, 2, 3]})`],
[`new Error("msg", "file", 1)`, `(new Error("msg", "file", 1))`],
[`new TypeError("msg", "file", 1)`, `(new TypeError("msg", "file", 1))`],
[`new class X extends Error {
constructor() {
super("msg", "file", 1);
this.name = "X";
}
}, `(new X("msg", "file", 1))`],
[/a(b)c/, `/a(b)c/`],
[/abc/gi, `/abc/gi`],
}`, `(new X("msg", "file", 1))`],
[`/a(b)c/`, `/a(b)c/`],
[`/abc/gi`, `/abc/gi`],
]
let g = newGlobal({newCompartment: true});
for (let [actual, expected] of TEST_CASES) {
assertEq(valueToSource(actual), expected);
assertEq(valueToSource(eval(actual)), expected);
assertEq(valueToSource(g.eval(actual)), expected);
}

View File

@ -302,6 +302,8 @@ JS_FRIEND_API bool js::GetBuiltinClass(JSContext* cx, HandleObject obj,
*cls = ESClass::Error;
} else if (obj->is<BigIntObject>()) {
*cls = ESClass::BigInt;
} else if (obj->is<JSFunction>()) {
*cls = ESClass::Function;
} else {
*cls = ESClass::Other;
}

View File

@ -1722,6 +1722,7 @@ bool JSStructuredCloneWriter::startWrite(HandleValue v) {
case ESClass::SetIterator:
case ESClass::Arguments:
case ESClass::Error:
case ESClass::Function:
break;
case ESClass::Other: {

View File

@ -12,12 +12,13 @@
#include <stdint.h> // uint32_t
#include "jsfriendapi.h" // CheckRecursionLimit
#include "jsfriendapi.h" // CheckRecursionLimit, GetBuiltinClass
#include "builtin/Array.h" // ArrayToSource
#include "builtin/Boolean.h" // BooleanToString
#include "builtin/Object.h" // ObjectToSource
#include "gc/Allocator.h" // CanGC
#include "js/Class.h" // ESClass
#include "js/Symbol.h" // SymbolCode, JS::WellKnownSymbolLimit
#include "js/TypeDecls.h" // Rooted{Function, Object, String, Value}, HandleValue, Latin1Char
#include "js/Utility.h" // UniqueChars
@ -27,9 +28,8 @@
#include "vm/ErrorObject.h" // ErrorObject, ErrorToSource
#include "vm/Interpreter.h" // Call
#include "vm/JSContext.h" // JSContext
#include "vm/JSFunction.h" // JSFunction, FunctionToString
#include "vm/JSFunction.h" // JSFunction, fun_toStringHelper
#include "vm/Printer.h" // QuoteString
#include "vm/RegExpObject.h" // RegExpObject
#include "vm/SelfHosting.h" // CallSelfHostedFunction
#include "vm/Stack.h" // FixedInvokeArgs
#include "vm/StringType.h" // NewStringCopy{N,Z}, ToString
@ -143,30 +143,35 @@ JSString* js::ValueToSource(JSContext* cx, HandleValue v) {
return ToString<CanGC>(cx, v);
}
if (obj->is<JSFunction>()) {
RootedFunction fun(cx, &obj->as<JSFunction>());
return FunctionToString(cx, fun, true);
ESClass cls;
if (!GetBuiltinClass(cx, obj, &cls)) {
return nullptr;
}
if (obj->is<ArrayObject>()) {
return ArrayToSource(cx, obj);
}
// All ToSource functions must be able to handle wrapped objects!
switch (cls) {
case ESClass::Function:
return fun_toStringHelper(cx, obj, true);
if (obj->is<ErrorObject>()) {
return ErrorToSource(cx, obj);
}
case ESClass::Array:
return ArrayToSource(cx, obj);
if (obj->is<RegExpObject>()) {
FixedInvokeArgs<0> args(cx);
RootedValue rval(cx);
if (!CallSelfHostedFunction(cx, cx->names().RegExpToString, v, args,
&rval)) {
return nullptr;
case ESClass::Error:
return ErrorToSource(cx, obj);
case ESClass::RegExp: {
FixedInvokeArgs<0> args(cx);
RootedValue rval(cx);
if (!CallSelfHostedFunction(cx, cx->names().RegExpToString, v, args,
&rval)) {
return nullptr;
}
return ToString<CanGC>(cx, rval);
}
return ToString<CanGC>(cx, rval);
}
return ObjectToSource(cx, obj);
default:
return ObjectToSource(cx, obj);
}
}
case JS::ValueType::PrivateGCThing: