Commit 3b6b8119 authored by titzer's avatar titzer Committed by Commit bot

[wasm] Add utilities to print out WASM ast directly from the bytes.

Motivated by finding a bug in a larger module, this CL adds the ability
to dump out a byte-by-byte, nested view of the decoded AST. This
byte-by-byte output uses the opcode enum to make it readable, but is
suitable for pasting into a byte[] in C or JS and thus making a regression
test.

Also fix a bug; the case of running out of registers for indirect calls.

R=ahaas@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1616973004

Cr-Commit-Position: refs/heads/master@{#33442}
parent 14f4f8fc
......@@ -1491,13 +1491,14 @@ void CodeGenerator::AssembleReturn() {
__ Bind(&return_label_);
if (descriptor->UseNativeStack()) {
__ Mov(csp, fp);
pop_count += (pop_count & 1); // align
} else {
__ Mov(jssp, fp);
}
__ Pop(fp, lr);
}
} else if (descriptor->UseNativeStack()) {
pop_count += (pop_count & 1);
pop_count += (pop_count & 1); // align
}
__ Drop(pop_count);
__ Ret();
......
......@@ -58,7 +58,7 @@ LinkageLocation stackloc(int i) {
// ===========================================================================
// == ia32 ===================================================================
// ===========================================================================
#define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi, edi
#define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi
#define GP_RETURN_REGISTERS eax, edx
#define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
#define FP_RETURN_REGISTERS xmm1, xmm2
......@@ -76,7 +76,7 @@ LinkageLocation stackloc(int i) {
// ===========================================================================
// == x87 ====================================================================
// ===========================================================================
#define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi, edi
#define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi
#define GP_RETURN_REGISTERS eax, edx
#define FP_RETURN_REGISTERS stX_0
......
......@@ -473,6 +473,7 @@ DEFINE_BOOL(expose_wasm, false, "expose WASM interface to JavaScript")
DEFINE_BOOL(trace_wasm_decoder, false, "trace decoding of wasm code")
DEFINE_BOOL(trace_wasm_decode_time, false, "trace decoding time of wasm code")
DEFINE_BOOL(trace_wasm_compiler, false, "trace compiling of wasm code")
DEFINE_BOOL(trace_wasm_ast, false, "dump AST after WASM decode")
DEFINE_BOOL(wasm_break_on_decoder_error, false,
"debug break when wasm decoder encounters an error")
......
......@@ -151,15 +151,20 @@ class LR_WasmDecoder : public Decoder {
}
if (ok()) {
if (FLAG_trace_wasm_ast) {
PrintAst(function_env, pc, end);
}
if (FLAG_trace_wasm_decode_time) {
double ms = decode_timer.Elapsed().InMillisecondsF();
PrintF(" - decoding took %0.3f ms\n", ms);
PrintF("wasm-decode ok (%0.3f ms)\n\n", ms);
} else {
TRACE("wasm-decode ok\n\n");
}
TRACE("wasm-decode ok\n\n");
} else {
TRACE("wasm-error module+%-6d func+%d: %s\n\n", baserel(error_pc_),
startrel(error_pc_), error_msg_.get());
}
return toResult(tree);
}
......@@ -1477,7 +1482,17 @@ int OpcodeLength(const byte* pc) {
FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
{
// Loads and stores have an optional offset.
byte bitfield = pc[1];
if (MemoryAccess::OffsetField::decode(bitfield)) {
int length;
uint32_t result = 0;
ReadUnsignedLEB128Operand(pc + 2, pc + 7, &length, &result);
return 2 + length;
}
return 2;
}
case kExprI8Const:
case kExprBlock:
case kExprLoop:
......@@ -1578,6 +1593,37 @@ int OpcodeArity(FunctionEnv* env, const byte* pc) {
UNREACHABLE();
return 0;
}
void PrintAst(FunctionEnv* env, const byte* start, const byte* end) {
const byte* pc = start;
std::vector<int> arity_stack;
while (pc < end) {
int arity = OpcodeArity(env, pc);
size_t length = OpcodeLength(pc);
for (auto arity : arity_stack) {
printf(" ");
USE(arity);
}
WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
printf("k%s,", WasmOpcodes::OpcodeName(opcode));
for (size_t i = 1; i < length; i++) {
printf(" 0x%02x,", pc[i]);
}
pc += length;
printf("\n");
arity_stack.push_back(arity);
while (arity_stack.back() == 0) {
arity_stack.pop_back();
if (arity_stack.empty()) break;
arity_stack.back()--;
}
}
}
} // namespace wasm
} // namespace internal
} // namespace v8
......@@ -89,6 +89,8 @@ TreeResult VerifyWasmCode(FunctionEnv* env, const byte* base, const byte* start,
TreeResult BuildTFGraph(TFBuilder* builder, FunctionEnv* env, const byte* base,
const byte* start, const byte* end);
void PrintAst(FunctionEnv* env, const byte* start, const byte* end);
inline TreeResult VerifyWasmCode(FunctionEnv* env, const byte* start,
const byte* end) {
return VerifyWasmCode(env, nullptr, start, end);
......
......@@ -2837,19 +2837,17 @@ TEST(Run_Wasm_LoadStoreI64_sx) {
TEST(Run_Wasm_SimpleCallIndirect) {
Isolate* isolate = CcTest::InitIsolateOnce();
WasmRunner<int32_t> r(MachineType::Int32());
TestSignatures sigs;
TestingModule module;
r.env()->module = &module;
WasmFunctionCompiler t1(sigs.i_ii());
BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
t1.CompileAndAdd(&module);
t1.CompileAndAdd(&module, /*sig_index*/ 1);
WasmFunctionCompiler t2(sigs.i_ii());
BUILD(t2, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
t2.CompileAndAdd(&module);
t2.CompileAndAdd(&module, /*sig_index*/ 1);
// Signature table.
module.AddSignature(sigs.f_ff());
......@@ -2857,18 +2855,9 @@ TEST(Run_Wasm_SimpleCallIndirect) {
module.AddSignature(sigs.d_dd());
// Function table.
int table_size = 2;
module.module->function_table = new std::vector<uint16_t>;
module.module->function_table->push_back(0);
module.module->function_table->push_back(1);
// Function table.
Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size);
fixed->set(0, Smi::FromInt(1));
fixed->set(1, Smi::FromInt(1));
fixed->set(2, *module.function_code->at(0));
fixed->set(3, *module.function_code->at(1));
module.function_table = fixed;
int table[] = {0, 1};
module.AddIndirectFunctionTable(table, 2);
module.PopulateIndirectFunctionTable();
// Builder the caller function.
BUILD(r, WASM_CALL_INDIRECT(1, WASM_GET_LOCAL(0), WASM_I8(66), WASM_I8(22)));
......@@ -2880,8 +2869,6 @@ TEST(Run_Wasm_SimpleCallIndirect) {
TEST(Run_Wasm_MultipleCallIndirect) {
Isolate* isolate = CcTest::InitIsolateOnce();
WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32(),
MachineType::Int32());
TestSignatures sigs;
......@@ -2889,11 +2876,11 @@ TEST(Run_Wasm_MultipleCallIndirect) {
r.env()->module = &module;
WasmFunctionCompiler t1(sigs.i_ii());
BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
t1.CompileAndAdd(&module);
t1.CompileAndAdd(&module, /*sig_index*/ 1);
WasmFunctionCompiler t2(sigs.i_ii());
BUILD(t2, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
t2.CompileAndAdd(&module);
t2.CompileAndAdd(&module, /*sig_index*/ 1);
// Signature table.
module.AddSignature(sigs.f_ff());
......@@ -2901,18 +2888,9 @@ TEST(Run_Wasm_MultipleCallIndirect) {
module.AddSignature(sigs.d_dd());
// Function table.
int table_size = 2;
module.module->function_table = new std::vector<uint16_t>;
module.module->function_table->push_back(0);
module.module->function_table->push_back(1);
// Function table.
Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size);
fixed->set(0, Smi::FromInt(1));
fixed->set(1, Smi::FromInt(1));
fixed->set(2, *module.function_code->at(0));
fixed->set(3, *module.function_code->at(1));
module.function_table = fixed;
int table[] = {0, 1};
module.AddIndirectFunctionTable(table, 2);
module.PopulateIndirectFunctionTable();
// Builder the caller function.
BUILD(r,
......@@ -3275,4 +3253,49 @@ TEST(Run_Wasm_F32CopySign) {
}
}
#endif
void CompileCallIndirectMany(LocalType param) {
// Make sure we don't run out of registers when compiling indirect calls
// with many many parameters.
TestSignatures sigs;
for (byte num_params = 0; num_params < 40; num_params++) {
Zone zone;
HandleScope scope(CcTest::InitIsolateOnce());
TestingModule module;
FunctionSig* sig = sigs.many(&zone, kAstStmt, param, num_params);
module.AddSignature(sig);
module.AddSignature(sig);
module.AddIndirectFunctionTable(nullptr, 0);
WasmFunctionCompiler t(sig);
t.env.module = &module;
std::vector<byte> code;
ADD_CODE(code, kExprCallIndirect, 1);
ADD_CODE(code, kExprI8Const, 0);
for (byte p = 0; p < num_params; p++) {
ADD_CODE(code, kExprGetLocal, p);
}
t.Build(&code[0], &code[0] + code.size());
t.Compile(&module);
}
}
TEST(Compile_Wasm_CallIndirect_Many_i32) { CompileCallIndirectMany(kAstI32); }
#if WASM_64
TEST(Compile_Wasm_CallIndirect_Many_i64) { CompileCallIndirectMany(kAstI64); }
#endif
TEST(Compile_Wasm_CallIndirect_Many_f32) { CompileCallIndirectMany(kAstF32); }
TEST(Compile_Wasm_CallIndirect_Many_f64) { CompileCallIndirectMany(kAstF64); }
......@@ -72,6 +72,15 @@ class TestSignatures {
FunctionSig* v_ii() { return &sig_v_ii; }
FunctionSig* v_iii() { return &sig_v_iii; }
FunctionSig* many(Zone* zone, LocalType ret, LocalType param, int count) {
FunctionSig::Builder builder(zone, ret == kAstStmt ? 0 : 1, count);
if (ret != kAstStmt) builder.AddReturn(ret);
for (int i = 0; i < count; i++) {
builder.AddParam(param);
}
return builder.Build();
}
private:
LocalType kIntTypes4[4];
LocalType kLongTypes4[4];
......
......@@ -168,6 +168,30 @@ class TestingModule : public ModuleEnv {
return &module->functions->back();
}
void AddIndirectFunctionTable(int* functions, int table_size) {
AllocModule();
Isolate* isolate = module->shared_isolate;
Handle<FixedArray> fixed =
isolate->factory()->NewFixedArray(2 * table_size);
function_table = fixed;
module->function_table = new std::vector<uint16_t>();
for (int i = 0; i < table_size; i++) {
module->function_table->push_back(functions[i]);
}
}
void PopulateIndirectFunctionTable() {
if (function_table.is_null()) return;
int table_size = static_cast<int>(module->function_table->size());
for (int i = 0; i < table_size; i++) {
int function_index = module->function_table->at(i);
WasmFunction* function = &module->functions->at(function_index);
function_table->set(i, Smi::FromInt(function->sig_index));
function_table->set(i + table_size, *function_code->at(function_index));
}
}
private:
size_t mem_size;
uint32_t global_offset;
......@@ -271,12 +295,13 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
return result;
}
uint32_t CompileAndAdd(TestingModule* module) {
uint32_t CompileAndAdd(TestingModule* module, int sig_index = 0) {
uint32_t index = 0;
if (module->module && module->module->functions) {
index = static_cast<uint32_t>(module->module->functions->size());
}
module->AddFunction(env.sig, Compile(module));
WasmFunction* function = module->AddFunction(env.sig, Compile(module));
function->sig_index = sig_index;
return index;
}
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment