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 <setjmp.h> | 8 #include <setjmp.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 #include <stdlib.h> | 10 #include <stdlib.h> |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 ModuleBytesEnv(&module_, &instance_, | 84 ModuleBytesEnv(&module_, &instance_, |
85 Vector<const byte>::empty()), | 85 Vector<const byte>::empty()), |
86 zone->allocator()) | 86 zone->allocator()) |
87 : nullptr) { | 87 : nullptr) { |
88 instance->module = &module_; | 88 instance->module = &module_; |
89 instance->globals_start = global_data; | 89 instance->globals_start = global_data; |
90 module_.globals_size = kMaxGlobalsSize; | 90 module_.globals_size = kMaxGlobalsSize; |
91 instance->mem_start = nullptr; | 91 instance->mem_start = nullptr; |
92 instance->mem_size = 0; | 92 instance->mem_size = 0; |
93 memset(global_data, 0, sizeof(global_data)); | 93 memset(global_data, 0, sizeof(global_data)); |
| 94 instance_object_ = InitInstanceObject(); |
94 } | 95 } |
95 | 96 |
96 ~TestingModule() { | 97 ~TestingModule() { |
97 if (instance->mem_start) { | 98 if (instance->mem_start) { |
98 free(instance->mem_start); | 99 free(instance->mem_start); |
99 } | 100 } |
100 if (interpreter_) delete interpreter_; | 101 if (interpreter_) delete interpreter_; |
101 } | 102 } |
102 | 103 |
103 void ChangeOriginToAsmjs() { module_.origin = kAsmJsOrigin; } | 104 void ChangeOriginToAsmjs() { module_.origin = kAsmJsOrigin; } |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 | 174 |
174 // Pseudo-randomly intialize the memory. | 175 // Pseudo-randomly intialize the memory. |
175 void RandomizeMemory(unsigned int seed = 88) { | 176 void RandomizeMemory(unsigned int seed = 88) { |
176 byte* raw = raw_mem_start<byte>(); | 177 byte* raw = raw_mem_start<byte>(); |
177 byte* end = raw_mem_end<byte>(); | 178 byte* end = raw_mem_end<byte>(); |
178 v8::base::RandomNumberGenerator rng; | 179 v8::base::RandomNumberGenerator rng; |
179 rng.SetSeed(seed); | 180 rng.SetSeed(seed); |
180 rng.NextBytes(raw, end - raw); | 181 rng.NextBytes(raw, end - raw); |
181 } | 182 } |
182 | 183 |
183 uint32_t AddFunction(FunctionSig* sig, Handle<Code> code) { | 184 uint32_t AddFunction(FunctionSig* sig, Handle<Code> code, const char* name) { |
184 if (module->functions.size() == 0) { | 185 if (module->functions.size() == 0) { |
185 // TODO(titzer): Reserving space here to avoid the underlying WasmFunction | 186 // TODO(titzer): Reserving space here to avoid the underlying WasmFunction |
186 // structs from moving. | 187 // structs from moving. |
187 module_.functions.reserve(kMaxFunctions); | 188 module_.functions.reserve(kMaxFunctions); |
188 } | 189 } |
189 uint32_t index = static_cast<uint32_t>(module->functions.size()); | 190 uint32_t index = static_cast<uint32_t>(module->functions.size()); |
190 module_.functions.push_back({sig, index, 0, 0, 0, 0, 0, false, false}); | 191 module_.functions.push_back({sig, index, 0, 0, 0, 0, 0, false, false}); |
| 192 if (name) { |
| 193 Vector<const byte> name_vec = Vector<const byte>::cast(CStrVector(name)); |
| 194 module_.functions.back().name_offset = AddBytes(name_vec); |
| 195 module_.functions.back().name_length = name_vec.length(); |
| 196 } |
191 instance->function_code.push_back(code); | 197 instance->function_code.push_back(code); |
192 if (interpreter_) { | 198 if (interpreter_) { |
193 const WasmFunction* function = &module->functions.back(); | 199 const WasmFunction* function = &module->functions.back(); |
194 int interpreter_index = interpreter_->AddFunctionForTesting(function); | 200 int interpreter_index = interpreter_->AddFunctionForTesting(function); |
195 CHECK_EQ(index, static_cast<uint32_t>(interpreter_index)); | 201 CHECK_EQ(index, static_cast<uint32_t>(interpreter_index)); |
196 } | 202 } |
197 DCHECK_LT(index, kMaxFunctions); // limited for testing. | 203 DCHECK_LT(index, kMaxFunctions); // limited for testing. |
198 return index; | 204 return index; |
199 } | 205 } |
200 | 206 |
201 uint32_t AddJsFunction(FunctionSig* sig, const char* source) { | 207 uint32_t AddJsFunction(FunctionSig* sig, const char* source) { |
202 Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle( | 208 Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle( |
203 *v8::Local<v8::Function>::Cast(CompileRun(source)))); | 209 *v8::Local<v8::Function>::Cast(CompileRun(source)))); |
204 uint32_t index = AddFunction(sig, Handle<Code>::null()); | 210 uint32_t index = AddFunction(sig, Handle<Code>::null(), nullptr); |
205 Handle<Code> code = CompileWasmToJSWrapper( | 211 Handle<Code> code = CompileWasmToJSWrapper( |
206 isolate_, jsfunc, sig, index, Handle<String>::null(), | 212 isolate_, jsfunc, sig, index, Handle<String>::null(), |
207 Handle<String>::null(), module->origin); | 213 Handle<String>::null(), module->origin); |
208 instance->function_code[index] = code; | 214 instance->function_code[index] = code; |
209 return index; | 215 return index; |
210 } | 216 } |
211 | 217 |
212 Handle<JSFunction> WrapCode(uint32_t index) { | 218 Handle<JSFunction> WrapCode(uint32_t index) { |
213 // Wrap the code so it can be called as a JS function. | 219 // Wrap the code so it can be called as a JS function. |
214 Handle<WasmInstanceObject> instance_obj(0, isolate_); | 220 Handle<WasmInstanceObject> instance_obj(0, isolate_); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 *instance->function_code[function.func_index]); | 264 *instance->function_code[function.func_index]); |
259 } | 265 } |
260 } | 266 } |
261 } | 267 } |
262 | 268 |
263 WasmFunction* GetFunctionAt(int index) { return &module_.functions[index]; } | 269 WasmFunction* GetFunctionAt(int index) { return &module_.functions[index]; } |
264 | 270 |
265 WasmInterpreter* interpreter() { return interpreter_; } | 271 WasmInterpreter* interpreter() { return interpreter_; } |
266 WasmExecutionMode execution_mode() { return execution_mode_; } | 272 WasmExecutionMode execution_mode() { return execution_mode_; } |
267 Isolate* isolate() { return isolate_; } | 273 Isolate* isolate() { return isolate_; } |
| 274 Handle<WasmInstanceObject> instance_object() { return instance_object_; } |
268 | 275 |
269 private: | 276 private: |
270 WasmExecutionMode execution_mode_; | 277 WasmExecutionMode execution_mode_; |
271 WasmModule module_; | 278 WasmModule module_; |
272 WasmInstance instance_; | 279 WasmInstance instance_; |
273 Isolate* isolate_; | 280 Isolate* isolate_; |
274 uint32_t global_offset; | 281 uint32_t global_offset; |
275 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. | 282 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. |
276 WasmInterpreter* interpreter_; | 283 WasmInterpreter* interpreter_; |
| 284 Handle<WasmInstanceObject> instance_object_; |
277 | 285 |
278 const WasmGlobal* AddGlobal(LocalType type) { | 286 const WasmGlobal* AddGlobal(LocalType type) { |
279 byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type)); | 287 byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type)); |
280 global_offset = (global_offset + size - 1) & ~(size - 1); // align | 288 global_offset = (global_offset + size - 1) & ~(size - 1); // align |
281 module_.globals.push_back( | 289 module_.globals.push_back( |
282 {type, true, WasmInitExpr(), global_offset, false, false}); | 290 {type, true, WasmInitExpr(), global_offset, false, false}); |
283 global_offset += size; | 291 global_offset += size; |
284 // limit number of globals. | 292 // limit number of globals. |
285 CHECK_LT(global_offset, kMaxGlobalsSize); | 293 CHECK_LT(global_offset, kMaxGlobalsSize); |
286 return &module->globals.back(); | 294 return &module->globals.back(); |
287 } | 295 } |
| 296 |
| 297 uint32_t AddBytes(Vector<const byte> bytes) { |
| 298 Handle<SeqOneByteString> old_bytes = |
| 299 instance_object_->get_compiled_module()->module_bytes(); |
| 300 uint32_t old_size = static_cast<uint32_t>(old_bytes->length()); |
| 301 ScopedVector<byte> new_bytes(old_size + bytes.length()); |
| 302 memcpy(new_bytes.start(), old_bytes->GetChars(), old_size); |
| 303 memcpy(new_bytes.start() + old_size, bytes.start(), bytes.length()); |
| 304 Handle<SeqOneByteString> new_bytes_str = Handle<SeqOneByteString>::cast( |
| 305 isolate_->factory()->NewStringFromOneByte(new_bytes).ToHandleChecked()); |
| 306 instance_object_->get_compiled_module()->set_module_bytes(new_bytes_str); |
| 307 return old_size; |
| 308 } |
| 309 |
| 310 Handle<WasmInstanceObject> InitInstanceObject() { |
| 311 Handle<Managed<wasm::WasmModule>> module_wrapper = |
| 312 Managed<wasm::WasmModule>::New(isolate_, &module_, false); |
| 313 Handle<WasmCompiledModule> compiled_module = |
| 314 WasmCompiledModule::New(isolate_, module_wrapper); |
| 315 // Minimally initialize the compiled module such that IsWasmCompiledModule |
| 316 // passes. |
| 317 // If tests need more (correct) information, add it later. |
| 318 compiled_module->set_min_mem_pages(0); |
| 319 compiled_module->set_max_mem_pages(Smi::kMaxValue); |
| 320 Handle<SeqOneByteString> empty_string = Handle<SeqOneByteString>::cast( |
| 321 isolate_->factory()->NewStringFromOneByte({}).ToHandleChecked()); |
| 322 compiled_module->set_module_bytes(empty_string); |
| 323 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); |
| 324 return WasmInstanceObject::New(isolate_, compiled_module); |
| 325 } |
288 }; | 326 }; |
289 | 327 |
290 inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module, | 328 inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module, |
291 FunctionSig* sig, | 329 FunctionSig* sig, |
292 SourcePositionTable* source_position_table, | 330 SourcePositionTable* source_position_table, |
293 const byte* start, const byte* end) { | 331 const byte* start, const byte* end) { |
294 compiler::WasmGraphBuilder builder(zone, jsgraph, sig, source_position_table); | 332 compiler::WasmGraphBuilder builder(zone, jsgraph, sig, source_position_table); |
295 DecodeResult result = | 333 DecodeResult result = |
296 BuildTFGraph(zone->allocator(), &builder, module, sig, start, end); | 334 BuildTFGraph(zone->allocator(), &builder, module, sig, start, end); |
297 if (result.failed()) { | 335 if (result.failed()) { |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 DCHECK_EQ(index, result); | 517 DCHECK_EQ(index, result); |
480 return result; | 518 return result; |
481 } | 519 } |
482 | 520 |
483 void SetSigIndex(int sig_index) { function_->sig_index = sig_index; } | 521 void SetSigIndex(int sig_index) { function_->sig_index = sig_index; } |
484 | 522 |
485 private: | 523 private: |
486 friend class WasmRunnerBase; | 524 friend class WasmRunnerBase; |
487 | 525 |
488 explicit WasmFunctionCompiler(Zone* zone, FunctionSig* sig, | 526 explicit WasmFunctionCompiler(Zone* zone, FunctionSig* sig, |
489 TestingModule* module) | 527 TestingModule* module, const char* name) |
490 : GraphAndBuilders(zone), | 528 : GraphAndBuilders(zone), |
491 jsgraph(module->isolate(), this->graph(), this->common(), nullptr, | 529 jsgraph(module->isolate(), this->graph(), this->common(), nullptr, |
492 nullptr, this->machine()), | 530 nullptr, this->machine()), |
493 sig(sig), | 531 sig(sig), |
494 descriptor_(nullptr), | 532 descriptor_(nullptr), |
495 testing_module_(module), | 533 testing_module_(module), |
496 local_decls(zone, sig), | 534 local_decls(zone, sig), |
497 source_position_table_(this->graph()), | 535 source_position_table_(this->graph()), |
498 interpreter_(module->interpreter()) { | 536 interpreter_(module->interpreter()) { |
499 // Get a new function from the testing module. | 537 // Get a new function from the testing module. |
500 int index = module->AddFunction(sig, Handle<Code>::null()); | 538 int index = module->AddFunction(sig, Handle<Code>::null(), name); |
501 function_ = testing_module_->GetFunctionAt(index); | 539 function_ = testing_module_->GetFunctionAt(index); |
502 } | 540 } |
503 | 541 |
504 Handle<Code> Compile() { | 542 Handle<Code> Compile() { |
505 CallDescriptor* desc = descriptor(); | 543 CallDescriptor* desc = descriptor(); |
506 if (kPointerSize == 4) { | 544 if (kPointerSize == 4) { |
507 desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc); | 545 desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc); |
508 } | 546 } |
509 CompilationInfo info(CStrVector("wasm"), this->isolate(), this->zone(), | 547 CompilationInfo info(CStrVector("wasm"), this->isolate(), this->zone(), |
510 Code::ComputeFlags(Code::WASM_FUNCTION)); | 548 Code::ComputeFlags(Code::WASM_FUNCTION)); |
511 std::unique_ptr<CompilationJob> job(Pipeline::NewWasmCompilationJob( | 549 std::unique_ptr<CompilationJob> job(Pipeline::NewWasmCompilationJob( |
512 &info, &jsgraph, desc, &source_position_table_, nullptr)); | 550 &info, &jsgraph, desc, &source_position_table_, nullptr)); |
513 if (job->ExecuteJob() != CompilationJob::SUCCEEDED || | 551 if (job->ExecuteJob() != CompilationJob::SUCCEEDED || |
514 job->FinalizeJob() != CompilationJob::SUCCEEDED) | 552 job->FinalizeJob() != CompilationJob::SUCCEEDED) |
515 return Handle<Code>::null(); | 553 return Handle<Code>::null(); |
516 | 554 |
517 Handle<Code> code = info.code(); | 555 Handle<Code> code = info.code(); |
518 | 556 |
519 // Length is always 2, since usually <wasm_obj, func_index> is stored in | 557 // Deopt data holds <WeakCell<wasm_instance>, func_index>. |
520 // the deopt data. Here, we only store the function index. | |
521 DCHECK(code->deoptimization_data() == nullptr || | 558 DCHECK(code->deoptimization_data() == nullptr || |
522 code->deoptimization_data()->length() == 0); | 559 code->deoptimization_data()->length() == 0); |
523 Handle<FixedArray> deopt_data = | 560 Handle<FixedArray> deopt_data = |
524 isolate()->factory()->NewFixedArray(2, TENURED); | 561 isolate()->factory()->NewFixedArray(2, TENURED); |
| 562 Handle<Object> weak_instance = |
| 563 isolate()->factory()->NewWeakCell(testing_module_->instance_object()); |
| 564 deopt_data->set(0, *weak_instance); |
525 deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index()))); | 565 deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index()))); |
526 deopt_data->set_length(2); | 566 deopt_data->set_length(2); |
527 code->set_deoptimization_data(*deopt_data); | 567 code->set_deoptimization_data(*deopt_data); |
528 | 568 |
529 #ifdef ENABLE_DISASSEMBLER | 569 #ifdef ENABLE_DISASSEMBLER |
530 if (FLAG_print_opt_code) { | 570 if (FLAG_print_opt_code) { |
531 OFStream os(stdout); | 571 OFStream os(stdout); |
532 code->Disassemble("wasm code", os); | 572 code->Disassemble("wasm code", os); |
533 } | 573 } |
534 #endif | 574 #endif |
(...skipping 27 matching lines...) Expand all Loading... |
562 // more than once. | 602 // more than once. |
563 void Build(const byte* start, const byte* end) { | 603 void Build(const byte* start, const byte* end) { |
564 CHECK(!compiled_); | 604 CHECK(!compiled_); |
565 compiled_ = true; | 605 compiled_ = true; |
566 functions_[0]->Build(start, end); | 606 functions_[0]->Build(start, end); |
567 } | 607 } |
568 | 608 |
569 // Resets the state for building the next function. | 609 // Resets the state for building the next function. |
570 // The main function called will always be the first function. | 610 // The main function called will always be the first function. |
571 template <typename ReturnType, typename... ParamTypes> | 611 template <typename ReturnType, typename... ParamTypes> |
572 WasmFunctionCompiler& NewFunction() { | 612 WasmFunctionCompiler& NewFunction(const char* name = nullptr) { |
573 return NewFunction(CreateSig<ReturnType, ParamTypes...>()); | 613 return NewFunction(CreateSig<ReturnType, ParamTypes...>(), name); |
574 } | 614 } |
575 | 615 |
576 // Resets the state for building the next function. | 616 // Resets the state for building the next function. |
577 // The main function called will be the last generated function. | 617 // The main function called will be the last generated function. |
578 // Returns the index of the previously built function. | 618 // Returns the index of the previously built function. |
579 WasmFunctionCompiler& NewFunction(FunctionSig* sig) { | 619 WasmFunctionCompiler& NewFunction(FunctionSig* sig, |
580 functions_.emplace_back(new WasmFunctionCompiler(&zone_, sig, &module_)); | 620 const char* name = nullptr) { |
| 621 functions_.emplace_back( |
| 622 new WasmFunctionCompiler(&zone_, sig, &module_, name)); |
581 return *functions_.back(); | 623 return *functions_.back(); |
582 } | 624 } |
583 | 625 |
584 byte AllocateLocal(LocalType type) { | 626 byte AllocateLocal(LocalType type) { |
585 return functions_[0]->AllocateLocal(type); | 627 return functions_[0]->AllocateLocal(type); |
586 } | 628 } |
587 | 629 |
588 WasmFunction* function() { return functions_[0]->function_; } | 630 WasmFunction* function() { return functions_[0]->function_; } |
589 WasmInterpreter* interpreter() { return functions_[0]->interpreter_; } | 631 WasmInterpreter* interpreter() { return functions_[0]->interpreter_; } |
590 bool possible_nondeterminism() { return possible_nondeterminism_; } | 632 bool possible_nondeterminism() { return possible_nondeterminism_; } |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
644 | 686 |
645 public: | 687 public: |
646 // This field has to be static. Otherwise, gcc complains about the using in | 688 // This field has to be static. Otherwise, gcc complains about the using in |
647 // the lambda context below. | 689 // the lambda context below. |
648 static jmp_buf jump_buffer; | 690 static jmp_buf jump_buffer; |
649 }; | 691 }; |
650 | 692 |
651 template <typename ReturnType, typename... ParamTypes> | 693 template <typename ReturnType, typename... ParamTypes> |
652 class WasmRunner : public WasmRunnerBase { | 694 class WasmRunner : public WasmRunnerBase { |
653 public: | 695 public: |
654 explicit WasmRunner(WasmExecutionMode execution_mode) | 696 explicit WasmRunner(WasmExecutionMode execution_mode, |
| 697 const char* main_fn_name = "main") |
655 : WasmRunnerBase(execution_mode, sizeof...(ParamTypes)) { | 698 : WasmRunnerBase(execution_mode, sizeof...(ParamTypes)) { |
656 NewFunction<ReturnType, ParamTypes...>(); | 699 NewFunction<ReturnType, ParamTypes...>(main_fn_name); |
657 if (!interpret()) { | 700 if (!interpret()) { |
658 wrapper_.Init<ReturnType, ParamTypes...>(functions_[0]->descriptor()); | 701 wrapper_.Init<ReturnType, ParamTypes...>(functions_[0]->descriptor()); |
659 } | 702 } |
660 } | 703 } |
661 | 704 |
662 ReturnType Call(ParamTypes... p) { | 705 ReturnType Call(ParamTypes... p) { |
663 DCHECK(compiled_); | 706 DCHECK(compiled_); |
664 if (interpret()) return CallInterpreter(p...); | 707 if (interpret()) return CallInterpreter(p...); |
665 | 708 |
666 // Use setjmp/longjmp to deal with traps in WebAssembly code. | 709 // Use setjmp/longjmp to deal with traps in WebAssembly code. |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 void RunWasm_##name(WasmExecutionMode execution_mode) | 783 void RunWasm_##name(WasmExecutionMode execution_mode) |
741 | 784 |
742 #define WASM_EXEC_COMPILED_TEST(name) \ | 785 #define WASM_EXEC_COMPILED_TEST(name) \ |
743 void RunWasm_##name(WasmExecutionMode execution_mode); \ | 786 void RunWasm_##name(WasmExecutionMode execution_mode); \ |
744 TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \ | 787 TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \ |
745 void RunWasm_##name(WasmExecutionMode execution_mode) | 788 void RunWasm_##name(WasmExecutionMode execution_mode) |
746 | 789 |
747 } // namespace | 790 } // namespace |
748 | 791 |
749 #endif | 792 #endif |
OLD | NEW |