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) { |