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