OLD | NEW |
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> |
(...skipping 18 matching lines...) Expand all Loading... |
29 #include "test/cctest/compiler/call-tester.h" | 29 #include "test/cctest/compiler/call-tester.h" |
30 #include "test/cctest/compiler/graph-builder-tester.h" | 30 #include "test/cctest/compiler/graph-builder-tester.h" |
31 | 31 |
32 // TODO(titzer): pull WASM_64 up to a common header. | 32 // TODO(titzer): pull WASM_64 up to a common header. |
33 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 | 33 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 |
34 #define WASM_64 1 | 34 #define WASM_64 1 |
35 #else | 35 #else |
36 #define WASM_64 0 | 36 #define WASM_64 0 |
37 #endif | 37 #endif |
38 | 38 |
| 39 static const uint32_t kMaxFunctions = 10; |
| 40 |
39 // TODO(titzer): check traps more robustly in tests. | 41 // TODO(titzer): check traps more robustly in tests. |
40 // Currently, in tests, we just return 0xdeadbeef from the function in which | 42 // Currently, in tests, we just return 0xdeadbeef from the function in which |
41 // the trap occurs if the runtime context is not available to throw a JavaScript | 43 // the trap occurs if the runtime context is not available to throw a JavaScript |
42 // exception. | 44 // exception. |
43 #define CHECK_TRAP32(x) \ | 45 #define CHECK_TRAP32(x) \ |
44 CHECK_EQ(0xdeadbeef, (bit_cast<uint32_t>(x)) & 0xFFFFFFFF) | 46 CHECK_EQ(0xdeadbeef, (bit_cast<uint32_t>(x)) & 0xFFFFFFFF) |
45 #define CHECK_TRAP64(x) \ | 47 #define CHECK_TRAP64(x) \ |
46 CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF) | 48 CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF) |
47 #define CHECK_TRAP(x) CHECK_TRAP32(x) | 49 #define CHECK_TRAP(x) CHECK_TRAP32(x) |
48 | 50 |
(...skipping 12 matching lines...) Expand all Loading... |
61 env->local_i32_count = 0; | 63 env->local_i32_count = 0; |
62 env->local_i64_count = 0; | 64 env->local_i64_count = 0; |
63 env->local_f32_count = 0; | 65 env->local_f32_count = 0; |
64 env->local_f64_count = 0; | 66 env->local_f64_count = 0; |
65 env->SumLocals(); | 67 env->SumLocals(); |
66 } | 68 } |
67 | 69 |
68 const uint32_t kMaxGlobalsSize = 128; | 70 const uint32_t kMaxGlobalsSize = 128; |
69 | 71 |
70 // A helper for module environments that adds the ability to allocate memory | 72 // A helper for module environments that adds the ability to allocate memory |
71 // and global variables. Contains a built-in {WasmModuleInstance}. | 73 // and global variables. Contains a built-in {WasmModule} and |
| 74 // {WasmModuleInstance}. |
72 class TestingModule : public ModuleEnv { | 75 class TestingModule : public ModuleEnv { |
73 public: | 76 public: |
74 TestingModule() : instance_(nullptr), global_offset(0) { | 77 TestingModule() : instance_(&module_), global_offset(0) { |
| 78 module_.shared_isolate = CcTest::InitIsolateOnce(); |
| 79 module = &module_; |
75 instance = &instance_; | 80 instance = &instance_; |
| 81 instance->module = &module_; |
76 instance->globals_start = global_data; | 82 instance->globals_start = global_data; |
77 instance->globals_size = kMaxGlobalsSize; | 83 instance->globals_size = kMaxGlobalsSize; |
78 instance->mem_start = nullptr; | 84 instance->mem_start = nullptr; |
79 instance->mem_size = 0; | 85 instance->mem_size = 0; |
80 instance->function_code = nullptr; | 86 instance->function_code = nullptr; |
81 module = nullptr; | |
82 linker = nullptr; | 87 linker = nullptr; |
83 asm_js = false; | 88 asm_js = false; |
84 memset(global_data, 0, sizeof(global_data)); | 89 memset(global_data, 0, sizeof(global_data)); |
85 } | 90 } |
86 | 91 |
87 ~TestingModule() { | 92 ~TestingModule() { |
88 if (instance->mem_start) { | 93 if (instance->mem_start) { |
89 free(instance->mem_start); | 94 free(instance->mem_start); |
90 } | 95 } |
91 if (instance->function_code) delete instance->function_code; | 96 if (instance->function_code) { |
92 if (module) delete module; | 97 delete instance->function_code; |
| 98 } |
93 } | 99 } |
94 | 100 |
95 byte* AddMemory(size_t size) { | 101 byte* AddMemory(size_t size) { |
96 CHECK_NULL(instance->mem_start); | 102 CHECK_NULL(instance->mem_start); |
97 CHECK_EQ(0, instance->mem_size); | 103 CHECK_EQ(0, instance->mem_size); |
98 instance->mem_start = reinterpret_cast<byte*>(malloc(size)); | 104 instance->mem_start = reinterpret_cast<byte*>(malloc(size)); |
99 CHECK(instance->mem_start); | 105 CHECK(instance->mem_start); |
100 memset(instance->mem_start, 0, size); | 106 memset(instance->mem_start, 0, size); |
101 instance->mem_size = size; | 107 instance->mem_size = size; |
102 return raw_mem_start<byte>(); | 108 return raw_mem_start<byte>(); |
103 } | 109 } |
104 | 110 |
105 template <typename T> | 111 template <typename T> |
106 T* AddMemoryElems(size_t count) { | 112 T* AddMemoryElems(size_t count) { |
107 AddMemory(count * sizeof(T)); | 113 AddMemory(count * sizeof(T)); |
108 return raw_mem_start<T>(); | 114 return raw_mem_start<T>(); |
109 } | 115 } |
110 | 116 |
111 template <typename T> | 117 template <typename T> |
112 T* AddGlobal(MachineType mem_type) { | 118 T* AddGlobal(MachineType mem_type) { |
113 WasmGlobal* global = AddGlobal(mem_type); | 119 WasmGlobal* global = AddGlobal(mem_type); |
114 return reinterpret_cast<T*>(instance->globals_start + global->offset); | 120 return reinterpret_cast<T*>(instance->globals_start + global->offset); |
115 } | 121 } |
116 | 122 |
117 byte AddSignature(FunctionSig* sig) { | 123 byte AddSignature(FunctionSig* sig) { |
118 AllocModule(); | |
119 if (!module->signatures) { | 124 if (!module->signatures) { |
120 module->signatures = new std::vector<FunctionSig*>(); | 125 module->signatures = new std::vector<FunctionSig*>(); |
121 } | 126 } |
122 module->signatures->push_back(sig); | 127 module->signatures->push_back(sig); |
123 size_t size = module->signatures->size(); | 128 size_t size = module->signatures->size(); |
124 CHECK(size < 127); | 129 CHECK(size < 127); |
125 return static_cast<byte>(size - 1); | 130 return static_cast<byte>(size - 1); |
126 } | 131 } |
127 | 132 |
128 template <typename T> | 133 template <typename T> |
(...skipping 29 matching lines...) Expand all Loading... |
158 | 163 |
159 // Pseudo-randomly intialize the memory. | 164 // Pseudo-randomly intialize the memory. |
160 void RandomizeMemory(unsigned int seed = 88) { | 165 void RandomizeMemory(unsigned int seed = 88) { |
161 byte* raw = raw_mem_start<byte>(); | 166 byte* raw = raw_mem_start<byte>(); |
162 byte* end = raw_mem_end<byte>(); | 167 byte* end = raw_mem_end<byte>(); |
163 v8::base::RandomNumberGenerator rng; | 168 v8::base::RandomNumberGenerator rng; |
164 rng.SetSeed(seed); | 169 rng.SetSeed(seed); |
165 rng.NextBytes(raw, end - raw); | 170 rng.NextBytes(raw, end - raw); |
166 } | 171 } |
167 | 172 |
168 WasmFunction* AddFunction(FunctionSig* sig, Handle<Code> code) { | 173 int AddFunction(FunctionSig* sig, Handle<Code> code) { |
169 AllocModule(); | |
170 if (module->functions == nullptr) { | 174 if (module->functions == nullptr) { |
171 module->functions = new std::vector<WasmFunction>(); | 175 module->functions = new std::vector<WasmFunction>(); |
| 176 // TODO(titzer): Reserving space here to avoid the underlying WasmFunction |
| 177 // structs from moving. |
| 178 module->functions->reserve(kMaxFunctions); |
172 instance->function_code = new std::vector<Handle<Code>>(); | 179 instance->function_code = new std::vector<Handle<Code>>(); |
173 } | 180 } |
174 uint32_t index = static_cast<uint32_t>(module->functions->size()); | 181 uint32_t index = static_cast<uint32_t>(module->functions->size()); |
175 module->functions->push_back( | 182 module->functions->push_back( |
176 {sig, index, 0, 0, 0, 0, 0, 0, 0, false, false}); | 183 {sig, index, 0, 0, 0, 0, 0, 0, 0, false, false}); |
177 instance->function_code->push_back(code); | 184 instance->function_code->push_back(code); |
178 return &module->functions->back(); | 185 DCHECK_LT(index, kMaxFunctions); // limited for testing. |
| 186 return index; |
| 187 } |
| 188 |
| 189 void SetFunctionCode(uint32_t index, Handle<Code> code) { |
| 190 instance->function_code->at(index) = code; |
179 } | 191 } |
180 | 192 |
181 void AddIndirectFunctionTable(int* functions, int table_size) { | 193 void AddIndirectFunctionTable(int* functions, int table_size) { |
182 AllocModule(); | |
183 Isolate* isolate = module->shared_isolate; | 194 Isolate* isolate = module->shared_isolate; |
184 Handle<FixedArray> fixed = | 195 Handle<FixedArray> fixed = |
185 isolate->factory()->NewFixedArray(2 * table_size); | 196 isolate->factory()->NewFixedArray(2 * table_size); |
186 instance->function_table = fixed; | 197 instance->function_table = fixed; |
187 module->function_table = new std::vector<uint16_t>(); | 198 module->function_table = new std::vector<uint16_t>(); |
188 for (int i = 0; i < table_size; i++) { | 199 for (int i = 0; i < table_size; i++) { |
189 module->function_table->push_back(functions[i]); | 200 module->function_table->push_back(functions[i]); |
190 } | 201 } |
191 } | 202 } |
192 | 203 |
193 void PopulateIndirectFunctionTable() { | 204 void PopulateIndirectFunctionTable() { |
194 if (instance->function_table.is_null()) return; | 205 if (instance->function_table.is_null()) return; |
195 int table_size = static_cast<int>(module->function_table->size()); | 206 int table_size = static_cast<int>(module->function_table->size()); |
196 for (int i = 0; i < table_size; i++) { | 207 for (int i = 0; i < table_size; i++) { |
197 int function_index = module->function_table->at(i); | 208 int function_index = module->function_table->at(i); |
198 WasmFunction* function = &module->functions->at(function_index); | 209 WasmFunction* function = &module->functions->at(function_index); |
199 instance->function_table->set(i, Smi::FromInt(function->sig_index)); | 210 instance->function_table->set(i, Smi::FromInt(function->sig_index)); |
200 instance->function_table->set( | 211 instance->function_table->set( |
201 i + table_size, *instance->function_code->at(function_index)); | 212 i + table_size, *instance->function_code->at(function_index)); |
202 } | 213 } |
203 } | 214 } |
204 | 215 |
205 | |
206 private: | 216 private: |
| 217 WasmModule module_; |
207 WasmModuleInstance instance_; | 218 WasmModuleInstance instance_; |
208 uint32_t global_offset; | 219 uint32_t global_offset; |
209 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. | 220 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. |
210 | 221 |
211 WasmGlobal* AddGlobal(MachineType mem_type) { | 222 WasmGlobal* AddGlobal(MachineType mem_type) { |
212 AllocModule(); | |
213 if (!module->globals) { | 223 if (!module->globals) { |
214 module->globals = new std::vector<WasmGlobal>(); | 224 module->globals = new std::vector<WasmGlobal>(); |
215 } | 225 } |
216 byte size = WasmOpcodes::MemSize(mem_type); | 226 byte size = WasmOpcodes::MemSize(mem_type); |
217 global_offset = (global_offset + size - 1) & ~(size - 1); // align | 227 global_offset = (global_offset + size - 1) & ~(size - 1); // align |
218 module->globals->push_back({0, mem_type, global_offset, false}); | 228 module->globals->push_back({0, mem_type, global_offset, false}); |
219 global_offset += size; | 229 global_offset += size; |
220 // limit number of globals. | 230 // limit number of globals. |
221 CHECK_LT(global_offset, kMaxGlobalsSize); | 231 CHECK_LT(global_offset, kMaxGlobalsSize); |
222 return &module->globals->back(); | 232 return &module->globals->back(); |
223 } | 233 } |
224 void AllocModule() { | |
225 if (module == nullptr) { | |
226 module = new WasmModule(); | |
227 module->shared_isolate = CcTest::InitIsolateOnce(); | |
228 module->globals = nullptr; | |
229 module->functions = nullptr; | |
230 module->data_segments = nullptr; | |
231 } | |
232 } | |
233 }; | 234 }; |
234 | 235 |
235 | 236 |
236 inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, FunctionEnv* env, | 237 inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, FunctionEnv* env, |
237 const byte* start, const byte* end) { | 238 const byte* start, const byte* end) { |
238 compiler::WasmGraphBuilder builder(zone, jsgraph, env->sig); | 239 compiler::WasmGraphBuilder builder(zone, jsgraph, env->sig); |
239 TreeResult result = BuildTFGraph(&builder, env, start, end); | 240 TreeResult result = BuildTFGraph(&builder, env, start, end); |
240 if (result.failed()) { | 241 if (result.failed()) { |
241 ptrdiff_t pc = result.error_pc - result.start; | 242 ptrdiff_t pc = result.error_pc - result.start; |
242 ptrdiff_t pt = result.error_pt - result.start; | 243 ptrdiff_t pt = result.error_pt - result.start; |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 } | 387 } |
387 | 388 |
388 Signature<MachineType>* signature() const { return signature_; } | 389 Signature<MachineType>* signature() const { return signature_; } |
389 | 390 |
390 private: | 391 private: |
391 Node* inner_code_node_; | 392 Node* inner_code_node_; |
392 Handle<Code> code_; | 393 Handle<Code> code_; |
393 Signature<MachineType>* signature_; | 394 Signature<MachineType>* signature_; |
394 }; | 395 }; |
395 | 396 |
396 // A helper for compiling functions that are only internally callable WASM code. | 397 // A helper for compiling WASM functions for testing. This class can create a |
| 398 // standalone function if {module} is NULL or a function within a |
| 399 // {TestingModule}. It contains the internal state for compilation (i.e. |
| 400 // TurboFan graph) and, later, interpretation. |
397 class WasmFunctionCompiler : public HandleAndZoneScope, | 401 class WasmFunctionCompiler : public HandleAndZoneScope, |
398 private GraphAndBuilders { | 402 private GraphAndBuilders { |
399 public: | 403 public: |
400 explicit WasmFunctionCompiler(FunctionSig* sig, ModuleEnv* module = nullptr) | 404 explicit WasmFunctionCompiler(FunctionSig* sig, TestingModule* module) |
401 : GraphAndBuilders(main_zone()), | 405 : GraphAndBuilders(main_zone()), |
402 jsgraph(this->isolate(), this->graph(), this->common(), nullptr, | 406 jsgraph(this->isolate(), this->graph(), this->common(), nullptr, |
403 nullptr, this->machine()), | 407 nullptr, this->machine()), |
404 descriptor_(nullptr) { | 408 descriptor_(nullptr), |
| 409 testing_module_(module) { |
405 init_env(&env, sig); | 410 init_env(&env, sig); |
406 env.module = module; | 411 env.module = module; |
| 412 if (module) { |
| 413 // Get a new function from the testing module. |
| 414 function_ = nullptr; |
| 415 function_index_ = module->AddFunction(sig, Handle<Code>::null()); |
| 416 } else { |
| 417 // Create our own function. |
| 418 function_ = new WasmFunction(); |
| 419 function_->sig = sig; |
| 420 function_index_ = 0; |
| 421 } |
| 422 } |
| 423 |
| 424 ~WasmFunctionCompiler() { |
| 425 if (function_) delete function_; |
407 } | 426 } |
408 | 427 |
409 JSGraph jsgraph; | 428 JSGraph jsgraph; |
410 FunctionEnv env; | 429 FunctionEnv env; |
411 // The call descriptor is initialized when the function is compiled. | 430 // The call descriptor is initialized when the function is compiled. |
412 CallDescriptor* descriptor_; | 431 CallDescriptor* descriptor_; |
| 432 TestingModule* testing_module_; |
| 433 WasmFunction* function_; |
| 434 int function_index_; |
413 | 435 |
414 Isolate* isolate() { return main_isolate(); } | 436 Isolate* isolate() { return main_isolate(); } |
415 Graph* graph() const { return main_graph_; } | 437 Graph* graph() const { return main_graph_; } |
416 Zone* zone() const { return graph()->zone(); } | 438 Zone* zone() const { return graph()->zone(); } |
417 CommonOperatorBuilder* common() { return &main_common_; } | 439 CommonOperatorBuilder* common() { return &main_common_; } |
418 MachineOperatorBuilder* machine() { return &main_machine_; } | 440 MachineOperatorBuilder* machine() { return &main_machine_; } |
419 void InitializeDescriptor() { | 441 void InitializeDescriptor() { |
420 if (descriptor_ == nullptr) { | 442 if (descriptor_ == nullptr) { |
421 descriptor_ = env.module->GetWasmCallDescriptor(main_zone(), env.sig); | 443 descriptor_ = env.module->GetWasmCallDescriptor(main_zone(), env.sig); |
422 } | 444 } |
423 } | 445 } |
424 CallDescriptor* descriptor() { return descriptor_; } | 446 CallDescriptor* descriptor() { return descriptor_; } |
425 | 447 |
426 void Build(const byte* start, const byte* end) { | 448 void Build(const byte* start, const byte* end) { |
| 449 // Transfer local counts before compiling. |
| 450 function()->local_i32_count = env.local_i32_count; |
| 451 function()->local_i64_count = env.local_i64_count; |
| 452 function()->local_f32_count = env.local_f32_count; |
| 453 function()->local_f64_count = env.local_f64_count; |
| 454 |
| 455 // Build the TurboFan graph. |
427 TestBuildingGraph(main_zone(), &jsgraph, &env, start, end); | 456 TestBuildingGraph(main_zone(), &jsgraph, &env, start, end); |
428 } | 457 } |
429 | 458 |
430 byte AllocateLocal(LocalType type) { | 459 byte AllocateLocal(LocalType type) { |
431 int result = static_cast<int>(env.total_locals); | 460 int result = static_cast<int>(env.total_locals); |
432 env.AddLocals(type, 1); | 461 env.AddLocals(type, 1); |
433 byte b = static_cast<byte>(result); | 462 byte b = static_cast<byte>(result); |
434 CHECK_EQ(result, b); | 463 CHECK_EQ(result, b); |
435 return b; | 464 return b; |
436 } | 465 } |
437 | 466 |
438 Handle<Code> Compile(ModuleEnv* module) { | 467 // TODO(titzer): remove me. |
| 468 Handle<Code> Compile() { |
439 InitializeDescriptor(); | 469 InitializeDescriptor(); |
440 CallDescriptor* desc = descriptor_; | 470 CallDescriptor* desc = descriptor_; |
441 if (kPointerSize == 4) { | 471 if (kPointerSize == 4) { |
442 desc = module->GetI32WasmCallDescriptor(this->zone(), desc); | 472 desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc); |
443 } | 473 } |
444 CompilationInfo info("wasm compile", this->isolate(), this->zone()); | 474 CompilationInfo info("wasm compile", this->isolate(), this->zone()); |
445 Handle<Code> result = | 475 Handle<Code> result = |
446 Pipeline::GenerateCodeForTesting(&info, desc, this->graph()); | 476 Pipeline::GenerateCodeForTesting(&info, desc, this->graph()); |
447 #ifdef ENABLE_DISASSEMBLER | 477 #ifdef ENABLE_DISASSEMBLER |
448 if (!result.is_null() && FLAG_print_opt_code) { | 478 if (!result.is_null() && FLAG_print_opt_code) { |
449 OFStream os(stdout); | 479 OFStream os(stdout); |
450 result->Disassemble("wasm code", os); | 480 result->Disassemble("wasm code", os); |
451 } | 481 } |
452 #endif | 482 #endif |
453 | 483 |
454 return result; | 484 return result; |
455 } | 485 } |
456 | 486 |
457 uint32_t CompileAndAdd(TestingModule* module, int sig_index = 0) { | 487 // TODO(titzer): remove me. |
458 uint32_t index = 0; | 488 uint32_t CompileAndAdd(uint16_t sig_index = 0) { |
459 if (module->module && module->module->functions) { | 489 CHECK(testing_module_); |
460 index = static_cast<uint32_t>(module->module->functions->size()); | 490 function()->sig_index = sig_index; |
461 } | 491 Handle<Code> code = Compile(); |
462 WasmFunction* function = module->AddFunction(env.sig, Compile(module)); | 492 testing_module_->SetFunctionCode(function_index_, code); |
463 function->sig_index = sig_index; | 493 return static_cast<uint32_t>(function_index_); |
464 return index; | 494 } |
| 495 |
| 496 WasmFunction* function() { |
| 497 if (function_) return function_; |
| 498 return &testing_module_->module->functions->at(function_index_); |
465 } | 499 } |
466 }; | 500 }; |
467 | 501 |
468 | |
469 // A helper class to build graphs from Wasm bytecode, generate machine | 502 // A helper class to build graphs from Wasm bytecode, generate machine |
470 // code, and run that code. | 503 // code, and run that code. |
471 template <typename ReturnType> | 504 template <typename ReturnType> |
472 class WasmRunner { | 505 class WasmRunner { |
473 public: | 506 public: |
474 WasmRunner(MachineType p0 = MachineType::None(), | 507 WasmRunner(MachineType p0 = MachineType::None(), |
475 MachineType p1 = MachineType::None(), | 508 MachineType p1 = MachineType::None(), |
476 MachineType p2 = MachineType::None(), | 509 MachineType p2 = MachineType::None(), |
477 MachineType p3 = MachineType::None()) | 510 MachineType p3 = MachineType::None()) |
478 : signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, | 511 : compiled_(false), |
| 512 |
| 513 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, |
479 GetParameterCount(p0, p1, p2, p3), storage_), | 514 GetParameterCount(p0, p1, p2, p3), storage_), |
480 compiler_(&signature_), | 515 compiler_(&signature_, nullptr) { |
481 compilation_done_(false) { | 516 InitSigStorage(p0, p1, p2, p3); |
| 517 } |
| 518 |
| 519 WasmRunner(TestingModule* module, MachineType p0 = MachineType::None(), |
| 520 MachineType p1 = MachineType::None(), |
| 521 MachineType p2 = MachineType::None(), |
| 522 MachineType p3 = MachineType::None()) |
| 523 : compiled_(false), |
| 524 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, |
| 525 GetParameterCount(p0, p1, p2, p3), storage_), |
| 526 compiler_(&signature_, module) { |
| 527 DCHECK(module); |
| 528 InitSigStorage(p0, p1, p2, p3); |
| 529 } |
| 530 |
| 531 void InitSigStorage(MachineType p0, MachineType p1, MachineType p2, |
| 532 MachineType p3) { |
482 int index = 0; | 533 int index = 0; |
483 MachineType ret = MachineTypeForC<ReturnType>(); | 534 MachineType ret = MachineTypeForC<ReturnType>(); |
484 if (ret != MachineType::None()) { | 535 if (ret != MachineType::None()) { |
485 storage_[index++] = WasmOpcodes::LocalTypeFor(ret); | 536 storage_[index++] = WasmOpcodes::LocalTypeFor(ret); |
486 } | 537 } |
487 if (p0 != MachineType::None()) | 538 if (p0 != MachineType::None()) |
488 storage_[index++] = WasmOpcodes::LocalTypeFor(p0); | 539 storage_[index++] = WasmOpcodes::LocalTypeFor(p0); |
489 if (p1 != MachineType::None()) | 540 if (p1 != MachineType::None()) |
490 storage_[index++] = WasmOpcodes::LocalTypeFor(p1); | 541 storage_[index++] = WasmOpcodes::LocalTypeFor(p1); |
491 if (p2 != MachineType::None()) | 542 if (p2 != MachineType::None()) |
492 storage_[index++] = WasmOpcodes::LocalTypeFor(p2); | 543 storage_[index++] = WasmOpcodes::LocalTypeFor(p2); |
493 if (p3 != MachineType::None()) | 544 if (p3 != MachineType::None()) |
494 storage_[index++] = WasmOpcodes::LocalTypeFor(p3); | 545 storage_[index++] = WasmOpcodes::LocalTypeFor(p3); |
495 | 546 |
496 compiler_.InitializeDescriptor(); | 547 compiler_.InitializeDescriptor(); |
497 wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3); | 548 wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3); |
498 } | 549 } |
499 | 550 |
500 | |
501 FunctionEnv* env() { return &compiler_.env; } | 551 FunctionEnv* env() { return &compiler_.env; } |
502 | 552 |
503 | 553 // Builds a graph from the given Wasm code and generates the machine |
504 // Builds a graph from the given Wasm code, and generates the machine | |
505 // code and call wrapper for that graph. This method must not be called | 554 // code and call wrapper for that graph. This method must not be called |
506 // more than once. | 555 // more than once. |
507 void Build(const byte* start, const byte* end) { | 556 void Build(const byte* start, const byte* end) { |
508 DCHECK(!compilation_done_); | 557 CHECK(!compiled_); |
509 compilation_done_ = true; | 558 compiled_ = true; |
510 // Build the TF graph. | 559 |
| 560 // Build the TF graph within the compiler. |
511 compiler_.Build(start, end); | 561 compiler_.Build(start, end); |
512 // Generate code. | 562 // Generate code. |
513 Handle<Code> code = compiler_.Compile(env()->module); | 563 Handle<Code> code = compiler_.Compile(); |
| 564 |
| 565 if (compiler_.testing_module_) { |
| 566 // Update the table of function code in the module. |
| 567 compiler_.testing_module_->SetFunctionCode(compiler_.function_index_, |
| 568 code); |
| 569 } |
514 | 570 |
515 wrapper_.SetInnerCode(code); | 571 wrapper_.SetInnerCode(code); |
516 } | 572 } |
517 | 573 |
518 ReturnType Call() { return Call(nullptr, nullptr, nullptr, nullptr); } | 574 ReturnType Call() { return Call(0, 0, 0, 0); } |
519 | 575 |
520 template <typename P0> | 576 template <typename P0> |
521 ReturnType Call(P0 p0) { | 577 ReturnType Call(P0 p0) { |
522 return Call(p0, nullptr, nullptr, nullptr); | 578 return Call(p0, 0, 0, 0); |
523 } | 579 } |
524 | 580 |
525 template <typename P0, typename P1> | 581 template <typename P0, typename P1> |
526 ReturnType Call(P0 p0, P1 p1) { | 582 ReturnType Call(P0 p0, P1 p1) { |
527 return Call(p0, p1, nullptr, nullptr); | 583 return Call(p0, p1, 0, 0); |
528 } | 584 } |
529 | 585 |
530 template <typename P0, typename P1, typename P2> | 586 template <typename P0, typename P1, typename P2> |
531 ReturnType Call(P0 p0, P1 p1, P2 p2) { | 587 ReturnType Call(P0 p0, P1 p1, P2 p2) { |
532 return Call(p0, p1, p2, nullptr); | 588 return Call(p0, p1, p2, 0); |
533 } | 589 } |
534 | 590 |
535 template <typename P0, typename P1, typename P2, typename P3> | 591 template <typename P0, typename P1, typename P2, typename P3> |
536 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) { | 592 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) { |
537 CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(), | 593 CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(), |
538 wrapper_.GetWrapperCode(), wrapper_.signature()); | 594 wrapper_.GetWrapperCode(), wrapper_.signature()); |
539 ReturnType return_value; | 595 ReturnType return_value; |
540 int32_t result = runner.Call<void*, void*, void*, void*, void*>( | 596 int32_t result = runner.Call<void*, void*, void*, void*, void*>( |
541 &p0, &p1, &p2, &p3, &return_value); | 597 &p0, &p1, &p2, &p3, &return_value); |
542 CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result); | 598 CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result); |
543 return return_value; | 599 return return_value; |
544 } | 600 } |
545 | 601 |
546 byte AllocateLocal(LocalType type) { | 602 byte AllocateLocal(LocalType type) { |
547 int result = static_cast<int>(env()->total_locals); | 603 int result = static_cast<int>(env()->total_locals); |
548 env()->AddLocals(type, 1); | 604 env()->AddLocals(type, 1); |
549 byte b = static_cast<byte>(result); | 605 byte b = static_cast<byte>(result); |
550 CHECK_EQ(result, b); | 606 CHECK_EQ(result, b); |
551 return b; | 607 return b; |
552 } | 608 } |
553 | 609 |
554 private: | 610 protected: |
| 611 Zone zone; |
| 612 bool compiled_; |
555 LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS]; | 613 LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS]; |
556 FunctionSig signature_; | 614 FunctionSig signature_; |
557 WasmFunctionCompiler compiler_; | 615 WasmFunctionCompiler compiler_; |
558 WasmFunctionWrapper<ReturnType> wrapper_; | 616 WasmFunctionWrapper<ReturnType> wrapper_; |
559 bool compilation_done_; | |
560 | 617 |
561 static size_t GetParameterCount(MachineType p0, MachineType p1, | 618 static size_t GetParameterCount(MachineType p0, MachineType p1, |
562 MachineType p2, MachineType p3) { | 619 MachineType p2, MachineType p3) { |
563 if (p0 == MachineType::None()) return 0; | 620 if (p0 == MachineType::None()) return 0; |
564 if (p1 == MachineType::None()) return 1; | 621 if (p1 == MachineType::None()) return 1; |
565 if (p2 == MachineType::None()) return 2; | 622 if (p2 == MachineType::None()) return 2; |
566 if (p3 == MachineType::None()) return 3; | 623 if (p3 == MachineType::None()) return 3; |
567 return 4; | 624 return 4; |
568 } | 625 } |
569 }; | 626 }; |
570 | 627 |
571 } // namespace | 628 } // namespace |
572 | 629 |
573 #endif | 630 #endif |
OLD | NEW |