зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 2 changesets (bug 1447591) for mochitest failures at dom/base/test/test_postMessages.html
Backed out changeset 0800fdb509d2 (bug 1447591) Backed out changeset 9b5347dee1f2 (bug 1447591)
This commit is contained in:
Родитель
0004f1c6ae
Коммит
e555bb0ae4
|
@ -792,10 +792,8 @@ const SourceActor = ActorClassWithSpec(sourceSpec, {
|
|||
|
||||
if (!this.isSourceMapped) {
|
||||
const generatedLocation = GeneratedLocation.fromOriginalLocation(originalLocation);
|
||||
const isWasm = this.source && this.source.introductionType === "wasm";
|
||||
if (!this._setBreakpointAtGeneratedLocation(actor, generatedLocation) &&
|
||||
!noSliding &&
|
||||
!isWasm) {
|
||||
!noSliding) {
|
||||
const query = { line: originalLine };
|
||||
// For most cases, we have a real source to query for. The
|
||||
// only time we don't is for HTML pages. In that case we want
|
||||
|
|
|
@ -26,10 +26,7 @@ function run_test() {
|
|||
gClient, "test-stack",
|
||||
function(response, tabClient, threadClient) {
|
||||
gThreadClient = threadClient;
|
||||
gThreadClient.reconfigure({
|
||||
observeAsmJS: true,
|
||||
wasmBinarySource: true
|
||||
}, function(response) {
|
||||
gThreadClient.reconfigure({ observeAsmJS: true }, function(response) {
|
||||
Assert.equal(!!response.error, false);
|
||||
test_pause_frame();
|
||||
});
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#include "vm/StringType.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
#include "wasm/AsmJS.h"
|
||||
#include "wasm/WasmBinaryToText.h"
|
||||
#include "wasm/WasmJS.h"
|
||||
#include "wasm/WasmModule.h"
|
||||
#include "wasm/WasmSignalHandlers.h"
|
||||
|
@ -658,61 +659,90 @@ WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!twoByteChars.initTwoByte(cx, args[0].toString()))
|
||||
return false;
|
||||
|
||||
bool withOffsets = false;
|
||||
if (args.hasDefined(1)) {
|
||||
if (!args[1].isBoolean()) {
|
||||
ReportUsageErrorASCII(cx, callee, "Second argument, if present, must be a boolean");
|
||||
if (!args[1].isString()) {
|
||||
ReportUsageErrorASCII(cx, callee, "Second argument, if present, must be a String");
|
||||
return false;
|
||||
}
|
||||
withOffsets = ToBoolean(args[1]);
|
||||
}
|
||||
|
||||
uintptr_t stackLimit = GetNativeStackLimit(cx);
|
||||
|
||||
wasm::Bytes bytes;
|
||||
UniqueChars error;
|
||||
wasm::Uint32Vector offsets;
|
||||
if (!wasm::TextToBinary(twoByteChars.twoByteChars(), stackLimit, &bytes, &offsets, &error)) {
|
||||
if (!wasm::TextToBinary(twoByteChars.twoByteChars(), stackLimit, &bytes, &error)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_TEXT_FAIL,
|
||||
error.get() ? error.get() : "out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject binary(cx, JS_NewUint8Array(cx, bytes.length()));
|
||||
if (!binary)
|
||||
return false;
|
||||
|
||||
memcpy(binary->as<TypedArrayObject>().viewDataUnshared(), bytes.begin(), bytes.length());
|
||||
|
||||
if (!withOffsets) {
|
||||
args.rval().setObject(*binary);
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedObject obj(cx, JS_NewPlainObject(cx));
|
||||
RootedObject obj(cx, JS_NewUint8Array(cx, bytes.length()));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
constexpr unsigned propAttrs = JSPROP_ENUMERATE;
|
||||
if (!JS_DefineProperty(cx, obj, "binary", binary, propAttrs))
|
||||
return false;
|
||||
|
||||
RootedObject jsOffsets(cx, JS_NewArrayObject(cx, offsets.length()));
|
||||
if (!jsOffsets)
|
||||
return false;
|
||||
for (size_t i = 0; i < offsets.length(); i++) {
|
||||
uint32_t offset = offsets[i];
|
||||
RootedValue offsetVal(cx, NumberValue(offset));
|
||||
if (!JS_SetElement(cx, jsOffsets, i, offsetVal))
|
||||
return false;
|
||||
}
|
||||
if (!JS_DefineProperty(cx, obj, "offsets", jsOffsets, propAttrs))
|
||||
return false;
|
||||
memcpy(obj->as<TypedArrayObject>().viewDataUnshared(), bytes.begin(), bytes.length());
|
||||
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
WasmBinaryToText(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
if (!cx->options().wasm()) {
|
||||
JS_ReportErrorASCII(cx, "wasm support unavailable");
|
||||
return false;
|
||||
}
|
||||
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!args.get(0).isObject() || !args.get(0).toObject().is<TypedArrayObject>()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_ARG);
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<TypedArrayObject*> code(cx, &args[0].toObject().as<TypedArrayObject>());
|
||||
|
||||
if (!TypedArrayObject::ensureHasBuffer(cx, code))
|
||||
return false;
|
||||
|
||||
if (code->isSharedMemory()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_BUF_ARG);
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t* bufferStart = code->bufferUnshared()->dataPointer();
|
||||
const uint8_t* bytes = bufferStart + code->byteOffset();
|
||||
uint32_t length = code->byteLength();
|
||||
|
||||
Vector<uint8_t> copy(cx);
|
||||
if (code->bufferUnshared()->hasInlineData()) {
|
||||
if (!copy.append(bytes, length))
|
||||
return false;
|
||||
bytes = copy.begin();
|
||||
}
|
||||
|
||||
if (args.length() > 1) {
|
||||
JS_ReportErrorASCII(cx, "wasm text format selection is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
StringBuffer buffer(cx);
|
||||
bool ok = wasm::BinaryToText(cx, bytes, length, buffer);
|
||||
if (!ok) {
|
||||
if (!cx->isExceptionPending())
|
||||
JS_ReportErrorASCII(cx, "wasm binary to text print error");
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString* result = buffer.finishString();
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
args.rval().setString(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
WasmExtractCode(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -5648,6 +5678,10 @@ gc::ZealModeHelpText),
|
|||
"wasmTextToBinary(str)",
|
||||
" Translates the given text wasm module into its binary encoding."),
|
||||
|
||||
JS_FN_HELP("wasmBinaryToText", WasmBinaryToText, 1, 0,
|
||||
"wasmBinaryToText(bin)",
|
||||
" Translates binary encoding to text format"),
|
||||
|
||||
JS_FN_HELP("wasmExtractCode", WasmExtractCode, 1, 0,
|
||||
"wasmExtractCode(module[, tier])",
|
||||
" Extracts generated machine code from WebAssembly.Module. The tier is a string,\n"
|
||||
|
|
|
@ -116,6 +116,14 @@ function wasmFullPass(text, expected, maybeImports, ...args) {
|
|||
let instance = new WebAssembly.Instance(module, maybeImports);
|
||||
assertEq(typeof instance.exports.run, 'function', "A 'run' function must be exported.");
|
||||
assertEq(instance.exports.run(...args), expected, "Initial module must return the expected result.");
|
||||
|
||||
let retext = wasmBinaryToText(binary);
|
||||
let rebinary = wasmTextToBinary(retext);
|
||||
|
||||
assertEq(WebAssembly.validate(rebinary), true, "Recreated binary must validate.");
|
||||
let remodule = new WebAssembly.Module(rebinary);
|
||||
let reinstance = new WebAssembly.Instance(remodule, maybeImports);
|
||||
assertEq(reinstance.exports.run(...args), expected, "Reformed module must return the expected result");
|
||||
}
|
||||
|
||||
// Ditto, but expects a function named '$run' instead of exported with this name.
|
||||
|
@ -126,15 +134,15 @@ function wasmFullPassI64(text, expected, maybeImports, ...args) {
|
|||
let augmentedSrc = _augmentSrc(text, [ { type: 'i64', func: '$run', args, expected } ]);
|
||||
let augmentedBinary = wasmTextToBinary(augmentedSrc);
|
||||
new WebAssembly.Instance(new WebAssembly.Module(augmentedBinary), maybeImports).exports.assert_0();
|
||||
|
||||
let retext = wasmBinaryToText(augmentedBinary);
|
||||
new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(retext)), maybeImports).exports.assert_0();
|
||||
}
|
||||
|
||||
function wasmRunWithDebugger(wast, lib, init, done) {
|
||||
let g = newGlobal('');
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
// Enable binary source mode.
|
||||
dbg.allowWasmBinarySource = true;
|
||||
|
||||
g.eval(`
|
||||
var wasm = wasmTextToBinary('${wast}');
|
||||
var lib = ${lib || 'undefined'};
|
||||
|
@ -152,6 +160,19 @@ var m = new WebAssembly.Instance(new WebAssembly.Module(wasm), lib);`);
|
|||
done({dbg, result, error, wasmScript, g,});
|
||||
}
|
||||
|
||||
function wasmGetScriptBreakpoints(wasmScript) {
|
||||
var result = [];
|
||||
var sourceText = wasmScript.source.text;
|
||||
sourceText.split('\n').forEach(function (line, i) {
|
||||
var lineOffsets = wasmScript.getLineOffsets(i + 1);
|
||||
if (lineOffsets.length === 0)
|
||||
return;
|
||||
assertEq(lineOffsets.length, 1);
|
||||
result.push({str: line.trim(), line: i + 1, offset: lineOffsets[0]});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
const WasmHelpers = {};
|
||||
|
||||
(function() {
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
// |jit-test| test-also-no-wasm-baseline
|
||||
// Tests that wasm module scripts have text line to bytecode offset information
|
||||
// when source text is generated.
|
||||
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
if (!wasmDebuggingIsSupported())
|
||||
quit();
|
||||
|
||||
// Checking if experimental format generates internal source map to binary file
|
||||
// by querying debugger scripts getLineOffsets.
|
||||
// (Notice that the source map will not be produced by wasmBinaryToText)
|
||||
function getAllOffsets(wast) {
|
||||
var sandbox = newGlobal('');
|
||||
var dbg = new Debugger();
|
||||
dbg.addDebuggee(sandbox);
|
||||
sandbox.eval(`
|
||||
var wasm = wasmTextToBinary('${wast}');
|
||||
var m = new WebAssembly.Instance(new WebAssembly.Module(wasm));
|
||||
`);
|
||||
var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
|
||||
var lines = wasmScript.source.text.split('\n');
|
||||
return lines.map((l, n) => { return { str: l, offsets: wasmScript.getLineOffsets(n + 1) }; });
|
||||
}
|
||||
|
||||
var result1 = getAllOffsets('(module \
|
||||
(func (nop)) \
|
||||
(func (drop (f32.sqrt (f32.add (f32.const 1.0) (f32.const 2.0))))) \
|
||||
)');
|
||||
|
||||
var nopLine = result1.filter(i => i.str.indexOf('nop') >= 0);
|
||||
assertEq(nopLine.length, 1);
|
||||
// The nopLine shall have single offset.
|
||||
assertEq(nopLine[0].offsets.length, 1);
|
||||
assertEq(nopLine[0].offsets[0] > 0, true);
|
||||
|
||||
var singleOffsetLines = result1.filter(i => i.offsets.length === 1);
|
||||
// There shall be total 8 lines with single offset.
|
||||
assertEq(singleOffsetLines.length, 8);
|
||||
|
||||
// Checking if all reported offsets can be resolved back to the corresponding
|
||||
// line number.
|
||||
function checkOffsetLineNumberMapping(wast, offsetsExpected) {
|
||||
var sandbox = newGlobal('');
|
||||
var dbg = new Debugger();
|
||||
dbg.addDebuggee(sandbox);
|
||||
sandbox.eval(`
|
||||
var wasm = wasmTextToBinary('${wast}');
|
||||
var module = new WebAssembly.Module(wasm);
|
||||
imports = {}
|
||||
for (let descriptor of WebAssembly.Module.imports(module)) {
|
||||
imports[descriptor.module] = {}
|
||||
switch(descriptor.kind) {
|
||||
case "function": imports[descriptor.module][descriptor.name] = new Function(''); break;
|
||||
}
|
||||
}
|
||||
var instance = new WebAssembly.Instance(module, imports);
|
||||
`);
|
||||
var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
|
||||
assertEq(wasmScript.startLine, 1);
|
||||
assertEq(wasmScript.lineCount >= 0, true);
|
||||
var lines = wasmScript.source.text.split('\n');
|
||||
var offsetsFound = 0;
|
||||
lines.forEach(function (l, n) {
|
||||
var offsets = wasmScript.getLineOffsets(n + 1);
|
||||
if (offsets.length < 1) return;
|
||||
assertEq(offsets.length, 1);
|
||||
assertEq(offsets[0] > 0, true);
|
||||
offsetsFound++;
|
||||
var loc = wasmScript.getOffsetLocation(offsets[0]);
|
||||
assertEq(loc instanceof Object, true);
|
||||
assertEq(loc.isEntryPoint, true);
|
||||
assertEq(loc.lineNumber, n + 1);
|
||||
assertEq(loc.columnNumber > 0, true);
|
||||
});
|
||||
assertEq(offsetsFound, offsetsExpected);
|
||||
}
|
||||
|
||||
checkOffsetLineNumberMapping('(module (func))', 1);
|
||||
checkOffsetLineNumberMapping('(module (func (nop)))', 2);
|
||||
checkOffsetLineNumberMapping('(module (import "a" "b"))', 0);
|
||||
checkOffsetLineNumberMapping('(module \
|
||||
(func (nop)) \
|
||||
(func (drop (f32.sqrt (f32.add (f32.const 1.0) (f32.const 2.0))))) \
|
||||
)', 8);
|
||||
checkOffsetLineNumberMapping('(module \
|
||||
(func (local i32) i32.const 0 i32.const 1 set_local 0 get_local 0 call 0 i32.add nop drop) \
|
||||
)', 9);
|
||||
|
||||
// Checking that there are no offsets are present in a wasm instance script for
|
||||
// which debug mode was not enabled.
|
||||
function getWasmScriptAfterDebuggerAttached(wast) {
|
||||
var sandbox = newGlobal('');
|
||||
var dbg = new Debugger();
|
||||
sandbox.eval(`
|
||||
var wasm = wasmTextToBinary('${wast}');
|
||||
var m = new WebAssembly.Instance(new WebAssembly.Module(wasm));
|
||||
`);
|
||||
// Attaching after wasm instance is created.
|
||||
dbg.addDebuggee(sandbox);
|
||||
var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
|
||||
return wasmScript;
|
||||
}
|
||||
|
||||
var wasmScript1 = getWasmScriptAfterDebuggerAttached('(module (func (nop)))');
|
||||
var wasmLines1 = wasmScript1.source.text.split('\n');
|
||||
assertEq(wasmScript1.startLine, 1);
|
||||
assertEq(wasmScript1.lineCount, 0);
|
||||
assertEq(wasmLines1.every((l, n) => wasmScript1.getLineOffsets(n + 1).length == 0), true);
|
||||
|
||||
// Checking that we must not resolve any location for any offset in a wasm
|
||||
// instance which debug mode was not enabled.
|
||||
var wasmScript2 = getWasmScriptAfterDebuggerAttached('(module (func (nop)))');
|
||||
for (var i = wasmTextToBinary('(module (func (nop)))').length - 1; i >= 0; i--)
|
||||
assertThrowsInstanceOf(() => wasmScript2.getOffsetLocation(i), Error);
|
|
@ -15,9 +15,7 @@ wasmRunWithDebugger(
|
|||
function ({dbg}) {
|
||||
offsets = [];
|
||||
dbg.onEnterFrame = function (frame) {
|
||||
if (frame.type != 'wasmcall') {
|
||||
return;
|
||||
}
|
||||
if (frame.type != 'wasmcall') return;
|
||||
offsets.push(frame.offset);
|
||||
frame.onStep = function () {
|
||||
offsets.push(frame.offset);
|
||||
|
@ -26,16 +24,16 @@ wasmRunWithDebugger(
|
|||
offsets.push(frame.offset);
|
||||
};
|
||||
};
|
||||
},
|
||||
function ({wasmScript, error}) {
|
||||
assertEq(error, undefined);
|
||||
assertEq(offsets.length, 5);
|
||||
offsets.forEach(offset => {
|
||||
var loc = wasmScript.getOffsetLocation(offset);
|
||||
assertEq(loc.isEntryPoint, true);
|
||||
assertEq(loc.lineNumber > 0, true);
|
||||
assertEq(loc.columnNumber > 0, true);
|
||||
assertEq(wasmScript.getLineOffsets(loc.lineNumber).length, 1);
|
||||
});
|
||||
}
|
||||
},
|
||||
function ({wasmScript, error}) {
|
||||
assertEq(error, undefined);
|
||||
assertEq(offsets.length, 5);
|
||||
offsets.forEach(offset => {
|
||||
var loc = wasmScript.getOffsetLocation(offset);
|
||||
assertEq(loc.isEntryPoint, true);
|
||||
assertEq(loc.lineNumber > 0, true);
|
||||
assertEq(loc.columnNumber > 0, true);
|
||||
assertEq(wasmScript.getLineOffsets(loc.lineNumber).length, 1);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -19,8 +19,8 @@ assertEq(s.format, "wasm");
|
|||
|
||||
var source = s.source;
|
||||
|
||||
// The text is never generated with the native Debugger API.
|
||||
assertEq(source.text.includes('module'), false);
|
||||
// The text is generated if wasm binary sources are disabled.
|
||||
assertEq(source.text.includes('module'), true);
|
||||
assertThrowsInstanceOf(() => source.binary, Error);
|
||||
|
||||
// Enable binary sources.
|
||||
|
@ -31,7 +31,7 @@ assertEq(s.format, "wasm");
|
|||
|
||||
var source2 = s.source;
|
||||
|
||||
// The text is predefined if wasm binary sources are enabled.
|
||||
// The text is '[wasm]' if wasm binary sources are enabled.
|
||||
assertEq(source2.text, '[wasm]');
|
||||
// The binary contains Uint8Array which is equal to wasm bytecode;
|
||||
arraysEqual(source2.binary, wasmTextToBinary('(module (func) (export "" 0))'));
|
||||
|
|
|
@ -6,55 +6,21 @@ load(libdir + "wasm.js");
|
|||
if (!wasmDebuggingIsSupported())
|
||||
quit();
|
||||
|
||||
function runTest(wast, initFunc, doneFunc) {
|
||||
let g = newGlobal('');
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
g.eval(`
|
||||
var { binary, offsets } = wasmTextToBinary('${wast}', /* offsets */ true);
|
||||
var m = new WebAssembly.Instance(new WebAssembly.Module(binary));`);
|
||||
|
||||
var { offsets } = g;
|
||||
|
||||
var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0];
|
||||
|
||||
initFunc({
|
||||
dbg,
|
||||
wasmScript,
|
||||
g,
|
||||
breakpoints: offsets
|
||||
});
|
||||
|
||||
let result, error;
|
||||
try {
|
||||
result = g.eval("m.exports.test()");
|
||||
} catch (ex) {
|
||||
error = ex;
|
||||
}
|
||||
|
||||
doneFunc({
|
||||
dbg,
|
||||
result,
|
||||
error,
|
||||
wasmScript,
|
||||
g
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var onBreakpointCalled;
|
||||
|
||||
// Checking if we can stop at specified breakpoint.
|
||||
runTest(
|
||||
var onBreakpointCalled;
|
||||
wasmRunWithDebugger(
|
||||
'(module (func (nop) (nop)) (export "test" 0))',
|
||||
function ({wasmScript, breakpoints}) {
|
||||
undefined,
|
||||
function ({wasmScript}) {
|
||||
var breakpoints = wasmGetScriptBreakpoints(wasmScript);
|
||||
assertEq(breakpoints.length, 3);
|
||||
assertEq(breakpoints[0] > 0, true);
|
||||
assertEq(breakpoints[0].offset > 0, true);
|
||||
// Checking if breakpoints offsets are in ascending order.
|
||||
assertEq(breakpoints[0] < breakpoints[1], true);
|
||||
assertEq(breakpoints[1] < breakpoints[2], true);
|
||||
assertEq(breakpoints[0].offset < breakpoints[1].offset, true);
|
||||
assertEq(breakpoints[1].offset < breakpoints[2].offset, true);
|
||||
onBreakpointCalled = 0;
|
||||
breakpoints.forEach(function (offset) {
|
||||
breakpoints.forEach(function (bp) {
|
||||
var offset = bp.offset;
|
||||
wasmScript.setBreakpoint(offset, {
|
||||
hit: (frame) => {
|
||||
assertEq(frame.offset, offset);
|
||||
|
@ -70,15 +36,18 @@ runTest(
|
|||
);
|
||||
|
||||
// Checking if we can remove breakpoint one by one.
|
||||
runTest(
|
||||
wasmRunWithDebugger(
|
||||
'(module (func (nop) (nop)) (export "test" 0))',
|
||||
function ({wasmScript, breakpoints}) {
|
||||
undefined,
|
||||
function ({wasmScript}) {
|
||||
var breakpoints = wasmGetScriptBreakpoints(wasmScript);
|
||||
onBreakpointCalled = 0;
|
||||
var handlers = [];
|
||||
breakpoints.forEach(function (offset, i) {
|
||||
breakpoints.forEach(function (bp, i) {
|
||||
var offset = bp.offset;
|
||||
wasmScript.setBreakpoint(offset, handlers[i] = {
|
||||
hit: (frame) => {
|
||||
assertEq(frame.offset, breakpoints[0]);
|
||||
assertEq(frame.offset, breakpoints[0].offset);
|
||||
onBreakpointCalled++;
|
||||
// Removing all handlers.
|
||||
handlers.forEach(h => wasmScript.clearBreakpoint(h));
|
||||
|
@ -93,15 +62,18 @@ runTest(
|
|||
);
|
||||
|
||||
// Checking if we can remove breakpoint one by one from a breakpoint handler.
|
||||
runTest(
|
||||
wasmRunWithDebugger(
|
||||
'(module (func (nop) (nop)) (export "test" 0))',
|
||||
function ({wasmScript, breakpoints}) {
|
||||
undefined,
|
||||
function ({wasmScript}) {
|
||||
var breakpoints = wasmGetScriptBreakpoints(wasmScript);
|
||||
onBreakpointCalled = 0;
|
||||
var handlers = [];
|
||||
breakpoints.forEach(function (offset, i) {
|
||||
breakpoints.forEach(function (bp, i) {
|
||||
var offset = bp.offset;
|
||||
wasmScript.setBreakpoint(offset, handlers[i] = {
|
||||
hit: (frame) => {
|
||||
assertEq(frame.offset, breakpoints[0]);
|
||||
assertEq(frame.offset, breakpoints[0].offset);
|
||||
onBreakpointCalled++;
|
||||
// Removing all handlers.
|
||||
handlers.forEach(h => wasmScript.clearBreakpoint(h));
|
||||
|
@ -118,13 +90,16 @@ runTest(
|
|||
// Checking if we can remove breakpoint one by one from onEnterFrame,
|
||||
// but onStep will still work.
|
||||
var onStepCalled;
|
||||
runTest(
|
||||
wasmRunWithDebugger(
|
||||
'(module (func (nop) (nop)) (export "test" 0))',
|
||||
function ({dbg, wasmScript, breakpoints}) {
|
||||
undefined,
|
||||
function ({dbg, wasmScript}) {
|
||||
var breakpoints = wasmGetScriptBreakpoints(wasmScript);
|
||||
onBreakpointCalled = 0;
|
||||
onStepCalled = [];
|
||||
var handlers = [];
|
||||
breakpoints.forEach(function (offset, i) {
|
||||
breakpoints.forEach(function (bp, i) {
|
||||
var offset = bp.offset;
|
||||
wasmScript.setBreakpoint(offset, handlers[i] = {
|
||||
hit: (frame) => {
|
||||
assertEq(false, true);
|
||||
|
@ -150,14 +125,17 @@ runTest(
|
|||
);
|
||||
|
||||
// Checking if we can remove all breakpoints.
|
||||
runTest(
|
||||
wasmRunWithDebugger(
|
||||
'(module (func (nop) (nop)) (export "test" 0))',
|
||||
function ({wasmScript, breakpoints}) {
|
||||
undefined,
|
||||
function ({wasmScript}) {
|
||||
var breakpoints = wasmGetScriptBreakpoints(wasmScript);
|
||||
onBreakpointCalled = 0;
|
||||
breakpoints.forEach(function (offset, i) {
|
||||
breakpoints.forEach(function (bp, i) {
|
||||
var offset = bp.offset;
|
||||
wasmScript.setBreakpoint(offset, {
|
||||
hit: (frame) => {
|
||||
assertEq(frame.offset, breakpoints[0]);
|
||||
assertEq(frame.offset, breakpoints[0].offset);
|
||||
onBreakpointCalled++;
|
||||
// Removing all handlers.
|
||||
wasmScript.clearAllBreakpoints();
|
||||
|
@ -172,11 +150,14 @@ runTest(
|
|||
);
|
||||
|
||||
// Checking if breakpoints are removed after debugger has been detached.
|
||||
runTest(
|
||||
wasmRunWithDebugger(
|
||||
'(module (func (nop) (nop)) (export "test" 0))',
|
||||
function ({dbg, wasmScript, g, breakpoints}) {
|
||||
undefined,
|
||||
function ({dbg, wasmScript, g}) {
|
||||
var breakpoints = wasmGetScriptBreakpoints(wasmScript);
|
||||
onBreakpointCalled = 0;
|
||||
breakpoints.forEach(function (offset, i) {
|
||||
breakpoints.forEach(function (bp, i) {
|
||||
var offset = bp.offset;
|
||||
wasmScript.setBreakpoint(offset, {
|
||||
hit: (frame) => {
|
||||
onBreakpointCalled++;
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
load(libdir + "asserts.js");
|
||||
|
||||
if (!wasmDebuggingIsSupported())
|
||||
quit();
|
||||
quit();
|
||||
|
||||
// Checking if experimental format generates internal source map to binary file
|
||||
// by querying debugger scripts getAllColumnOffsets.
|
||||
// (Notice that the source map will not be produced by wasmBinaryToText)
|
||||
function getAllOffsets(wast) {
|
||||
var sandbox = newGlobal('');
|
||||
var dbg = new Debugger();
|
||||
dbg.addDebuggee(sandbox);
|
||||
dbg.allowWasmBinarySource = true;
|
||||
sandbox.eval(`
|
||||
var wasm = wasmTextToBinary('${wast}');
|
||||
var m = new WebAssembly.Instance(new WebAssembly.Module(wasm));
|
||||
|
@ -28,10 +28,8 @@ var offsets1 = getAllOffsets('(module \
|
|||
)');
|
||||
|
||||
// There shall be total 8 lines with single and unique offset per line.
|
||||
var usedOffsets = Object.create(null),
|
||||
usedLines = Object.create(null);
|
||||
var usedOffsets = Object.create(null), usedLines = Object.create(null);
|
||||
assertEq(offsets1.length, 8);
|
||||
|
||||
offsets1.forEach(({offset, lineNumber, columnNumber}) => {
|
||||
assertEq(offset > 0, true);
|
||||
assertEq(lineNumber > 0, true);
|
||||
|
|
|
@ -84,10 +84,79 @@ for (let align of [1, 2, 4, 8]) {
|
|||
assertEq(valText(text), align == 4);
|
||||
}
|
||||
|
||||
// Check that the text output is sane.
|
||||
|
||||
for (let [type,view] of [['i32','8_u'],['i32','16_u'],['i32',''],['i64','8_u'],['i64','16_u'],['i64','32_u'],['i64','']]) {
|
||||
let addr = "i32.const 48";
|
||||
let value = `${type}.const 1`;
|
||||
let value2 = `${type}.const 2`;
|
||||
for (let op of ["add", "and", "or", "xor", "xchg"]) {
|
||||
let operator = `${type}.atomic.rmw${view}.${op}`;
|
||||
let text = `(module (memory 1 1 shared)
|
||||
(func (result ${type}) (${operator} (${addr}) (${value})))
|
||||
(export "" 0))`;
|
||||
checkRoundTrip(text, [addr, value, operator]);
|
||||
}
|
||||
{
|
||||
let operator = `${type}.atomic.rmw${view}.cmpxchg`;
|
||||
let text = `(module (memory 1 1 shared)
|
||||
(func (result ${type}) (${operator} (${addr}) (${value}) (${value2})))
|
||||
(export "" 0))`;
|
||||
checkRoundTrip(text, [addr, value, value2, operator]);
|
||||
}
|
||||
{
|
||||
let operator = `${type}.atomic.load${view}`;
|
||||
let text = `(module (memory 1 1 shared)
|
||||
(func (result ${type}) (${operator} (${addr})))
|
||||
(export "" 0))`;
|
||||
checkRoundTrip(text, [addr, operator]);
|
||||
}
|
||||
{
|
||||
let operator = `${type}.atomic.store${view}`;
|
||||
let text = `(module (memory 1 1 shared)
|
||||
(func (${operator} (${addr}) (${value})))
|
||||
(export "" 0))`;
|
||||
checkRoundTrip(text, [addr, value, operator]);
|
||||
}
|
||||
}
|
||||
|
||||
for (let type of ['i32', 'i64']) {
|
||||
let addr = "i32.const 48";
|
||||
let operator = `${type}.atomic.wait`
|
||||
let value = `${type}.const 1`;
|
||||
let timeout = "i64.const 314159";
|
||||
let text = `(module (memory 1 1 shared)
|
||||
(func (result i32) (${operator} (${addr}) (${value}) (${timeout})))
|
||||
(export "" 0))`;
|
||||
checkRoundTrip(text, [addr, value, timeout, operator]);
|
||||
}
|
||||
|
||||
{
|
||||
let addr = "i32.const 48";
|
||||
let operator = "atomic.wake"
|
||||
let count = "i32.const 1";
|
||||
let text = `(module (memory 1 1 shared)
|
||||
(func (result i32) (${operator} (${addr}) (${count})))
|
||||
(export "" 0))`;
|
||||
checkRoundTrip(text, [addr, count, operator]);
|
||||
}
|
||||
|
||||
function valText(text) {
|
||||
return WebAssembly.validate(wasmTextToBinary(text));
|
||||
}
|
||||
|
||||
function checkRoundTrip(text, ss) {
|
||||
let input = wasmTextToBinary(text);
|
||||
let output = wasmBinaryToText(input).split("\n").map(String.trim);
|
||||
for (let s of output) {
|
||||
if (ss.length == 0)
|
||||
break;
|
||||
if (s.match(ss[0]))
|
||||
ss.shift();
|
||||
}
|
||||
assertEq(ss.length, 0);
|
||||
}
|
||||
|
||||
// Test that atomic operations work.
|
||||
|
||||
function I64(hi, lo) {
|
||||
|
|
|
@ -69,6 +69,15 @@ assertEq(ins.hello(4.0, 1), 16.0)
|
|||
assertEq(ins.x1(12), 36)
|
||||
assertEq(ins.x2(8), Math.PI)
|
||||
|
||||
// Crude but at least checks that we have *something*.
|
||||
|
||||
var txt = wasmBinaryToText(bin);
|
||||
var re = /\(type\s+\$[a-z0-9]+\s+\(struct/gm;
|
||||
assertEq(Array.isArray(re.exec(txt)), true);
|
||||
assertEq(Array.isArray(re.exec(txt)), true);
|
||||
assertEq(Array.isArray(re.exec(txt)), true);
|
||||
assertEq(Array.isArray(re.exec(txt)), false);
|
||||
|
||||
// The field name is optional, so this should work.
|
||||
|
||||
wasmEvalText(`
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
var caught = false;
|
||||
try {
|
||||
wasmBinaryToText(new Int8Array(1));
|
||||
} catch (e) {
|
||||
caught = true;
|
||||
}
|
||||
assertEq(caught, true);
|
||||
|
||||
assertErrorMessage(() => wasmBinaryToText(wasmTextToBinary(`(module (func (result i32) (f32.const 13.37)))`)), WebAssembly.CompileError, /type mismatch/);
|
||||
|
||||
function runTest(code) {
|
||||
var expected = wasmTextToBinary(code);
|
||||
var s = wasmBinaryToText(expected);
|
||||
print("TEXT: " + s);
|
||||
var roundtrip = wasmTextToBinary(s);
|
||||
assertDeepEq(expected, roundtrip);
|
||||
}
|
||||
|
||||
// Smoke test
|
||||
runTest(`
|
||||
(module
|
||||
(func (param i32) (result f64)
|
||||
(local $l f32)
|
||||
(block
|
||||
(set_local $l (f32.const 0.0))
|
||||
(loop $exit $cont
|
||||
(br_if $exit (get_local 0))
|
||||
(br 2)
|
||||
)
|
||||
(drop (if f64 (i32.const 1)
|
||||
(f64.min (f64.neg (f64.const 1)) (f64.const 0))
|
||||
(f64.add (f64.const 0.5) (f64.load offset=0 (i32.const 0)) )
|
||||
))
|
||||
)
|
||||
(i32.store16 (i32.const 8) (i32.const 128))
|
||||
|
||||
(return (f64.const 0))
|
||||
)
|
||||
(export "test" 0)
|
||||
(memory 1 10)
|
||||
)`);
|
||||
|
||||
// Constants, stores and loads
|
||||
runTest(`
|
||||
(module (func
|
||||
(local i32) (local f32) (local f64)
|
||||
(drop (i32.const 0))
|
||||
(drop (i32.const 100002))
|
||||
(drop (f32.const 0.0))
|
||||
(drop (f32.const 1.5))
|
||||
(drop (f64.const 0.0))
|
||||
(drop (f64.const -10.25))
|
||||
(i32.store (i32.const 0) (i32.load (i32.const 0)))
|
||||
(i32.store8 (i32.const 1) (i32.load8_s (i32.const 2)))
|
||||
(i32.store8 (i32.const 3) (i32.load8_u (i32.const 4)))
|
||||
(i32.store16 (i32.const 2) (i32.load16_s (i32.const 0)))
|
||||
(i32.store16 (i32.const 1) (i32.load16_u (i32.const 0)))
|
||||
(f32.store (i32.const 5) (f32.load (i32.const 6)))
|
||||
(f64.store (i32.const 5) (f64.load (i32.const 6)))
|
||||
(set_local 0 (get_local 0))
|
||||
(set_local 2 (get_local 2))
|
||||
)(memory 100))`);
|
||||
|
||||
// Branching
|
||||
runTest(`
|
||||
(module
|
||||
(func
|
||||
(block (block (block (nop))))
|
||||
(block (loop ))
|
||||
(if (i32.const 0) (block $label (nop)))
|
||||
(if (i32.const 1) (nop) (loop $exit $cont (block )))
|
||||
(block $l (br $l))
|
||||
(block $m (block (block (br $m))))
|
||||
(block $k (br_if 0 (i32.const 0)) (return))
|
||||
(block $n (block (block (br_if 2 (i32.const 1)) (nop))))
|
||||
(block $1 (block $2 (block $3 (br_table $2 $3 $1 (i32.const 1)) )) (nop))
|
||||
(loop $exit $cont (br_if $cont (i32.const 0)) (nop))
|
||||
(return)
|
||||
)
|
||||
(func (result f32) (return (f32.const -0.5)))
|
||||
(memory 0)
|
||||
)`);
|
||||
|
||||
// i32, f32 and f64 operations
|
||||
runTest(`
|
||||
(module
|
||||
(func $iadd (param $x i32) (param $y i32) (result i32) (i32.add (get_local $x) (get_local $y)))
|
||||
(func $isub (param $x i32) (param $y i32) (result i32) (i32.sub (get_local $x) (get_local $y)))
|
||||
(func $imul (param $x i32) (param $y i32) (result i32) (i32.mul (get_local $x) (get_local $y)))
|
||||
(func $idiv_s (param $x i32) (param $y i32) (result i32) (i32.div_s (get_local $x) (get_local $y)))
|
||||
(func $idiv_u (param $x i32) (param $y i32) (result i32) (i32.div_u (get_local $x) (get_local $y)))
|
||||
(func $irem_s (param $x i32) (param $y i32) (result i32) (i32.rem_s (get_local $x) (get_local $y)))
|
||||
(func $irem_u (param $x i32) (param $y i32) (result i32) (i32.rem_u (get_local $x) (get_local $y)))
|
||||
(func $iand (param $x i32) (param $y i32) (result i32) (i32.and (get_local $x) (get_local $y)))
|
||||
(func $ior (param $x i32) (param $y i32) (result i32) (i32.or (get_local $x) (get_local $y)))
|
||||
(func $ixor (param $x i32) (param $y i32) (result i32) (i32.xor (get_local $x) (get_local $y)))
|
||||
(func $ishl (param $x i32) (param $y i32) (result i32) (i32.shl (get_local $x) (get_local $y)))
|
||||
(func $ishr_s (param $x i32) (param $y i32) (result i32) (i32.shr_s (get_local $x) (get_local $y)))
|
||||
(func $ishr_u (param $x i32) (param $y i32) (result i32) (i32.shr_u (get_local $x) (get_local $y)))
|
||||
(func $iclz (param $x i32) (result i32) (i32.clz (get_local $x)))
|
||||
(func $ictz (param $x i32) (result i32) (i32.ctz (get_local $x)))
|
||||
(func $ipopcnt (param $x i32) (result i32) (i32.popcnt (get_local $x)))
|
||||
(func $ieq (param $x i32) (param $y i32) (result i32) (i32.eq (get_local $x) (get_local $y)))
|
||||
(func $ine (param $x i32) (param $y i32) (result i32) (i32.ne (get_local $x) (get_local $y)))
|
||||
(func $ilt_s (param $x i32) (param $y i32) (result i32) (i32.lt_s (get_local $x) (get_local $y)))
|
||||
(func $ilt_u (param $x i32) (param $y i32) (result i32) (i32.lt_u (get_local $x) (get_local $y)))
|
||||
(func $ile_s (param $x i32) (param $y i32) (result i32) (i32.le_s (get_local $x) (get_local $y)))
|
||||
(func $ile_u (param $x i32) (param $y i32) (result i32) (i32.le_u (get_local $x) (get_local $y)))
|
||||
(func $igt_s (param $x i32) (param $y i32) (result i32) (i32.gt_s (get_local $x) (get_local $y)))
|
||||
(func $igt_u (param $x i32) (param $y i32) (result i32) (i32.gt_u (get_local $x) (get_local $y)))
|
||||
(func $ige_s (param $x i32) (param $y i32) (result i32) (i32.ge_s (get_local $x) (get_local $y)))
|
||||
(func $ige_u (param $x i32) (param $y i32) (result i32) (i32.ge_u (get_local $x) (get_local $y)))
|
||||
|
||||
(func $fadd (param $x f32) (param $y f32) (result f32) (f32.add (get_local $x) (get_local $y)))
|
||||
(func $fsub (param $x f32) (param $y f32) (result f32) (f32.sub (get_local $x) (get_local $y)))
|
||||
(func $fmul (param $x f32) (param $y f32) (result f32) (f32.mul (get_local $x) (get_local $y)))
|
||||
(func $fdiv (param $x f32) (param $y f32) (result f32) (f32.div (get_local $x) (get_local $y)))
|
||||
(func $fsqrt (param $x f32) (result f32) (f32.sqrt (get_local $x)))
|
||||
(func $fmin (param $x f32) (param $y f32) (result f32) (f32.min (get_local $x) (get_local $y)))
|
||||
(func $fmax (param $x f32) (param $y f32) (result f32) (f32.max (get_local $x) (get_local $y)))
|
||||
(func $fceil (param $x f32) (result f32) (f32.ceil (get_local $x)))
|
||||
(func $ffloor (param $x f32) (result f32) (f32.floor (get_local $x)))
|
||||
(func $fabs (param $x f32) (result f32) (f32.abs (get_local $x)))
|
||||
(func $fneg (param $x f32) (result f32) (f32.neg (get_local $x)))
|
||||
|
||||
(func $dadd (param $x f64) (param $y f64) (result f64) (f64.add (get_local $x) (get_local $y)))
|
||||
(func $dsub (param $x f64) (param $y f64) (result f64) (f64.sub (get_local $x) (get_local $y)))
|
||||
(func $dmul (param $x f64) (param $y f64) (result f64) (f64.mul (get_local $x) (get_local $y)))
|
||||
(func $ddiv (param $x f64) (param $y f64) (result f64) (f64.div (get_local $x) (get_local $y)))
|
||||
(func $dceil (param $x f64) (result f64) (f64.ceil (get_local $x)))
|
||||
(func $dfloor (param $x f64) (result f64) (f64.floor (get_local $x)))
|
||||
(func $dabs (param $x f64) (result f64) (f64.abs (get_local $x)))
|
||||
(func $dneg (param $x f64) (result f64) (f64.neg (get_local $x)))
|
||||
(memory 0))`);
|
||||
|
||||
// conversions
|
||||
runTest(`
|
||||
(module
|
||||
(func $itrunc_s_f32 (param $x f32) (result i32) (i32.trunc_s/f32 (get_local $x)))
|
||||
(func $itrunc_u_f32 (param $x f32) (result i32) (i32.trunc_u/f32 (get_local $x)))
|
||||
(func $itrunc_s_f64 (param $x f64) (result i32) (i32.trunc_s/f64 (get_local $x)))
|
||||
(func $itrunc_u_f64 (param $x f64) (result i32) (i32.trunc_u/f64 (get_local $x)))
|
||||
(func $fconvert_s_i32 (param $x i32) (result f32) (f32.convert_s/i32 (get_local $x)))
|
||||
(func $dconvert_s_i32 (param $x i32) (result f64) (f64.convert_s/i32 (get_local $x)))
|
||||
(func $fconvert_u_i32 (param $x i32) (result f32) (f32.convert_u/i32 (get_local $x)))
|
||||
(func $dconvert_u_i32 (param $x i32) (result f64) (f64.convert_u/i32 (get_local $x)))
|
||||
(func $dpromote_f32 (param $x f32) (result f64) (f64.promote/f32 (get_local $x)))
|
||||
(func $fdemote_f64 (param $x f64) (result f32) (f32.demote/f64 (get_local $x)))
|
||||
(memory 0))`);
|
||||
|
||||
// function calls
|
||||
runTest(`
|
||||
(module
|
||||
(type $type1 (func (param i32) (result i32)))
|
||||
(import $import1 "mod" "test" (param f32) (result f32))
|
||||
(table anyfunc (elem $func1 $func2))
|
||||
(func $func1 (param i32) (param f32) (nop))
|
||||
(func $func2 (param i32) (result i32) (get_local 0))
|
||||
(func $test
|
||||
(call $func1
|
||||
(call_indirect $type1 (i32.const 2) (i32.const 1))
|
||||
(call $import1 (f32.const 1.0))
|
||||
)
|
||||
)
|
||||
(export "test" $test)
|
||||
(memory 1)
|
||||
)`);
|
||||
|
||||
// default memory export from binaryen
|
||||
runTest(`(module (func (nop)) (memory 0 65535))`);
|
||||
|
||||
// stack-machine code that isn't directly representable as an AST
|
||||
runTest(`
|
||||
(module
|
||||
(func (result i32)
|
||||
(local $x i32)
|
||||
i32.const 100
|
||||
set_local $x
|
||||
i32.const 200
|
||||
set_local $x
|
||||
i32.const 400
|
||||
set_local $x
|
||||
i32.const 2
|
||||
i32.const 16
|
||||
nop
|
||||
set_local $x
|
||||
i32.const 3
|
||||
i32.const 17
|
||||
set_local $x
|
||||
i32.const 18
|
||||
set_local $x
|
||||
i32.lt_s
|
||||
if i32
|
||||
i32.const 101
|
||||
set_local $x
|
||||
i32.const 8
|
||||
i32.const 102
|
||||
set_local $x
|
||||
else
|
||||
i32.const 103
|
||||
set_local $x
|
||||
i32.const 900
|
||||
i32.const 104
|
||||
set_local $x
|
||||
i32.const 105
|
||||
set_local $x
|
||||
end
|
||||
i32.const 107
|
||||
set_local $x
|
||||
get_local $x
|
||||
i32.add
|
||||
i32.const 106
|
||||
set_local $x
|
||||
)
|
||||
(export "" 0)
|
||||
)`);
|
||||
|
||||
// more stack-machine code that isn't directly representable as an AST
|
||||
runTest(`
|
||||
(module
|
||||
(func $return_void)
|
||||
|
||||
(func (result i32)
|
||||
(local $x i32)
|
||||
i32.const 0
|
||||
block
|
||||
i32.const 1
|
||||
set_local $x
|
||||
end
|
||||
i32.const 2
|
||||
set_local $x
|
||||
i32.const 3
|
||||
loop
|
||||
i32.const 4
|
||||
set_local $x
|
||||
end
|
||||
i32.const 5
|
||||
set_local $x
|
||||
i32.add
|
||||
call $return_void
|
||||
)
|
||||
(export "" 0)
|
||||
)`);
|
||||
|
||||
runTest(`
|
||||
(module
|
||||
(func $func
|
||||
block $block
|
||||
i32.const 0
|
||||
if
|
||||
i32.const 0
|
||||
if
|
||||
end
|
||||
else
|
||||
end
|
||||
end
|
||||
)
|
||||
(export "" 0)
|
||||
)`);
|
||||
|
||||
// Branch table.
|
||||
runTest(`(module
|
||||
(func (export "run") (param $p i32) (local $n i32)
|
||||
i32.const 0
|
||||
set_local $n
|
||||
loop $outer
|
||||
block $c block $b block $a
|
||||
loop $inner
|
||||
get_local $p
|
||||
br_table $b $a $c $inner $outer
|
||||
end $inner
|
||||
end $a
|
||||
get_local $n
|
||||
i32.const 1
|
||||
i32.add
|
||||
set_local $n
|
||||
end $b
|
||||
block
|
||||
get_local $n
|
||||
i32.const 2
|
||||
i32.add
|
||||
set_local $n
|
||||
end
|
||||
end $c
|
||||
end $outer
|
||||
)
|
||||
)`);
|
||||
|
||||
// Import as a start function.
|
||||
runTest(`(module
|
||||
(import "env" "test" (func))
|
||||
(start 0)
|
||||
)`);
|
|
@ -401,6 +401,8 @@ UNIFIED_SOURCES += [
|
|||
'vm/Xdr.cpp',
|
||||
'wasm/AsmJS.cpp',
|
||||
'wasm/WasmBaselineCompile.cpp',
|
||||
'wasm/WasmBinaryToAST.cpp',
|
||||
'wasm/WasmBinaryToText.cpp',
|
||||
'wasm/WasmBuiltins.cpp',
|
||||
'wasm/WasmCode.cpp',
|
||||
'wasm/WasmCompile.cpp',
|
||||
|
@ -418,6 +420,7 @@ UNIFIED_SOURCES += [
|
|||
'wasm/WasmStubs.cpp',
|
||||
'wasm/WasmTable.cpp',
|
||||
'wasm/WasmTextToBinary.cpp',
|
||||
'wasm/WasmTextUtils.cpp',
|
||||
'wasm/WasmTypes.cpp',
|
||||
'wasm/WasmValidate.cpp'
|
||||
]
|
||||
|
|
|
@ -126,17 +126,10 @@ struct AstBase
|
|||
}
|
||||
};
|
||||
|
||||
struct AstNode
|
||||
{
|
||||
void* operator new(size_t numBytes, LifoAlloc& astLifo) throw() {
|
||||
return astLifo.alloc(numBytes);
|
||||
}
|
||||
};
|
||||
|
||||
class AstFuncType;
|
||||
class AstStructType;
|
||||
|
||||
class AstTypeDef : public AstNode
|
||||
class AstTypeDef : public AstBase
|
||||
{
|
||||
protected:
|
||||
enum class Which { IsFuncType, IsStructType };
|
||||
|
@ -265,6 +258,19 @@ AstTypeDef::asStructType() const
|
|||
return *static_cast<const AstStructType*>(this);
|
||||
}
|
||||
|
||||
const uint32_t AstNodeUnknownOffset = 0;
|
||||
|
||||
class AstNode : public AstBase
|
||||
{
|
||||
uint32_t offset_; // if applicable, offset in the binary format file
|
||||
|
||||
public:
|
||||
AstNode() : offset_(AstNodeUnknownOffset) {}
|
||||
|
||||
uint32_t offset() const { return offset_; }
|
||||
void setOffset(uint32_t offset) { offset_ = offset; }
|
||||
};
|
||||
|
||||
enum class AstExprKind
|
||||
{
|
||||
AtomicCmpXchg,
|
||||
|
@ -856,6 +862,7 @@ class AstFunc : public AstNode
|
|||
AstValTypeVector vars_;
|
||||
AstNameVector localNames_;
|
||||
AstExprVector body_;
|
||||
uint32_t endOffset_; // if applicable, offset in the binary format file
|
||||
|
||||
public:
|
||||
AstFunc(AstName name, AstRef ft, AstValTypeVector&& vars,
|
||||
|
@ -864,13 +871,16 @@ class AstFunc : public AstNode
|
|||
funcType_(ft),
|
||||
vars_(std::move(vars)),
|
||||
localNames_(std::move(locals)),
|
||||
body_(std::move(body))
|
||||
body_(std::move(body)),
|
||||
endOffset_(AstNodeUnknownOffset)
|
||||
{}
|
||||
AstRef& funcType() { return funcType_; }
|
||||
const AstValTypeVector& vars() const { return vars_; }
|
||||
const AstNameVector& locals() const { return localNames_; }
|
||||
const AstExprVector& body() const { return body_; }
|
||||
AstName name() const { return name_; }
|
||||
uint32_t endOffset() const { return endOffset_; }
|
||||
void setEndOffset(uint32_t offset) { endOffset_ = offset; }
|
||||
};
|
||||
|
||||
class AstGlobal : public AstNode
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,37 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef wasmbinarytoast_h
|
||||
#define wasmbinarytoast_h
|
||||
|
||||
#include "ds/LifoAlloc.h"
|
||||
|
||||
#include "wasm/WasmAST.h"
|
||||
#include "wasm/WasmTypes.h"
|
||||
|
||||
namespace js {
|
||||
namespace wasm {
|
||||
|
||||
bool
|
||||
BinaryToAst(JSContext* cx, const uint8_t* bytes, uint32_t length, LifoAlloc& lifo,
|
||||
AstModule** module);
|
||||
|
||||
} // end wasm namespace
|
||||
} // end js namespace
|
||||
|
||||
#endif // namespace wasmbinarytoast_h
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,45 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef wasm_binary_to_text_h
|
||||
#define wasm_binary_to_text_h
|
||||
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
#include "gc/Rooting.h"
|
||||
#include "js/Class.h"
|
||||
#include "wasm/WasmCode.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class StringBuffer;
|
||||
|
||||
namespace wasm {
|
||||
|
||||
// Translate the given binary representation of a wasm module into the module's textual
|
||||
// representation.
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
BinaryToText(JSContext* cx, const uint8_t* bytes, size_t length, StringBuffer& buffer,
|
||||
GeneratedSourceMap* sourceMap = nullptr);
|
||||
|
||||
} // namespace wasm
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // namespace wasm_binary_to_text_h
|
|
@ -27,6 +27,7 @@
|
|||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "wasm/WasmBinaryToText.h"
|
||||
#include "wasm/WasmInstance.h"
|
||||
#include "wasm/WasmValidate.h"
|
||||
|
||||
|
@ -36,6 +37,56 @@ using namespace js::wasm;
|
|||
|
||||
using mozilla::BinarySearchIf;
|
||||
|
||||
bool
|
||||
GeneratedSourceMap::searchLineByOffset(JSContext* cx, uint32_t offset, size_t* exprlocIndex)
|
||||
{
|
||||
MOZ_ASSERT(!exprlocs_.empty());
|
||||
size_t exprlocsLength = exprlocs_.length();
|
||||
|
||||
// Lazily build sorted array for fast log(n) lookup.
|
||||
if (!sortedByOffsetExprLocIndices_) {
|
||||
ExprLocIndexVector scratch;
|
||||
auto indices = MakeUnique<ExprLocIndexVector>();
|
||||
if (!indices || !indices->resize(exprlocsLength) || !scratch.resize(exprlocsLength)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
sortedByOffsetExprLocIndices_ = std::move(indices);
|
||||
|
||||
for (size_t i = 0; i < exprlocsLength; i++)
|
||||
(*sortedByOffsetExprLocIndices_)[i] = i;
|
||||
|
||||
auto compareExprLocViaIndex = [&](uint32_t i, uint32_t j, bool* lessOrEqualp) -> bool {
|
||||
*lessOrEqualp = exprlocs_[i].offset <= exprlocs_[j].offset;
|
||||
return true;
|
||||
};
|
||||
MOZ_ALWAYS_TRUE(MergeSort(sortedByOffsetExprLocIndices_->begin(), exprlocsLength,
|
||||
scratch.begin(), compareExprLocViaIndex));
|
||||
}
|
||||
|
||||
// Allowing non-exact search and if BinarySearchIf returns out-of-bound
|
||||
// index, moving the index to the last index.
|
||||
auto lookupFn = [&](uint32_t i) -> int {
|
||||
const ExprLoc& loc = exprlocs_[i];
|
||||
return offset == loc.offset ? 0 : offset < loc.offset ? -1 : 1;
|
||||
};
|
||||
size_t match;
|
||||
Unused << BinarySearchIf(sortedByOffsetExprLocIndices_->begin(), 0, exprlocsLength, lookupFn, &match);
|
||||
if (match >= exprlocsLength)
|
||||
match = exprlocsLength - 1;
|
||||
*exprlocIndex = (*sortedByOffsetExprLocIndices_)[match];
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t
|
||||
GeneratedSourceMap::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
size_t size = exprlocs_.sizeOfExcludingThis(mallocSizeOf);
|
||||
if (sortedByOffsetExprLocIndices_)
|
||||
size += sortedByOffsetExprLocIndices_->sizeOfIncludingThis(mallocSizeOf);
|
||||
return size;
|
||||
}
|
||||
|
||||
DebugState::DebugState(SharedCode code,
|
||||
const ShareableBytes* maybeBytecode,
|
||||
bool binarySource)
|
||||
|
@ -48,14 +99,17 @@ DebugState::DebugState(SharedCode code,
|
|||
}
|
||||
|
||||
const char enabledMessage[] =
|
||||
"Restart with developer tools open to view WebAssembly source.";
|
||||
"Restart with developer tools open to view WebAssembly source";
|
||||
|
||||
const char noBinarySource[] =
|
||||
"Configure the debugger to display WebAssembly bytecode.";
|
||||
const char tooBigMessage[] =
|
||||
"Unfortunately, this WebAssembly module is too big to view as text.\n"
|
||||
"We are working hard to remove this limitation.";
|
||||
|
||||
const char notGeneratedMessage[] =
|
||||
"WebAssembly text generation was disabled.";
|
||||
|
||||
static const unsigned TooBig = 1000000;
|
||||
|
||||
static const uint32_t DefaultBinarySourceColumnNumber = 1;
|
||||
|
||||
static const CallSite*
|
||||
|
@ -75,26 +129,98 @@ DebugState::createText(JSContext* cx)
|
|||
if (!maybeBytecode_) {
|
||||
if (!buffer.append(enabledMessage))
|
||||
return nullptr;
|
||||
|
||||
MOZ_ASSERT(!maybeSourceMap_);
|
||||
} else if (binarySource_) {
|
||||
if (!buffer.append(notGeneratedMessage))
|
||||
return nullptr;
|
||||
} else {
|
||||
if (!buffer.append(noBinarySource))
|
||||
return buffer.finishString();
|
||||
} else if (maybeBytecode_->bytes.length() > TooBig) {
|
||||
if (!buffer.append(tooBigMessage))
|
||||
return nullptr;
|
||||
|
||||
MOZ_ASSERT(!maybeSourceMap_);
|
||||
} else {
|
||||
const Bytes& bytes = maybeBytecode_->bytes;
|
||||
auto sourceMap = MakeUnique<GeneratedSourceMap>();
|
||||
if (!sourceMap) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
maybeSourceMap_ = std::move(sourceMap);
|
||||
|
||||
if (!BinaryToText(cx, bytes.begin(), bytes.length(), buffer, maybeSourceMap_.get()))
|
||||
return nullptr;
|
||||
|
||||
#if DEBUG
|
||||
// Check that expression locations are sorted by line number.
|
||||
uint32_t lastLineno = 0;
|
||||
for (const ExprLoc& loc : maybeSourceMap_->exprlocs()) {
|
||||
MOZ_ASSERT(lastLineno <= loc.lineno);
|
||||
lastLineno = loc.lineno;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return buffer.finishString();
|
||||
}
|
||||
|
||||
bool
|
||||
DebugState::ensureSourceMap(JSContext* cx)
|
||||
{
|
||||
if (maybeSourceMap_ || !maybeBytecode_)
|
||||
return true;
|
||||
|
||||
// We just need to cache maybeSourceMap_, ignoring the text result.
|
||||
return createText(cx);
|
||||
}
|
||||
|
||||
struct LineComparator
|
||||
{
|
||||
const uint32_t lineno;
|
||||
explicit LineComparator(uint32_t lineno) : lineno(lineno) {}
|
||||
|
||||
int operator()(const ExprLoc& loc) const {
|
||||
return lineno == loc.lineno ? 0 : lineno < loc.lineno ? -1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
DebugState::getLineOffsets(JSContext* cx, size_t lineno, Vector<uint32_t>* offsets)
|
||||
{
|
||||
if (!debugEnabled())
|
||||
return true;
|
||||
if (!binarySource_)
|
||||
|
||||
if (binarySource_) {
|
||||
const CallSite* callsite = SlowCallSiteSearchByOffset(metadata(Tier::Debug), lineno);
|
||||
if (callsite && !offsets->append(lineno))
|
||||
return false;
|
||||
return true;
|
||||
const CallSite* callsite = SlowCallSiteSearchByOffset(metadata(Tier::Debug), lineno);
|
||||
if (callsite && !offsets->append(lineno))
|
||||
}
|
||||
|
||||
if (!ensureSourceMap(cx))
|
||||
return false;
|
||||
|
||||
if (!maybeSourceMap_)
|
||||
return true; // no source text available, keep offsets empty.
|
||||
|
||||
ExprLocVector& exprlocs = maybeSourceMap_->exprlocs();
|
||||
|
||||
// Binary search for the expression with the specified line number and
|
||||
// rewind to the first expression, if more than one expression on the same line.
|
||||
size_t match;
|
||||
if (!BinarySearchIf(exprlocs, 0, exprlocs.length(), LineComparator(lineno), &match))
|
||||
return true;
|
||||
|
||||
while (match > 0 && exprlocs[match - 1].lineno == lineno)
|
||||
match--;
|
||||
|
||||
// Return all expression offsets that were printed on the specified line.
|
||||
for (size_t i = match; i < exprlocs.length() && exprlocs[i].lineno == lineno; i++) {
|
||||
if (!offsets->append(exprlocs[i].offset))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -103,16 +229,25 @@ DebugState::getAllColumnOffsets(JSContext* cx, Vector<ExprLoc>* offsets)
|
|||
{
|
||||
if (!metadata().debugEnabled)
|
||||
return true;
|
||||
if (!binarySource_)
|
||||
|
||||
if (binarySource_) {
|
||||
for (const CallSite& callSite : metadata(Tier::Debug).callSites) {
|
||||
if (callSite.kind() != CallSite::Breakpoint)
|
||||
continue;
|
||||
uint32_t offset = callSite.lineOrBytecode();
|
||||
if (!offsets->emplaceBack(offset, DefaultBinarySourceColumnNumber, offset))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
for (const CallSite& callSite : metadata(Tier::Debug).callSites) {
|
||||
if (callSite.kind() != CallSite::Breakpoint)
|
||||
continue;
|
||||
uint32_t offset = callSite.lineOrBytecode();
|
||||
if (!offsets->emplaceBack(offset, DefaultBinarySourceColumnNumber, offset))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
if (!ensureSourceMap(cx))
|
||||
return false;
|
||||
|
||||
if (!maybeSourceMap_)
|
||||
return true; // no source text available, keep offsets empty.
|
||||
|
||||
return offsets->appendAll(maybeSourceMap_->exprlocs());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -121,13 +256,30 @@ DebugState::getOffsetLocation(JSContext* cx, uint32_t offset, bool* found, size_
|
|||
*found = false;
|
||||
if (!debugEnabled())
|
||||
return true;
|
||||
if (!binarySource_)
|
||||
|
||||
if (binarySource_) {
|
||||
if (!SlowCallSiteSearchByOffset(metadata(Tier::Debug), offset))
|
||||
return true; // offset was not found
|
||||
*found = true;
|
||||
*lineno = offset;
|
||||
*column = DefaultBinarySourceColumnNumber;
|
||||
return true;
|
||||
if (!SlowCallSiteSearchByOffset(metadata(Tier::Debug), offset))
|
||||
return true; // offset was not found
|
||||
}
|
||||
|
||||
if (!ensureSourceMap(cx))
|
||||
return false;
|
||||
|
||||
if (!maybeSourceMap_ || maybeSourceMap_->exprlocs().empty())
|
||||
return true; // no source text available
|
||||
|
||||
size_t foundAt;
|
||||
if (!maybeSourceMap_->searchLineByOffset(cx, offset, &foundAt))
|
||||
return false;
|
||||
|
||||
const ExprLoc& loc = maybeSourceMap_->exprlocs()[foundAt];
|
||||
*found = true;
|
||||
*lineno = offset;
|
||||
*column = DefaultBinarySourceColumnNumber;
|
||||
*lineno = loc.lineno;
|
||||
*column = loc.column;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -137,10 +289,18 @@ DebugState::totalSourceLines(JSContext* cx, uint32_t* count)
|
|||
*count = 0;
|
||||
if (!debugEnabled())
|
||||
return true;
|
||||
if (!binarySource_)
|
||||
|
||||
if (binarySource_) {
|
||||
if (maybeBytecode_)
|
||||
*count = maybeBytecode_->length();
|
||||
return true;
|
||||
if (maybeBytecode_)
|
||||
*count = maybeBytecode_->length();
|
||||
}
|
||||
|
||||
if (!ensureSourceMap(cx))
|
||||
return false;
|
||||
|
||||
if (maybeSourceMap_)
|
||||
*count = maybeSourceMap_->totalLines();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -548,6 +708,8 @@ DebugState::addSizeOfMisc(MallocSizeOf mallocSizeOf,
|
|||
size_t* data) const
|
||||
{
|
||||
code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenCode, code, data);
|
||||
if (maybeSourceMap_)
|
||||
*data += maybeSourceMap_->sizeOfExcludingThis(mallocSizeOf);
|
||||
if (maybeBytecode_)
|
||||
*data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
|
||||
}
|
||||
|
|
|
@ -34,8 +34,8 @@ namespace wasm {
|
|||
|
||||
struct MetadataTier;
|
||||
|
||||
// The generated source location for the AST node/expression. The offset field
|
||||
// refers an offset in an binary format file.
|
||||
// The generated source location for the AST node/expression. The offset field refers
|
||||
// an offset in an binary format file.
|
||||
|
||||
struct ExprLoc
|
||||
{
|
||||
|
@ -48,14 +48,39 @@ struct ExprLoc
|
|||
{}
|
||||
};
|
||||
|
||||
typedef Vector<ExprLoc, 0, SystemAllocPolicy> ExprLocVector;
|
||||
typedef Vector<uint32_t, 0, SystemAllocPolicy> ExprLocIndexVector;
|
||||
|
||||
// The generated source map for WebAssembly binary file. This map is generated during
|
||||
// building the text buffer (see BinaryToExperimentalText).
|
||||
|
||||
class GeneratedSourceMap
|
||||
{
|
||||
ExprLocVector exprlocs_;
|
||||
UniquePtr<ExprLocIndexVector> sortedByOffsetExprLocIndices_;
|
||||
uint32_t totalLines_;
|
||||
|
||||
public:
|
||||
explicit GeneratedSourceMap() : totalLines_(0) {}
|
||||
ExprLocVector& exprlocs() { return exprlocs_; }
|
||||
|
||||
uint32_t totalLines() { return totalLines_; }
|
||||
void setTotalLines(uint32_t val) { totalLines_ = val; }
|
||||
|
||||
bool searchLineByOffset(JSContext* cx, uint32_t offset, size_t* exprlocIndex);
|
||||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
};
|
||||
|
||||
typedef UniquePtr<GeneratedSourceMap> UniqueGeneratedSourceMap;
|
||||
typedef HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy> StepModeCounters;
|
||||
typedef HashMap<uint32_t, WasmBreakpointSite*, DefaultHasher<uint32_t>, SystemAllocPolicy>
|
||||
WasmBreakpointSiteMap;
|
||||
typedef HashMap<uint32_t, WasmBreakpointSite*, DefaultHasher<uint32_t>, SystemAllocPolicy> WasmBreakpointSiteMap;
|
||||
|
||||
class DebugState
|
||||
{
|
||||
const SharedCode code_;
|
||||
const SharedBytes maybeBytecode_;
|
||||
UniqueGeneratedSourceMap maybeSourceMap_;
|
||||
bool binarySource_;
|
||||
|
||||
// State maintained when debugging is enabled. In this case, the Code is
|
||||
|
@ -67,6 +92,7 @@ class DebugState
|
|||
StepModeCounters stepModeCounters_;
|
||||
|
||||
void toggleDebugTrap(uint32_t offset, bool enabled);
|
||||
bool ensureSourceMap(JSContext* cx);
|
||||
|
||||
public:
|
||||
DebugState(SharedCode code,
|
||||
|
@ -76,6 +102,10 @@ class DebugState
|
|||
const Bytes* maybeBytecode() const { return maybeBytecode_ ? &maybeBytecode_->bytes : nullptr; }
|
||||
bool binarySource() const { return binarySource_; }
|
||||
|
||||
// If the source bytecode was saved when this Code was constructed, this
|
||||
// method will render the binary as text. Otherwise, a diagnostic string
|
||||
// will be returned.
|
||||
|
||||
JSString* createText(JSContext* cx);
|
||||
bool getLineOffsets(JSContext* cx, size_t lineno, Vector<uint32_t>* offsets);
|
||||
bool getAllColumnOffsets(JSContext* cx, Vector<ExprLoc>* offsets);
|
||||
|
|
|
@ -5544,7 +5544,7 @@ EncodeTableSection(Encoder& e, AstModule& module)
|
|||
}
|
||||
|
||||
static bool
|
||||
EncodeFunctionBody(Encoder& e, Uint32Vector* offsets, AstFunc& func)
|
||||
EncodeFunctionBody(Encoder& e, AstFunc& func)
|
||||
{
|
||||
size_t bodySizeAt;
|
||||
if (!e.writePatchableVarU32(&bodySizeAt))
|
||||
|
@ -5559,14 +5559,10 @@ EncodeFunctionBody(Encoder& e, Uint32Vector* offsets, AstFunc& func)
|
|||
return false;
|
||||
|
||||
for (AstExpr* expr : func.body()) {
|
||||
if (!offsets->append(e.currentOffset()))
|
||||
return false;
|
||||
if (!EncodeExpr(e, *expr))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!offsets->append(e.currentOffset()))
|
||||
return false;
|
||||
if (!e.writeOp(Op::End))
|
||||
return false;
|
||||
|
||||
|
@ -5592,7 +5588,7 @@ EncodeStartSection(Encoder& e, AstModule& module)
|
|||
}
|
||||
|
||||
static bool
|
||||
EncodeCodeSection(Encoder& e, Uint32Vector* offsets, AstModule& module)
|
||||
EncodeCodeSection(Encoder& e, AstModule& module)
|
||||
{
|
||||
if (module.funcs().empty())
|
||||
return true;
|
||||
|
@ -5605,7 +5601,7 @@ EncodeCodeSection(Encoder& e, Uint32Vector* offsets, AstModule& module)
|
|||
return false;
|
||||
|
||||
for (AstFunc* func : module.funcs()) {
|
||||
if (!EncodeFunctionBody(e, offsets, *func))
|
||||
if (!EncodeFunctionBody(e, *func))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -5712,7 +5708,7 @@ EncodeElemSection(Encoder& e, AstModule& module)
|
|||
}
|
||||
|
||||
static bool
|
||||
EncodeModule(AstModule& module, Uint32Vector* offsets, Bytes* bytes)
|
||||
EncodeModule(AstModule& module, Bytes* bytes)
|
||||
{
|
||||
Encoder e(*bytes);
|
||||
|
||||
|
@ -5749,7 +5745,7 @@ EncodeModule(AstModule& module, Uint32Vector* offsets, Bytes* bytes)
|
|||
if (!EncodeElemSection(e, module))
|
||||
return false;
|
||||
|
||||
if (!EncodeCodeSection(e, offsets, module))
|
||||
if (!EncodeCodeSection(e, module))
|
||||
return false;
|
||||
|
||||
if (!EncodeDataSection(e, module))
|
||||
|
@ -5783,8 +5779,7 @@ EncodeBinaryModule(const AstModule& module, Bytes* bytes)
|
|||
/*****************************************************************************/
|
||||
|
||||
bool
|
||||
wasm::TextToBinary(const char16_t* text, uintptr_t stackLimit, Bytes* bytes, Uint32Vector* offsets,
|
||||
UniqueChars* error)
|
||||
wasm::TextToBinary(const char16_t* text, uintptr_t stackLimit, Bytes* bytes, UniqueChars* error)
|
||||
{
|
||||
LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE);
|
||||
|
||||
|
@ -5799,5 +5794,5 @@ wasm::TextToBinary(const char16_t* text, uintptr_t stackLimit, Bytes* bytes, Uin
|
|||
if (!ResolveModule(lifo, module, error))
|
||||
return false;
|
||||
|
||||
return EncodeModule(*module, offsets, bytes);
|
||||
return EncodeModule(*module, bytes);
|
||||
}
|
||||
|
|
|
@ -29,8 +29,7 @@ namespace wasm {
|
|||
// other than out-of-memory an error message string will be stored in 'error'.
|
||||
|
||||
extern MOZ_MUST_USE bool
|
||||
TextToBinary(const char16_t* text, uintptr_t stackLimit, Bytes* bytes, Uint32Vector* offsets,
|
||||
UniqueChars* error);
|
||||
TextToBinary(const char16_t* text, uintptr_t stackLimit, Bytes* bytes, UniqueChars* error);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*
|
||||
* Copyright 2016 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "wasm/WasmTextUtils.h"
|
||||
|
||||
#include "util/StringBuffer.h"
|
||||
#include "wasm/WasmTypes.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace jit;
|
||||
using namespace wasm;
|
||||
|
||||
using mozilla::IsNaN;
|
||||
|
||||
template<size_t base>
|
||||
bool
|
||||
wasm::RenderInBase(StringBuffer& sb, uint64_t num)
|
||||
{
|
||||
uint64_t n = num;
|
||||
uint64_t pow = 1;
|
||||
while (n) {
|
||||
pow *= base;
|
||||
n /= base;
|
||||
}
|
||||
pow /= base;
|
||||
|
||||
n = num;
|
||||
while (pow) {
|
||||
if (!sb.append("0123456789abcdef"[n / pow]))
|
||||
return false;
|
||||
n -= (n / pow) * pow;
|
||||
pow /= base;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool wasm::RenderInBase<10>(StringBuffer& sb, uint64_t num);
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
wasm::RenderNaN(StringBuffer& sb, T num)
|
||||
{
|
||||
typedef typename mozilla::SelectTrait<T> Traits;
|
||||
typedef typename Traits::Bits Bits;
|
||||
|
||||
MOZ_ASSERT(IsNaN(num));
|
||||
|
||||
Bits bits = mozilla::BitwiseCast<Bits>(num);
|
||||
if ((bits & Traits::kSignBit) && !sb.append("-"))
|
||||
return false;
|
||||
if (!sb.append("nan"))
|
||||
return false;
|
||||
|
||||
Bits payload = bits & Traits::kSignificandBits;
|
||||
// Only render the payload if it's not the spec's default NaN.
|
||||
if (payload == ((Traits::kSignificandBits + 1) >> 1))
|
||||
return true;
|
||||
|
||||
return sb.append(":0x") &&
|
||||
RenderInBase<16>(sb, payload);
|
||||
}
|
||||
|
||||
template MOZ_MUST_USE bool wasm::RenderNaN(StringBuffer& b, float num);
|
||||
template MOZ_MUST_USE bool wasm::RenderNaN(StringBuffer& b, double num);
|
|
@ -0,0 +1,105 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
*
|
||||
* Copyright 2016 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef wasm_text_utils
|
||||
#define wasm_text_utils
|
||||
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
#include "util/StringBuffer.h"
|
||||
|
||||
namespace js {
|
||||
namespace wasm {
|
||||
|
||||
template<size_t base>
|
||||
MOZ_MUST_USE bool
|
||||
RenderInBase(StringBuffer& sb, uint64_t num);
|
||||
|
||||
template<class T>
|
||||
MOZ_MUST_USE bool
|
||||
RenderNaN(StringBuffer& sb, T num);
|
||||
|
||||
// Helper class, StringBuffer wrapper, to track the position (line and column)
|
||||
// within the generated source.
|
||||
|
||||
class WasmPrintBuffer
|
||||
{
|
||||
StringBuffer& stringBuffer_;
|
||||
uint32_t lineno_;
|
||||
uint32_t column_;
|
||||
|
||||
public:
|
||||
explicit WasmPrintBuffer(StringBuffer& stringBuffer)
|
||||
: stringBuffer_(stringBuffer),
|
||||
lineno_(1),
|
||||
column_(1)
|
||||
{}
|
||||
inline char processChar(char ch) {
|
||||
if (ch == '\n') {
|
||||
lineno_++; column_ = 1;
|
||||
} else
|
||||
column_++;
|
||||
return ch;
|
||||
}
|
||||
inline char16_t processChar(char16_t ch) {
|
||||
if (ch == '\n') {
|
||||
lineno_++; column_ = 1;
|
||||
} else
|
||||
column_++;
|
||||
return ch;
|
||||
}
|
||||
bool append(const char ch) {
|
||||
return stringBuffer_.append(processChar(ch));
|
||||
}
|
||||
bool append(const char16_t ch) {
|
||||
return stringBuffer_.append(processChar(ch));
|
||||
}
|
||||
bool append(const char* str, size_t length) {
|
||||
for (size_t i = 0; i < length; i++)
|
||||
processChar(str[i]);
|
||||
return stringBuffer_.append(str, length);
|
||||
}
|
||||
bool append(const char16_t* begin, const char16_t* end) {
|
||||
for (const char16_t* p = begin; p != end; p++)
|
||||
processChar(*p);
|
||||
return stringBuffer_.append(begin, end);
|
||||
}
|
||||
bool append(const char16_t* str, size_t length) {
|
||||
return append(str, str + length);
|
||||
}
|
||||
template <size_t ArrayLength>
|
||||
bool append(const char (&array)[ArrayLength]) {
|
||||
static_assert(ArrayLength > 0, "null-terminated");
|
||||
MOZ_ASSERT(array[ArrayLength - 1] == '\0');
|
||||
return append(array, ArrayLength - 1);
|
||||
}
|
||||
char16_t getChar(size_t index) {
|
||||
return stringBuffer_.getChar(index);
|
||||
}
|
||||
size_t length() {
|
||||
return stringBuffer_.length();
|
||||
}
|
||||
StringBuffer& stringBuffer() { return stringBuffer_; }
|
||||
uint32_t lineno() { return lineno_; }
|
||||
uint32_t column() { return column_; }
|
||||
};
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
||||
#endif // namespace wasm_text_utils
|
|
@ -132,6 +132,9 @@ struct ModuleEnvironment
|
|||
bool funcIsImport(uint32_t funcIndex) const {
|
||||
return funcIndex < funcImportGlobalDataOffsets.length();
|
||||
}
|
||||
uint32_t funcIndexToFuncTypeIndex(uint32_t funcIndex) const {
|
||||
return TypeDef::fromFuncTypeWithIdPtr(funcTypes[funcIndex]) - types.begin();
|
||||
}
|
||||
};
|
||||
|
||||
// The Encoder class appends bytes to the Bytes object it is given during
|
||||
|
|
Загрузка…
Ссылка в новой задаче