Chromium Code Reviews| Index: test/cctest/wasm/wasm-run-utils.h |
| diff --git a/test/cctest/wasm/wasm-run-utils.h b/test/cctest/wasm/wasm-run-utils.h |
| index d6dd893064d71627f332fa42393ae090e1545713..7c8bccafd99a36b4f23d0cf6eba74c634a20468b 100644 |
| --- a/test/cctest/wasm/wasm-run-utils.h |
| +++ b/test/cctest/wasm/wasm-run-utils.h |
| @@ -9,6 +9,7 @@ |
| #include <stdlib.h> |
| #include <string.h> |
| +#include "src/base/accounting-allocator.h" |
| #include "src/base/utils/random-number-generator.h" |
| #include "src/compiler/graph-visualizer.h" |
| @@ -20,6 +21,7 @@ |
| #include "src/compiler/zone-pool.h" |
| #include "src/wasm/ast-decoder.h" |
| +#include "src/wasm/wasm-interpreter.h" |
| #include "src/wasm/wasm-js.h" |
| #include "src/wasm/wasm-macro-gen.h" |
| #include "src/wasm/wasm-module.h" |
| @@ -39,6 +41,7 @@ |
| #endif |
| static const uint32_t kMaxFunctions = 10; |
| +#define WASM_INTERPRETER 1 |
| // TODO(titzer): check traps more robustly in tests. |
| // Currently, in tests, we just return 0xdeadbeef from the function in which |
| @@ -72,7 +75,10 @@ const uint32_t kMaxGlobalsSize = 128; |
| // {WasmModuleInstance}. |
| class TestingModule : public ModuleEnv { |
| public: |
| - TestingModule() : instance_(&module_), global_offset(0) { |
| + TestingModule() |
| + : instance_(&module_), |
| + global_offset(0), |
| + interpreter_(&instance_, &allocator_) { |
| module_.shared_isolate = CcTest::InitIsolateOnce(); |
| module = &module_; |
| instance = &instance_; |
| @@ -171,6 +177,9 @@ class TestingModule : public ModuleEnv { |
| module->functions.push_back( |
| {sig, index, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false}); |
| instance->function_code.push_back(code); |
| + WasmFunction* function = &module->functions.back(); |
| + int interpreter_index = interpreter_.AddFunctionForTesting(function); |
| + DCHECK_EQ(index, static_cast<uint32_t>(interpreter_index)); |
| DCHECK_LT(index, kMaxFunctions); // limited for testing. |
| return index; |
| } |
| @@ -226,11 +235,18 @@ class TestingModule : public ModuleEnv { |
| } |
| } |
| + WasmInterpreter* GetInterpreter() { return &interpreter_; } |
| + |
| private: |
| WasmModule module_; |
| WasmModuleInstance instance_; |
| + v8::base::AccountingAllocator allocator_; |
| uint32_t global_offset; |
| V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. |
| + // TODO(titzer): This is ugly. Because the functions must be manually added |
| + // to the interpreter for testing, it needs to be accessible to each creation |
| + // of a WasmFunctionCompiler below. |
| + WasmInterpreter interpreter_; |
| WasmGlobal* AddGlobal(MachineType mem_type) { |
| byte size = WasmOpcodes::MemSize(mem_type); |
| @@ -409,7 +425,7 @@ class WasmFunctionWrapper : public HandleAndZoneScope, |
| // A helper for compiling WASM functions for testing. This class can create a |
| // standalone function if {module} is NULL or a function within a |
| // {TestingModule}. It contains the internal state for compilation (i.e. |
| -// TurboFan graph) and, later, interpretation. |
| +// TurboFan graph) and interpretation (by adding to the interpreter manually). |
| class WasmFunctionCompiler : public HandleAndZoneScope, |
| private GraphAndBuilders { |
| public: |
| @@ -463,12 +479,25 @@ class WasmFunctionCompiler : public HandleAndZoneScope, |
| } |
| CallDescriptor* descriptor() { return descriptor_; } |
| - void Build(const byte* start, const byte* end) { |
| + void Build(const byte* start, const byte* end, |
| + WasmInterpreter* interpreter = nullptr) { |
| // Build the TurboFan graph. |
| local_decls.Prepend(&start, &end); |
| TestBuildingGraph(main_zone(), &jsgraph, testing_module_, sig, |
| &source_position_table_, start, end); |
| - delete[] start; |
| +#if WASM_INTERPRETER |
| + // Build the interpreter code. |
| + if (!testing_module_) { |
| + // No module; the function was never added to the interpreter. |
| + int index = interpreter->AddFunctionForTesting(function_); |
| + CHECK_EQ(function_index_, index); |
| + } else { |
| + // Always use the interpreter from the module. |
| + interpreter = testing_module_->GetInterpreter(); |
| + } |
| + CHECK(interpreter->SetFunctionCodeForTesting(function(), start, end)); |
| +// TODO(titzer): memory leak!!!! delete[] start; |
|
Clemens Hammacher
2016/05/12 15:20:55
SetFunctionCodeForTesting could allocate memory fo
|
| +#endif |
| } |
| byte AllocateLocal(LocalType type) { |
| @@ -551,7 +580,8 @@ class WasmRunner { |
| compiled_(false), |
| signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, |
| GetParameterCount(p0, p1, p2, p3), storage_), |
| - compiler_(&signature_, nullptr) { |
| + compiler_(&signature_, nullptr), |
| + interpreter_(new WasmInterpreter(nullptr, &allocator_)) { |
| InitSigStorage(p0, p1, p2, p3); |
| } |
| @@ -563,7 +593,8 @@ class WasmRunner { |
| compiled_(false), |
| signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, |
| GetParameterCount(p0, p1, p2, p3), storage_), |
| - compiler_(&signature_, module) { |
| + compiler_(&signature_, module), |
| + interpreter_(nullptr) { |
| DCHECK(module); |
| InitSigStorage(p0, p1, p2, p3); |
| } |
| @@ -595,50 +626,112 @@ class WasmRunner { |
| CHECK(!compiled_); |
| compiled_ = true; |
| - // Build the TF graph within the compiler. |
| - compiler_.Build(start, end); |
| - // Generate code. |
| - Handle<Code> code = compiler_.Compile(); |
| + if (WASM_INTERPRETER) { |
| + // Build the interpreter code. |
| + compiler_.Build(start, end, interpreter_); |
| + } else { |
| + // Build the TF graph within the compiler. |
| + compiler_.Build(start, end); |
| + // Generate code. |
| + Handle<Code> code = compiler_.Compile(); |
| + |
| + if (compiler_.testing_module_) { |
| + // Update the table of function code in the module. |
| + compiler_.testing_module_->SetFunctionCode(compiler_.function_index_, |
| + code); |
| + } |
| - if (compiler_.testing_module_) { |
| - // Update the table of function code in the module. |
| - compiler_.testing_module_->SetFunctionCode(compiler_.function_index_, |
| - code); |
| + wrapper_.SetInnerCode(code); |
| } |
| - |
| - wrapper_.SetInnerCode(code); |
| } |
| - ReturnType Call() { return Call(0, 0, 0, 0); } |
| + ReturnType Call() { |
| + if (WASM_INTERPRETER) { |
| + return CallInterpreter(nullptr, 0); |
| + } else { |
| + return Call(0, 0, 0, 0); |
| + } |
| + } |
| template <typename P0> |
| ReturnType Call(P0 p0) { |
| - return Call(p0, 0, 0, 0); |
| + if (WASM_INTERPRETER) { |
| + WasmVal args[] = {WasmVal(p0)}; |
| + return CallInterpreter(args, 1); |
| + } else { |
| + return Call(p0, 0, 0, 0); |
| + } |
| } |
| template <typename P0, typename P1> |
| ReturnType Call(P0 p0, P1 p1) { |
| - return Call(p0, p1, 0, 0); |
| + if (WASM_INTERPRETER) { |
| + WasmVal args[] = {WasmVal(p0), WasmVal(p1)}; |
| + return CallInterpreter(args, 2); |
| + } else { |
| + return Call(p0, p1, 0, 0); |
| + } |
| } |
| template <typename P0, typename P1, typename P2> |
| ReturnType Call(P0 p0, P1 p1, P2 p2) { |
| - return Call(p0, p1, p2, 0); |
| + if (WASM_INTERPRETER) { |
| + WasmVal args[] = {WasmVal(p0), WasmVal(p1), WasmVal(p2)}; |
| + return CallInterpreter(args, 3); |
| + } else { |
| + return Call(p0, p1, p2, 0); |
| + } |
| } |
| template <typename P0, typename P1, typename P2, typename P3> |
| ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) { |
| - CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(), |
| - wrapper_.GetWrapperCode(), wrapper_.signature()); |
| - ReturnType return_value; |
| - int32_t result = runner.Call<void*, void*, void*, void*, void*>( |
| - &p0, &p1, &p2, &p3, &return_value); |
| - CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result); |
| - return return_value; |
| + if (WASM_INTERPRETER) { |
| + WasmVal args[] = {WasmVal(p0), WasmVal(p1), WasmVal(p2), WasmVal(p3)}; |
| + return CallInterpreter(args, 4); |
| + } else { |
| + CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(), |
| + wrapper_.GetWrapperCode(), |
| + wrapper_.signature()); |
| + ReturnType return_value; |
| + int32_t result = runner.Call<void*, void*, void*, void*, void*>( |
| + &p0, &p1, &p2, &p3, &return_value); |
| + CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result); |
| + return return_value; |
| + } |
| + } |
| + |
| + ReturnType CallInterpreter(WasmVal* args, int count) { |
| + CHECK_EQ(count, |
| + static_cast<int>(compiler_.function()->sig->parameter_count())); |
| + WasmInterpreter* interpreter = GetInterpreter(); |
| + |
| + WasmInterpreter::Thread& thread = interpreter->GetThread(0); |
| + thread.Reset(); |
| + thread.PushFrame(compiler_.function(), args); |
| + if (thread.Run() == WasmInterpreter::FINISHED) { |
| + WasmVal val = thread.GetReturnValue(); |
| + return val.to<ReturnType>(); |
| + } else if (thread.state() == WasmInterpreter::TRAPPED) { |
| + // TODO(titzer): return the correct trap code |
| + int64_t result = 0xdeadbeefdeadbeef; |
| + return static_cast<ReturnType>(result); |
| + } else { |
|
ahaas
2016/05/13 12:18:55
if the program is more than 1000 (wasm-interpreter
|
| + // TODO(titzer): falling off end |
| + ReturnType val = 0; |
| + return val; |
| + } |
| } |
| byte AllocateLocal(LocalType type) { return compiler_.AllocateLocal(type); } |
| + WasmInterpreter* GetInterpreter() { |
| + return compiler_.testing_module_ |
| + ? compiler_.testing_module_->GetInterpreter() |
| + : interpreter_; |
| + } |
| + |
| + WasmFunction* function() { return compiler_.function(); } |
| + |
| protected: |
| v8::base::AccountingAllocator allocator_; |
| Zone zone; |
| @@ -647,6 +740,7 @@ class WasmRunner { |
| FunctionSig signature_; |
| WasmFunctionCompiler compiler_; |
| WasmFunctionWrapper<ReturnType> wrapper_; |
| + WasmInterpreter* interpreter_; |
| static size_t GetParameterCount(MachineType p0, MachineType p1, |
| MachineType p2, MachineType p3) { |