Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(502)

Side by Side Diff: test/cctest/wasm/wasm-run-utils.h

Issue 1972153002: [wasm] Implement an interpreter for WASM. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: stupid skip Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef WASM_RUN_UTILS_H 5 #ifndef WASM_RUN_UTILS_H
6 #define WASM_RUN_UTILS_H 6 #define WASM_RUN_UTILS_H
7 7
8 #include <stdint.h> 8 #include <stdint.h>
9 #include <stdlib.h> 9 #include <stdlib.h>
10 #include <string.h> 10 #include <string.h>
11 11
12 #include "src/base/accounting-allocator.h"
12 #include "src/base/utils/random-number-generator.h" 13 #include "src/base/utils/random-number-generator.h"
13 14
14 #include "src/compiler/graph-visualizer.h" 15 #include "src/compiler/graph-visualizer.h"
15 #include "src/compiler/int64-lowering.h" 16 #include "src/compiler/int64-lowering.h"
16 #include "src/compiler/js-graph.h" 17 #include "src/compiler/js-graph.h"
17 #include "src/compiler/node.h" 18 #include "src/compiler/node.h"
18 #include "src/compiler/pipeline.h" 19 #include "src/compiler/pipeline.h"
19 #include "src/compiler/wasm-compiler.h" 20 #include "src/compiler/wasm-compiler.h"
20 #include "src/compiler/zone-pool.h" 21 #include "src/compiler/zone-pool.h"
21 22
22 #include "src/wasm/ast-decoder.h" 23 #include "src/wasm/ast-decoder.h"
24 #include "src/wasm/wasm-interpreter.h"
23 #include "src/wasm/wasm-js.h" 25 #include "src/wasm/wasm-js.h"
24 #include "src/wasm/wasm-macro-gen.h" 26 #include "src/wasm/wasm-macro-gen.h"
25 #include "src/wasm/wasm-module.h" 27 #include "src/wasm/wasm-module.h"
26 #include "src/wasm/wasm-opcodes.h" 28 #include "src/wasm/wasm-opcodes.h"
27 29
28 #include "src/zone.h" 30 #include "src/zone.h"
29 31
30 #include "test/cctest/cctest.h" 32 #include "test/cctest/cctest.h"
31 #include "test/cctest/compiler/call-tester.h" 33 #include "test/cctest/compiler/call-tester.h"
32 #include "test/cctest/compiler/graph-builder-tester.h" 34 #include "test/cctest/compiler/graph-builder-tester.h"
33 35
34 // TODO(titzer): pull WASM_64 up to a common header. 36 // TODO(titzer): pull WASM_64 up to a common header.
35 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 37 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
36 #define WASM_64 1 38 #define WASM_64 1
37 #else 39 #else
38 #define WASM_64 0 40 #define WASM_64 0
39 #endif 41 #endif
40 42
41 static const uint32_t kMaxFunctions = 10; 43 static const uint32_t kMaxFunctions = 10;
44 #define WASM_INTERPRETER 1
Clemens Hammacher 2016/05/24 12:47:03 This can be removed now.
titzer 2016/05/24 14:50:48 Done.
45
46 enum WasmExecutionMode { kExecuteInterpreted, kExecuteCompiled };
42 47
43 // TODO(titzer): check traps more robustly in tests. 48 // TODO(titzer): check traps more robustly in tests.
44 // Currently, in tests, we just return 0xdeadbeef from the function in which 49 // Currently, in tests, we just return 0xdeadbeef from the function in which
45 // the trap occurs if the runtime context is not available to throw a JavaScript 50 // the trap occurs if the runtime context is not available to throw a JavaScript
46 // exception. 51 // exception.
47 #define CHECK_TRAP32(x) \ 52 #define CHECK_TRAP32(x) \
48 CHECK_EQ(0xdeadbeef, (bit_cast<uint32_t>(x)) & 0xFFFFFFFF) 53 CHECK_EQ(0xdeadbeef, (bit_cast<uint32_t>(x)) & 0xFFFFFFFF)
49 #define CHECK_TRAP64(x) \ 54 #define CHECK_TRAP64(x) \
50 CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF) 55 CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF)
51 #define CHECK_TRAP(x) CHECK_TRAP32(x) 56 #define CHECK_TRAP(x) CHECK_TRAP32(x)
(...skipping 13 matching lines...) Expand all
65 using namespace v8::internal::compiler; 70 using namespace v8::internal::compiler;
66 using namespace v8::internal::wasm; 71 using namespace v8::internal::wasm;
67 72
68 const uint32_t kMaxGlobalsSize = 128; 73 const uint32_t kMaxGlobalsSize = 128;
69 74
70 // A helper for module environments that adds the ability to allocate memory 75 // A helper for module environments that adds the ability to allocate memory
71 // and global variables. Contains a built-in {WasmModule} and 76 // and global variables. Contains a built-in {WasmModule} and
72 // {WasmModuleInstance}. 77 // {WasmModuleInstance}.
73 class TestingModule : public ModuleEnv { 78 class TestingModule : public ModuleEnv {
74 public: 79 public:
75 TestingModule() 80 explicit TestingModule(WasmExecutionMode mode = kExecuteCompiled)
76 : instance_(&module_), 81 : execution_mode_(mode),
82 instance_(&module_),
77 isolate_(CcTest::InitIsolateOnce()), 83 isolate_(CcTest::InitIsolateOnce()),
78 global_offset(0) { 84 global_offset(0),
85 interpreter_(mode == kExecuteInterpreted
86 ? new WasmInterpreter(&instance_, &allocator_)
87 : nullptr) {
79 module = &module_; 88 module = &module_;
80 instance = &instance_; 89 instance = &instance_;
81 instance->module = &module_; 90 instance->module = &module_;
82 instance->globals_start = global_data; 91 instance->globals_start = global_data;
83 instance->globals_size = kMaxGlobalsSize; 92 instance->globals_size = kMaxGlobalsSize;
84 instance->mem_start = nullptr; 93 instance->mem_start = nullptr;
85 instance->mem_size = 0; 94 instance->mem_size = 0;
86 linker = nullptr; 95 linker = nullptr;
87 origin = kWasmOrigin; 96 origin = kWasmOrigin;
88 memset(global_data, 0, sizeof(global_data)); 97 memset(global_data, 0, sizeof(global_data));
89 } 98 }
90 99
91 ~TestingModule() { 100 ~TestingModule() {
92 if (instance->mem_start) { 101 if (instance->mem_start) {
93 free(instance->mem_start); 102 free(instance->mem_start);
94 } 103 }
104 if (interpreter_) delete interpreter_;
95 } 105 }
96 106
97 byte* AddMemory(size_t size) { 107 byte* AddMemory(size_t size) {
98 CHECK_NULL(instance->mem_start); 108 CHECK_NULL(instance->mem_start);
99 CHECK_EQ(0, instance->mem_size); 109 CHECK_EQ(0, instance->mem_size);
100 instance->mem_start = reinterpret_cast<byte*>(malloc(size)); 110 instance->mem_start = reinterpret_cast<byte*>(malloc(size));
101 CHECK(instance->mem_start); 111 CHECK(instance->mem_start);
102 memset(instance->mem_start, 0, size); 112 memset(instance->mem_start, 0, size);
103 instance->mem_size = size; 113 instance->mem_size = size;
104 return raw_mem_start<byte>(); 114 return raw_mem_start<byte>();
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 175
166 uint32_t AddFunction(FunctionSig* sig, Handle<Code> code) { 176 uint32_t AddFunction(FunctionSig* sig, Handle<Code> code) {
167 if (module->functions.size() == 0) { 177 if (module->functions.size() == 0) {
168 // TODO(titzer): Reserving space here to avoid the underlying WasmFunction 178 // TODO(titzer): Reserving space here to avoid the underlying WasmFunction
169 // structs from moving. 179 // structs from moving.
170 module->functions.reserve(kMaxFunctions); 180 module->functions.reserve(kMaxFunctions);
171 } 181 }
172 uint32_t index = static_cast<uint32_t>(module->functions.size()); 182 uint32_t index = static_cast<uint32_t>(module->functions.size());
173 module->functions.push_back({sig, index, 0, 0, 0, 0, 0, false}); 183 module->functions.push_back({sig, index, 0, 0, 0, 0, 0, false});
174 instance->function_code.push_back(code); 184 instance->function_code.push_back(code);
185 WasmFunction* function = &module->functions.back();
Clemens Hammacher 2016/05/24 12:47:03 This can be moved inside the if.
titzer 2016/05/24 14:50:48 Done.
186 if (interpreter_) {
187 int interpreter_index = interpreter_->AddFunctionForTesting(function);
188 CHECK_EQ(index, static_cast<uint32_t>(interpreter_index));
189 }
175 DCHECK_LT(index, kMaxFunctions); // limited for testing. 190 DCHECK_LT(index, kMaxFunctions); // limited for testing.
176 return index; 191 return index;
177 } 192 }
178 193
179 uint32_t AddJsFunction(FunctionSig* sig, const char* source) { 194 uint32_t AddJsFunction(FunctionSig* sig, const char* source) {
180 Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle( 195 Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
181 *v8::Local<v8::Function>::Cast(CompileRun(source)))); 196 *v8::Local<v8::Function>::Cast(CompileRun(source))));
182 uint32_t index = AddFunction(sig, Handle<Code>::null()); 197 uint32_t index = AddFunction(sig, Handle<Code>::null());
183 WasmName module_name = ArrayVector("test"); 198 WasmName module_name = ArrayVector("test");
184 WasmName function_name; 199 WasmName function_name;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 int table_size = static_cast<int>(module->function_table.size()); 232 int table_size = static_cast<int>(module->function_table.size());
218 for (int i = 0; i < table_size; i++) { 233 for (int i = 0; i < table_size; i++) {
219 int function_index = module->function_table[i]; 234 int function_index = module->function_table[i];
220 WasmFunction* function = &module->functions[function_index]; 235 WasmFunction* function = &module->functions[function_index];
221 instance->function_table->set(i, Smi::FromInt(function->sig_index)); 236 instance->function_table->set(i, Smi::FromInt(function->sig_index));
222 instance->function_table->set(i + table_size, 237 instance->function_table->set(i + table_size,
223 *instance->function_code[function_index]); 238 *instance->function_code[function_index]);
224 } 239 }
225 } 240 }
226 241
242 WasmInterpreter* interpreter() { return interpreter_; }
243 WasmExecutionMode execution_mode() { return execution_mode_; }
244
227 private: 245 private:
246 WasmExecutionMode execution_mode_;
228 WasmModule module_; 247 WasmModule module_;
229 WasmModuleInstance instance_; 248 WasmModuleInstance instance_;
230 Isolate* isolate_; 249 Isolate* isolate_;
250 v8::base::AccountingAllocator allocator_;
231 uint32_t global_offset; 251 uint32_t global_offset;
232 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. 252 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data.
253 WasmInterpreter* interpreter_;
233 254
234 WasmGlobal* AddGlobal(MachineType mem_type) { 255 WasmGlobal* AddGlobal(MachineType mem_type) {
235 byte size = WasmOpcodes::MemSize(mem_type); 256 byte size = WasmOpcodes::MemSize(mem_type);
236 global_offset = (global_offset + size - 1) & ~(size - 1); // align 257 global_offset = (global_offset + size - 1) & ~(size - 1); // align
237 module->globals.push_back({0, 0, mem_type, global_offset, false}); 258 module->globals.push_back({0, 0, mem_type, global_offset, false});
238 global_offset += size; 259 global_offset += size;
239 // limit number of globals. 260 // limit number of globals.
240 CHECK_LT(global_offset, kMaxGlobalsSize); 261 CHECK_LT(global_offset, kMaxGlobalsSize);
241 return &module->globals.back(); 262 return &module->globals.back();
242 } 263 }
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 422
402 private: 423 private:
403 Node* inner_code_node_; 424 Node* inner_code_node_;
404 Handle<Code> code_; 425 Handle<Code> code_;
405 Signature<MachineType>* signature_; 426 Signature<MachineType>* signature_;
406 }; 427 };
407 428
408 // A helper for compiling WASM functions for testing. This class can create a 429 // A helper for compiling WASM functions for testing. This class can create a
409 // standalone function if {module} is NULL or a function within a 430 // standalone function if {module} is NULL or a function within a
410 // {TestingModule}. It contains the internal state for compilation (i.e. 431 // {TestingModule}. It contains the internal state for compilation (i.e.
411 // TurboFan graph) and, later, interpretation. 432 // TurboFan graph) and interpretation (by adding to the interpreter manually).
412 class WasmFunctionCompiler : public HandleAndZoneScope, 433 class WasmFunctionCompiler : public HandleAndZoneScope,
413 private GraphAndBuilders { 434 private GraphAndBuilders {
414 public: 435 public:
415 explicit WasmFunctionCompiler( 436 explicit WasmFunctionCompiler(
437 FunctionSig* sig, WasmExecutionMode mode,
438 Vector<const char> debug_name = ArrayVector("<WASM UNNAMED>"))
439 : GraphAndBuilders(main_zone()),
440 execution_mode_(mode),
441 jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
442 nullptr, this->machine()),
443 sig(sig),
444 descriptor_(nullptr),
445 testing_module_(nullptr),
446 debug_name_(debug_name),
447 local_decls(main_zone(), sig),
448 source_position_table_(this->graph()),
449 interpreter_(nullptr) {
450 // Create our own function.
451 function_ = new WasmFunction();
452 function_->sig = sig;
453 function_->func_index = 0;
454 function_->sig_index = 0;
455 if (mode == kExecuteInterpreted) {
456 interpreter_ = new WasmInterpreter(nullptr, zone()->allocator());
457 int index = interpreter_->AddFunctionForTesting(function_);
458 CHECK_EQ(0, index);
459 }
460 }
461
462 explicit WasmFunctionCompiler(
416 FunctionSig* sig, TestingModule* module, 463 FunctionSig* sig, TestingModule* module,
417 Vector<const char> debug_name = ArrayVector("<WASM UNNAMED>")) 464 Vector<const char> debug_name = ArrayVector("<WASM UNNAMED>"))
418 : GraphAndBuilders(main_zone()), 465 : GraphAndBuilders(main_zone()),
466 execution_mode_(module->execution_mode()),
419 jsgraph(this->isolate(), this->graph(), this->common(), nullptr, 467 jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
420 nullptr, this->machine()), 468 nullptr, this->machine()),
421 sig(sig), 469 sig(sig),
422 descriptor_(nullptr), 470 descriptor_(nullptr),
423 testing_module_(module), 471 testing_module_(module),
424 debug_name_(debug_name), 472 debug_name_(debug_name),
425 local_decls(main_zone(), sig), 473 local_decls(main_zone(), sig),
426 source_position_table_(this->graph()) { 474 source_position_table_(this->graph()),
427 if (module) { 475 interpreter_(module->interpreter()) {
428 // Get a new function from the testing module. 476 // Get a new function from the testing module.
429 function_ = nullptr; 477 int index = module->AddFunction(sig, Handle<Code>::null());
430 function_index_ = module->AddFunction(sig, Handle<Code>::null()); 478 function_ = &testing_module_->module->functions[index];
431 } else {
432 // Create our own function.
433 function_ = new WasmFunction();
434 function_->sig = sig;
435 function_index_ = 0;
436 }
437 } 479 }
438 480
439 ~WasmFunctionCompiler() { 481 ~WasmFunctionCompiler() {
440 if (function_) delete function_; 482 if (testing_module_) return; // testing module owns the below things.
483 delete function_;
484 if (interpreter_) delete interpreter_;
441 } 485 }
442 486
487 WasmExecutionMode execution_mode_;
443 JSGraph jsgraph; 488 JSGraph jsgraph;
444 FunctionSig* sig; 489 FunctionSig* sig;
445 // The call descriptor is initialized when the function is compiled. 490 // The call descriptor is initialized when the function is compiled.
446 CallDescriptor* descriptor_; 491 CallDescriptor* descriptor_;
447 TestingModule* testing_module_; 492 TestingModule* testing_module_;
448 Vector<const char> debug_name_; 493 Vector<const char> debug_name_;
449 WasmFunction* function_; 494 WasmFunction* function_;
450 int function_index_;
451 LocalDeclEncoder local_decls; 495 LocalDeclEncoder local_decls;
452 SourcePositionTable source_position_table_; 496 SourcePositionTable source_position_table_;
497 WasmInterpreter* interpreter_;
453 498
454 Isolate* isolate() { return main_isolate(); } 499 Isolate* isolate() { return main_isolate(); }
455 Graph* graph() const { return main_graph_; } 500 Graph* graph() const { return main_graph_; }
456 Zone* zone() const { return graph()->zone(); } 501 Zone* zone() const { return graph()->zone(); }
457 CommonOperatorBuilder* common() { return &main_common_; } 502 CommonOperatorBuilder* common() { return &main_common_; }
458 MachineOperatorBuilder* machine() { return &main_machine_; } 503 MachineOperatorBuilder* machine() { return &main_machine_; }
459 void InitializeDescriptor() { 504 void InitializeDescriptor() {
460 if (descriptor_ == nullptr) { 505 if (descriptor_ == nullptr) {
461 descriptor_ = testing_module_->GetWasmCallDescriptor(main_zone(), sig); 506 descriptor_ = testing_module_->GetWasmCallDescriptor(main_zone(), sig);
462 } 507 }
463 } 508 }
464 CallDescriptor* descriptor() { return descriptor_; } 509 CallDescriptor* descriptor() { return descriptor_; }
510 int function_index() { return static_cast<int>(function_->func_index); }
Clemens Hammacher 2016/05/24 12:47:03 You could use this function in all the code below.
titzer 2016/05/24 14:50:47 Done.
465 511
466 void Build(const byte* start, const byte* end) { 512 void Build(const byte* start, const byte* end) {
467 // Build the TurboFan graph. 513 // Build the TurboFan graph.
468 local_decls.Prepend(&start, &end); 514 local_decls.Prepend(main_zone(), &start, &end);
469 TestBuildingGraph(main_zone(), &jsgraph, testing_module_, sig, 515 TestBuildingGraph(main_zone(), &jsgraph, testing_module_, sig,
470 &source_position_table_, start, end); 516 &source_position_table_, start, end);
471 delete[] start; 517 if (interpreter_) {
518 // Add the code to the interpreter.
519 CHECK(interpreter_->SetFunctionCodeForTesting(function_, start, end));
520 }
472 } 521 }
473 522
474 byte AllocateLocal(LocalType type) { 523 byte AllocateLocal(LocalType type) {
475 uint32_t index = local_decls.AddLocals(1, type); 524 uint32_t index = local_decls.AddLocals(1, type);
476 byte result = static_cast<byte>(index); 525 byte result = static_cast<byte>(index);
477 DCHECK_EQ(index, result); 526 DCHECK_EQ(index, result);
478 return result; 527 return result;
479 } 528 }
480 529
481 Handle<Code> Compile() { 530 Handle<Code> Compile() {
482 InitializeDescriptor(); 531 InitializeDescriptor();
483 CallDescriptor* desc = descriptor_; 532 CallDescriptor* desc = descriptor_;
484 if (kPointerSize == 4) { 533 if (kPointerSize == 4) {
485 desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc); 534 desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc);
486 } 535 }
487 CompilationInfo info(debug_name_, this->isolate(), this->zone(), 536 CompilationInfo info(debug_name_, this->isolate(), this->zone(),
488 Code::ComputeFlags(Code::WASM_FUNCTION)); 537 Code::ComputeFlags(Code::WASM_FUNCTION));
489 v8::base::SmartPointer<CompilationJob> job(Pipeline::NewWasmCompilationJob( 538 v8::base::SmartPointer<CompilationJob> job(Pipeline::NewWasmCompilationJob(
490 &info, graph(), desc, &source_position_table_)); 539 &info, graph(), desc, &source_position_table_));
491 if (job->OptimizeGraph() != CompilationJob::SUCCEEDED || 540 if (job->OptimizeGraph() != CompilationJob::SUCCEEDED ||
492 job->GenerateCode() != CompilationJob::SUCCEEDED) 541 job->GenerateCode() != CompilationJob::SUCCEEDED)
493 return Handle<Code>::null(); 542 return Handle<Code>::null();
494 543
495 Handle<Code> code = info.code(); 544 Handle<Code> code = info.code();
496 545
497 // Length is always 2, since usually <wasm_obj, func_index> is stored in the 546 // Length is always 2, since usually <wasm_obj, func_index> is stored in
547 // the
Clemens Hammacher 2016/05/24 12:47:03 Huh, what happened here? The "the" should still fi
ahaas 2016/05/24 14:48:27 Fix the line break.
titzer 2016/05/24 14:50:48 Done.
498 // deopt data. Here, we only store the function index. 548 // deopt data. Here, we only store the function index.
499 DCHECK(code->deoptimization_data() == nullptr || 549 DCHECK(code->deoptimization_data() == nullptr ||
500 code->deoptimization_data()->length() == 0); 550 code->deoptimization_data()->length() == 0);
501 Handle<FixedArray> deopt_data = 551 Handle<FixedArray> deopt_data =
502 isolate()->factory()->NewFixedArray(2, TENURED); 552 isolate()->factory()->NewFixedArray(2, TENURED);
503 deopt_data->set(1, Smi::FromInt(function_index_)); 553 deopt_data->set(1, Smi::FromInt(function_->func_index));
504 deopt_data->set_length(2); 554 deopt_data->set_length(2);
505 code->set_deoptimization_data(*deopt_data); 555 code->set_deoptimization_data(*deopt_data);
506 556
507 #ifdef ENABLE_DISASSEMBLER 557 #ifdef ENABLE_DISASSEMBLER
508 if (FLAG_print_opt_code) { 558 if (FLAG_print_opt_code) {
509 OFStream os(stdout); 559 OFStream os(stdout);
510 code->Disassemble("wasm code", os); 560 code->Disassemble("wasm code", os);
511 } 561 }
512 #endif 562 #endif
513 563
514 return code; 564 return code;
515 } 565 }
516 566
517 uint32_t CompileAndAdd(uint16_t sig_index = 0) { 567 uint32_t CompileAndAdd(uint16_t sig_index = 0) {
518 CHECK(testing_module_); 568 CHECK(testing_module_);
519 function()->sig_index = sig_index; 569 function_->sig_index = sig_index;
520 Handle<Code> code = Compile(); 570 Handle<Code> code = Compile();
521 testing_module_->SetFunctionCode(function_index_, code); 571 testing_module_->SetFunctionCode(function_->func_index, code);
522 return static_cast<uint32_t>(function_index_); 572 return static_cast<uint32_t>(function_->func_index);
523 }
524
525 WasmFunction* function() {
526 if (function_) return function_;
527 return &testing_module_->module->functions[function_index_];
528 } 573 }
529 574
530 // Set the context, such that e.g. runtime functions can be called. 575 // Set the context, such that e.g. runtime functions can be called.
531 void SetModuleContext() { 576 void SetModuleContext() {
532 if (!testing_module_->instance->context.is_null()) { 577 if (!testing_module_->instance->context.is_null()) {
533 CHECK(testing_module_->instance->context.is_identical_to( 578 CHECK(testing_module_->instance->context.is_identical_to(
534 main_isolate()->native_context())); 579 main_isolate()->native_context()));
535 return; 580 return;
536 } 581 }
537 testing_module_->instance->context = main_isolate()->native_context(); 582 testing_module_->instance->context = main_isolate()->native_context();
538 } 583 }
539 }; 584 };
540 585
541 // A helper class to build graphs from Wasm bytecode, generate machine 586 // A helper class to build graphs from Wasm bytecode, generate machine
542 // code, and run that code. 587 // code, and run that code.
543 template <typename ReturnType> 588 template <typename ReturnType>
544 class WasmRunner { 589 class WasmRunner {
545 public: 590 public:
546 WasmRunner(MachineType p0 = MachineType::None(), 591 WasmRunner(WasmExecutionMode execution_mode,
592 MachineType p0 = MachineType::None(),
547 MachineType p1 = MachineType::None(), 593 MachineType p1 = MachineType::None(),
548 MachineType p2 = MachineType::None(), 594 MachineType p2 = MachineType::None(),
549 MachineType p3 = MachineType::None()) 595 MachineType p3 = MachineType::None())
550 : zone(&allocator_), 596 : zone(&allocator_),
551 compiled_(false), 597 compiled_(false),
552 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, 598 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
553 GetParameterCount(p0, p1, p2, p3), storage_), 599 GetParameterCount(p0, p1, p2, p3), storage_),
554 compiler_(&signature_, nullptr) { 600 compiler_(&signature_, execution_mode) {
555 InitSigStorage(p0, p1, p2, p3); 601 InitSigStorage(p0, p1, p2, p3);
556 } 602 }
557 603
558 WasmRunner(TestingModule* module, MachineType p0 = MachineType::None(), 604 WasmRunner(TestingModule* module, MachineType p0 = MachineType::None(),
559 MachineType p1 = MachineType::None(), 605 MachineType p1 = MachineType::None(),
560 MachineType p2 = MachineType::None(), 606 MachineType p2 = MachineType::None(),
561 MachineType p3 = MachineType::None()) 607 MachineType p3 = MachineType::None())
562 : zone(&allocator_), 608 : zone(&allocator_),
563 compiled_(false), 609 compiled_(false),
564 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, 610 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
(...skipping 22 matching lines...) Expand all
587 compiler_.InitializeDescriptor(); 633 compiler_.InitializeDescriptor();
588 wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3); 634 wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3);
589 } 635 }
590 636
591 // Builds a graph from the given Wasm code and generates the machine 637 // Builds a graph from the given Wasm code and generates the machine
592 // code and call wrapper for that graph. This method must not be called 638 // code and call wrapper for that graph. This method must not be called
593 // more than once. 639 // more than once.
594 void Build(const byte* start, const byte* end) { 640 void Build(const byte* start, const byte* end) {
595 CHECK(!compiled_); 641 CHECK(!compiled_);
596 compiled_ = true; 642 compiled_ = true;
643 compiler_.Build(start, end);
597 644
598 // Build the TF graph within the compiler. 645 if (!interpret()) {
599 compiler_.Build(start, end); 646 // Compile machine code and install it into the module.
600 // Generate code. 647 Handle<Code> code = compiler_.Compile();
601 Handle<Code> code = compiler_.Compile();
602 648
603 if (compiler_.testing_module_) { 649 if (compiler_.testing_module_) {
604 // Update the table of function code in the module. 650 // Update the table of function code in the module.
605 compiler_.testing_module_->SetFunctionCode(compiler_.function_index_, 651 compiler_.testing_module_->SetFunctionCode(
606 code); 652 compiler_.function_->func_index, code);
653 }
654
655 wrapper_.SetInnerCode(code);
607 } 656 }
608
609 wrapper_.SetInnerCode(code);
610 } 657 }
611 658
612 ReturnType Call() { return Call(0, 0, 0, 0); } 659 ReturnType Call() {
660 if (interpret()) {
661 return CallInterpreter(nullptr, 0);
662 } else {
663 return Call(0, 0, 0, 0);
664 }
665 }
613 666
614 template <typename P0> 667 template <typename P0>
615 ReturnType Call(P0 p0) { 668 ReturnType Call(P0 p0) {
616 return Call(p0, 0, 0, 0); 669 if (interpret()) {
670 WasmVal args[] = {WasmVal(p0)};
671 return CallInterpreter(args, 1);
672 } else {
673 return Call(p0, 0, 0, 0);
674 }
617 } 675 }
618 676
619 template <typename P0, typename P1> 677 template <typename P0, typename P1>
620 ReturnType Call(P0 p0, P1 p1) { 678 ReturnType Call(P0 p0, P1 p1) {
621 return Call(p0, p1, 0, 0); 679 if (interpret()) {
680 WasmVal args[] = {WasmVal(p0), WasmVal(p1)};
681 return CallInterpreter(args, 2);
682 } else {
683 return Call(p0, p1, 0, 0);
684 }
622 } 685 }
623 686
624 template <typename P0, typename P1, typename P2> 687 template <typename P0, typename P1, typename P2>
625 ReturnType Call(P0 p0, P1 p1, P2 p2) { 688 ReturnType Call(P0 p0, P1 p1, P2 p2) {
626 return Call(p0, p1, p2, 0); 689 if (interpret()) {
690 WasmVal args[] = {WasmVal(p0), WasmVal(p1), WasmVal(p2)};
691 return CallInterpreter(args, 3);
692 } else {
693 return Call(p0, p1, p2, 0);
694 }
627 } 695 }
628 696
629 template <typename P0, typename P1, typename P2, typename P3> 697 template <typename P0, typename P1, typename P2, typename P3>
630 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) { 698 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) {
631 CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(), 699 if (interpret()) {
632 wrapper_.GetWrapperCode(), wrapper_.signature()); 700 WasmVal args[] = {WasmVal(p0), WasmVal(p1), WasmVal(p2), WasmVal(p3)};
633 ReturnType return_value; 701 return CallInterpreter(args, 4);
634 int32_t result = runner.Call<void*, void*, void*, void*, void*>( 702 } else {
635 &p0, &p1, &p2, &p3, &return_value); 703 CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
636 CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result); 704 wrapper_.GetWrapperCode(),
637 return return_value; 705 wrapper_.signature());
706 ReturnType return_value;
707 int32_t result = runner.Call<void*, void*, void*, void*, void*>(
708 &p0, &p1, &p2, &p3, &return_value);
709 CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result);
710 return return_value;
711 }
712 }
713
714 ReturnType CallInterpreter(WasmVal* args, int count) {
Clemens Hammacher 2016/05/24 12:47:03 Looks like a candidate for Vector<WasmVal*>.
titzer 2016/05/24 14:50:48 Done.
715 CHECK_EQ(count,
716 static_cast<int>(compiler_.function_->sig->parameter_count()));
717 WasmInterpreter::Thread& thread = interpreter()->GetThread(0);
718 thread.Reset();
719 thread.PushFrame(compiler_.function_, args);
720 if (thread.Run() == WasmInterpreter::FINISHED) {
721 WasmVal val = thread.GetReturnValue();
722 return val.to<ReturnType>();
723 } else if (thread.state() == WasmInterpreter::TRAPPED) {
724 // TODO(titzer): return the correct trap code
725 int64_t result = 0xdeadbeefdeadbeef;
726 return static_cast<ReturnType>(result);
727 } else {
728 // TODO(titzer): falling off end
729 ReturnType val = 0;
730 return val;
731 }
638 } 732 }
639 733
640 byte AllocateLocal(LocalType type) { return compiler_.AllocateLocal(type); } 734 byte AllocateLocal(LocalType type) { return compiler_.AllocateLocal(type); }
641 735
736 WasmFunction* function() { return compiler_.function_; }
737 WasmInterpreter* interpreter() { return compiler_.interpreter_; }
738
642 protected: 739 protected:
643 v8::base::AccountingAllocator allocator_; 740 v8::base::AccountingAllocator allocator_;
644 Zone zone; 741 Zone zone;
645 bool compiled_; 742 bool compiled_;
646 LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS]; 743 LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS];
647 FunctionSig signature_; 744 FunctionSig signature_;
648 WasmFunctionCompiler compiler_; 745 WasmFunctionCompiler compiler_;
649 WasmFunctionWrapper<ReturnType> wrapper_; 746 WasmFunctionWrapper<ReturnType> wrapper_;
650 747
748 bool interpret() { return compiler_.execution_mode_ == kExecuteInterpreted; }
749
651 static size_t GetParameterCount(MachineType p0, MachineType p1, 750 static size_t GetParameterCount(MachineType p0, MachineType p1,
652 MachineType p2, MachineType p3) { 751 MachineType p2, MachineType p3) {
653 if (p0 == MachineType::None()) return 0; 752 if (p0 == MachineType::None()) return 0;
654 if (p1 == MachineType::None()) return 1; 753 if (p1 == MachineType::None()) return 1;
655 if (p2 == MachineType::None()) return 2; 754 if (p2 == MachineType::None()) return 2;
656 if (p3 == MachineType::None()) return 3; 755 if (p3 == MachineType::None()) return 3;
657 return 4; 756 return 4;
658 } 757 }
659 }; 758 };
660 759
661 // A macro to define tests that run in different engine configurations. 760 // A macro to define tests that run in different engine configurations.
662 // Currently only supports compiled tests, but a future 761 // Currently only supports compiled tests, but a future
663 // RunWasmInterpreted_##name version will allow each test to also run in the 762 // RunWasmInterpreted_##name version will allow each test to also run in the
664 // interpreter. 763 // interpreter.
665 #define WASM_EXEC_TEST(name) \ 764 #define WASM_EXEC_TEST(name) \
666 void RunWasm_##name(); \ 765 void RunWasm_##name(WasmExecutionMode execution_mode); \
667 TEST(RunWasmCompiled_##name) { RunWasm_##name(); } \ 766 TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \
668 void RunWasm_##name() 767 TEST(RunWasmInterpreted_##name) { RunWasm_##name(kExecuteInterpreted); } \
768 void RunWasm_##name(WasmExecutionMode execution_mode)
Clemens Hammacher 2016/05/24 12:47:03 Passing this execution_mode explicitely adds a ton
titzer 2016/05/24 14:50:48 Explicit is better than relying on global state, e
669 769
670 } // namespace 770 } // namespace
671 771
672 #endif 772 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698