Skip to content

Commit

Permalink
Bug 1606084 - ValueToSource should be able to handle wrapped objects.…
Browse files Browse the repository at this point in the history
… r=jwalden

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

--HG--
extra : moz-landing-system : lando
  • Loading branch information
evilpie committed Jan 23, 2020
1 parent 99f4d7d commit b464660
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 41 deletions.
1 change: 1 addition & 0 deletions js/public/Class.h
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,7 @@ enum class ESClass {
Arguments,
Error,
BigInt,
Function, // Note: Only JSFunction objects.

/** None of the above. */
Other
Expand Down
38 changes: 20 additions & 18 deletions js/src/jit-test/tests/basic/valuetosource.js
Original file line number Diff line number Diff line change
@@ -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);
}
2 changes: 2 additions & 0 deletions js/src/jsfriendapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions js/src/vm/StructuredClone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
51 changes: 28 additions & 23 deletions js/src/vm/ToSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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);
}

if (obj->is<ArrayObject>()) {
return ArrayToSource(cx, obj);
}

if (obj->is<ErrorObject>()) {
return ErrorToSource(cx, obj);
ESClass cls;
if (!GetBuiltinClass(cx, obj, &cls)) {
return nullptr;
}

if (obj->is<RegExpObject>()) {
FixedInvokeArgs<0> args(cx);
RootedValue rval(cx);
if (!CallSelfHostedFunction(cx, cx->names().RegExpToString, v, args,
&rval)) {
return nullptr;
// All ToSource functions must be able to handle wrapped objects!
switch (cls) {
case ESClass::Function:
return fun_toStringHelper(cx, obj, true);

case ESClass::Array:
return ArrayToSource(cx, obj);

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:
Expand Down

0 comments on commit b464660

Please sign in to comment.