v8/test/mjsunit/wasm/asm-wasm-stack.js
Clemens Backes 003f622abe [wasm] Implement toString of exported functions
We currently print asm.js functions converted to wasm as
"function foo() { [native code] }", even though without asm to wasm
translation we get the proper source code. This is an observable
difference that should not be, and also foozzie finds this frequently in
different variations.

This CL makes us remember the start position (position of the "function"
token) and end position (right behind the closing "}") of each function
we transform to wasm. These offsets, together with the Script that
contained the function, allows us to reconstruct the source code of the
function for the {toString()} method.

R=jkummerow@chromium.org

Bug: chromium:667678
Change-Id: If22471cad4cefdfc67f6d1b8fda85aa0eeb411bd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2016582
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65972}
2020-01-24 12:53:31 +00:00

157 lines
4.5 KiB
JavaScript

// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --validate-asm --allow-natives-syntax
var filename = '(?:[^ ]+/)?test/mjsunit/wasm/asm-wasm-stack.js';
filename = filename.replace(/\//g, '[/\\\\]');
function checkPreformattedStack(e, expected_lines) {
print('preformatted stack: ' + e.stack);
var lines = e.stack.split('\n');
assertEquals(expected_lines.length, lines.length);
for (var i = 0; i < lines.length; ++i) {
assertMatches(expected_lines[i], lines[i], 'line ' + i);
}
}
function printCallsites(stack) {
print('callsite objects (size ' + stack.length + '):');
for (var i = 0; i < stack.length; ++i) {
var s = stack[i];
print(
' [' + i + '] ' + s.getFunctionName() + ' (' + s.getFileName() + ':' +
s.getLineNumber() + ':' + s.getColumnNumber() + ')');
}
}
function checkCallsiteArray(stack, expected) {
assertEquals(expected.length, stack.length, 'stack size');
for (var i = 0; i < expected.length; ++i) {
var cs = stack[i];
assertMatches('^' + filename + '$', cs.getFileName(), 'file name at ' + i);
assertEquals(expected[i][0], cs.getFunctionName(), 'function name at ' + i);
assertEquals(expected[i][1], cs.getLineNumber(), 'line number at ' + i);
assertEquals(expected[i][2], cs.getColumnNumber(), 'column number at ' + i);
assertNotNull(cs.getThis(), 'receiver should be global');
assertEquals(stack[0].getThis(), cs.getThis(), 'receiver should be global');
}
}
function checkFunctionsOnCallsites(e, expected) {
printCallsites(e.stack);
checkCallsiteArray(e.stack, expected);
}
function checkTopFunctionsOnCallsites(e, expected) {
printCallsites(e.stack);
assertTrue(
e.stack.length >= expected.length, 'expected at least ' +
expected.length + ' callsites, got ' + e.stack.length);
checkCallsiteArray(e.stack.slice(0, expected.length), expected);
}
function throwException() {
throw new Error('exception from JS');
}
function generateWasmFromAsmJs(stdlib, foreign) {
'use asm';
var throwFunc = foreign.throwFunc;
function callThrow() {
throwFunc();
}
function redirectFun(i) {
i = i | 0;
switch (i | 0) {
case 0: callThrow(); break;
case 1: redirectFun(0); break;
case 2: redirectFun(1); break;
case 3: funTable[i & 0](2); break;
case 4: forwardFun(); break;
}
}
function forwardFun() {
redirectFun(3);
}
var funTable = [ redirectFun ];
return redirectFun;
}
(function PreformattedStackTraceFromJS() {
var fun = generateWasmFromAsmJs(this, {throwFunc: throwException});
assertTrue(%IsWasmCode(fun));
var e = null;
try {
fun(0);
} catch (ex) {
e = ex;
}
assertInstanceof(e, Error, 'exception should have been thrown');
checkPreformattedStack(e, [
'^Error: exception from JS$',
'^ *at throwException \\(' + filename + ':56:9\\)$',
'^ *at callThrow \\(' + filename + ':63:5\\)$',
'^ *at redirectFun \\(' + filename + ':68:15\\)$',
'^ *at PreformattedStackTraceFromJS \\(' + filename + ':87:5\\)$',
'^ *at ' + filename + ':100:3$'
]);
})();
// Now collect the Callsite objects instead of just a string.
Error.prepareStackTrace = function(error, frames) {
return frames;
};
(function CallsiteObjectsFromJS() {
var fun = generateWasmFromAsmJs(this, {throwFunc: throwException});
assertTrue(%IsWasmCode(fun));
var e = null;
try {
fun(4);
} catch (ex) {
e = ex;
}
assertInstanceof(e, Error, 'exception should have been thrown');
checkFunctionsOnCallsites(e, [
['throwException', 56, 9], // --
['callThrow', 63, 5], // --
['redirectFun', 68, 15], // --
['redirectFun', 69, 15], // --
['redirectFun', 70, 15], // --
['redirectFun', 71, 30], // --
['forwardFun', 76, 5], // --
['redirectFun', 72, 15], // --
['CallsiteObjectsFromJS', 112, 5], // --
[null, 129, 3]
]);
})();
function generateOverflowWasmFromAsmJs() {
'use asm';
function f(a) {
a = a | 0;
return f(a) | 0;
}
return f;
}
(function StackOverflowPosition() {
var fun = generateOverflowWasmFromAsmJs();
assertTrue(%IsWasmCode(fun));
var e = null;
try {
fun(23);
} catch (ex) {
e = ex;
}
assertInstanceof(e, RangeError, 'RangeError should have been thrown');
checkTopFunctionsOnCallsites(e, [
['f', 133, 3], // --
['f', 135, 12], // --
['f', 135, 12], // --
['f', 135, 12] // --
]);
})();