зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1659104 - Part 4 - Shell and testing functions for Stencil XDR. r=tcampbell
Differential Revision: https://phabricator.services.mozilla.com/D90513
This commit is contained in:
Родитель
d775f14cc9
Коммит
a404783ac7
|
@ -43,6 +43,8 @@
|
|||
#ifdef DEBUG
|
||||
# include "frontend/TokenStream.h"
|
||||
#endif
|
||||
#include "frontend/BytecodeCompilation.h"
|
||||
#include "frontend/CompilationInfo.h"
|
||||
#include "gc/Allocator.h"
|
||||
#include "gc/Zone.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
|
@ -100,6 +102,7 @@
|
|||
#include "vm/PromiseObject.h" // js::PromiseObject, js::PromiseSlot_*
|
||||
#include "vm/ProxyObject.h"
|
||||
#include "vm/SavedStacks.h"
|
||||
#include "vm/ScopeKind.h"
|
||||
#include "vm/Stack.h"
|
||||
#include "vm/StringType.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
@ -4872,6 +4875,124 @@ static bool SetLazyParsingDisabled(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool CompileStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!args.requireAtLeast(cx, "compileStencilXDR", 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedString src(cx, ToString<CanGC>(cx, args[0]));
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: Retrieve these from an optional `config` object. */
|
||||
const char* filename = "compileStencilXDR-DATA.js";
|
||||
uint32_t lineno = 1;
|
||||
|
||||
/* Linearize the string to obtain a char16_t* range. */
|
||||
AutoStableStringChars linearChars(cx);
|
||||
if (!linearChars.initTwoByte(cx, src)) {
|
||||
return false;
|
||||
}
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, linearChars.twoByteChars(), src->length(),
|
||||
JS::SourceOwnership::Borrowed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Compile the script text to stencil. */
|
||||
CompileOptions options(cx);
|
||||
options.setFileAndLine(filename, lineno);
|
||||
|
||||
/* TODO: StencilXDR - Add option to select between full and syntax parse. */
|
||||
options.setForceFullParse();
|
||||
|
||||
Rooted<frontend::CompilationInfo> compilationInfo(
|
||||
cx, frontend::CompilationInfo(cx, options));
|
||||
if (!compilationInfo.get().input.initForGlobal(cx)) {
|
||||
return false;
|
||||
}
|
||||
if (!frontend::CompileGlobalScriptToStencil(cx, compilationInfo.get(), srcBuf,
|
||||
ScopeKind::Global)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Serialize the stencil to XDR. */
|
||||
JS::TranscodeBuffer xdrBytes;
|
||||
if (!compilationInfo.get().serializeStencils(cx, xdrBytes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Dump the bytes into a javascript ArrayBuffer and return a UInt8Array. */
|
||||
RootedObject arrayBuf(cx, JS::NewArrayBuffer(cx, xdrBytes.length()));
|
||||
if (!arrayBuf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
JS::AutoAssertNoGC nogc;
|
||||
bool isSharedMemory = false;
|
||||
uint8_t* data = JS::GetArrayBufferData(arrayBuf, &isSharedMemory, nogc);
|
||||
std::copy(xdrBytes.begin(), xdrBytes.end(), data);
|
||||
}
|
||||
|
||||
args.rval().setObject(*arrayBuf);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool EvalStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!args.requireAtLeast(cx, "evalStencilXDR", 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Prepare the input byte array. */
|
||||
if (!args[0].isObject() || !args[0].toObject().is<ArrayBufferObject>()) {
|
||||
JS_ReportErrorASCII(cx, "evalStencilXDR: ArrayBuffer expected");
|
||||
return false;
|
||||
}
|
||||
RootedArrayBufferObject src(cx, &args[0].toObject().as<ArrayBufferObject>());
|
||||
|
||||
const char* filename = "compileStencilXDR-DATA.js";
|
||||
uint32_t lineno = 1;
|
||||
|
||||
/* Prepare the CompilationInfo for decoding. */
|
||||
CompileOptions options(cx);
|
||||
options.setFileAndLine(filename, lineno);
|
||||
options.setForceFullParse();
|
||||
|
||||
Rooted<frontend::CompilationInfo> compilationInfo(
|
||||
cx, frontend::CompilationInfo(cx, options));
|
||||
if (!compilationInfo.get().input.initForGlobal(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Deserialize the stencil from XDR. */
|
||||
JS::TranscodeRange xdrRange(src->dataPointer(), src->byteLength());
|
||||
if (!compilationInfo.get().deserializeStencils(cx, xdrRange)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Instantiate the stencil. */
|
||||
frontend::CompilationGCOutput output(cx);
|
||||
if (!compilationInfo.get().instantiateStencils(cx, output)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Obtain the JSScript and evaluate it. */
|
||||
RootedScript script(cx, output.script);
|
||||
RootedValue retVal(cx, UndefinedValue());
|
||||
if (!JS_ExecuteScript(cx, script, &retVal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().set(retVal);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SetDiscardSource(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
|
@ -7188,6 +7309,16 @@ JS_FN_HELP("setDefaultLocale", SetDefaultLocale, 1, 0,
|
|||
" An empty string or undefined resets the runtime locale to its default value.\n"
|
||||
" NOTE: The input string is not fully validated, it must be a valid BCP-47 language tag."),
|
||||
|
||||
JS_FN_HELP("compileStencilXDR", CompileStencilXDR, 1, 0,
|
||||
"compileStencilXDR(string)",
|
||||
" Parses the given string argument as js script, produces the stencil"
|
||||
" for it, XDR-encodes the stencil, and returns an ArrayBuf of the contents."),
|
||||
|
||||
JS_FN_HELP("evalStencilXDR", EvalStencilXDR, 1, 0,
|
||||
"evalStencilXDR(arrayBuf)",
|
||||
" Reads the given buffer as an XDR-encoded stencil, and evaluates the"
|
||||
" top-level script it defines."),
|
||||
|
||||
JS_FS_HELP_END
|
||||
};
|
||||
// clang-format on
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
/*
|
||||
* This exercises stencil XDR encoding and decoding using a broad
|
||||
* smoke testing.
|
||||
*
|
||||
* A set of scripts exercising various codepaths are XDR-encoded,
|
||||
* then decoded, and then executed. Their output is compared to
|
||||
* the execution of the scripts through a normal path and the
|
||||
* outputs checked.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Exercises global scope access and object literals, as well as some
|
||||
* simple object destructuring.
|
||||
*/
|
||||
const testGlobal0 = 13;
|
||||
let testGlobal1 = undefined;
|
||||
var testGlobal2 = undefined;
|
||||
|
||||
const SCRIPT_0 = `
|
||||
testGlobal1 = 123456789012345678901234567890n;
|
||||
testGlobal2 = {'foo':3, 'bar': [1, 2, 3],
|
||||
'4': 'zing'};
|
||||
var testGlobal3 = /NewlyDefinedGlobal/;
|
||||
function testGlobal4(a, {b}) {
|
||||
return a + b.foo + b['bar'].reduce((a,b) => (a+b), 0);
|
||||
+ b[4].length +
|
||||
+ testGlobal3.toString().length;
|
||||
};
|
||||
testGlobal4(Number(testGlobal1), {b:testGlobal2})
|
||||
`;
|
||||
|
||||
/*
|
||||
* Exercises function scopes, lexical scopes, var and let
|
||||
* within them, and some longer identifiers, and array destructuring in
|
||||
* arguments. Also contains some tiny atoms and globls access.
|
||||
*/
|
||||
const SCRIPT_1 = `
|
||||
function foo(a, b, c) {
|
||||
var q = a * (b + c);
|
||||
let bix = function (d, e) {
|
||||
let x = a + d;
|
||||
var y = e * b;
|
||||
const a0 = q + x + y;
|
||||
for (let i = 0; i < 3; i++) {
|
||||
y = a0 + Math.PI + y;
|
||||
}
|
||||
return y;
|
||||
};
|
||||
function bang(d, [e, f]) {
|
||||
let reallyLongIdentifierName = a + d;
|
||||
var y = e * b;
|
||||
const z = reallyLongIdentifierName + f;
|
||||
return z;
|
||||
}
|
||||
return bix(1, 2) + bang(3, [4, 5, 6]);
|
||||
}
|
||||
foo(1, 2, 3)
|
||||
`;
|
||||
|
||||
/*
|
||||
* Exercises eval and with scopes, object destructuring, function rest
|
||||
* arguments.
|
||||
*/
|
||||
const SCRIPT_2 = `
|
||||
function foo(with_obj, ...xs) {
|
||||
const [x0, x1, ...xrest] = xs;
|
||||
eval('var x2 = x0 + x1');
|
||||
var sum = [];
|
||||
with (with_obj) {
|
||||
sum.push(x2 + xrest.length);
|
||||
}
|
||||
sum.push(x2 + xrest.length);
|
||||
return sum;
|
||||
}
|
||||
foo({x2: 99}, 1, 2, 3, 4, 5, 6)
|
||||
`;
|
||||
|
||||
function test_script(script_str) {
|
||||
const eval_f = eval;
|
||||
const bytes = compileStencilXDR(script_str);
|
||||
const result = evalStencilXDR(bytes);
|
||||
assertDeepEq(result, eval_f(script_str));
|
||||
}
|
||||
|
||||
function tests() {
|
||||
test_script(SCRIPT_0);
|
||||
test_script(SCRIPT_1);
|
||||
test_script(SCRIPT_2);
|
||||
}
|
||||
|
||||
tests()
|
Загрузка…
Ссылка в новой задаче