Chromium Code Reviews| 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> |
| 11 #include <array> | |
| 11 #include <memory> | 12 #include <memory> |
| 12 | 13 |
| 13 #include "src/base/utils/random-number-generator.h" | 14 #include "src/base/utils/random-number-generator.h" |
| 14 #include "src/zone/accounting-allocator.h" | 15 #include "src/zone/accounting-allocator.h" |
| 15 | 16 |
| 16 #include "src/compiler/compiler-source-position-table.h" | 17 #include "src/compiler/compiler-source-position-table.h" |
| 17 #include "src/compiler/graph-visualizer.h" | 18 #include "src/compiler/graph-visualizer.h" |
| 18 #include "src/compiler/int64-lowering.h" | 19 #include "src/compiler/int64-lowering.h" |
| 19 #include "src/compiler/js-graph.h" | 20 #include "src/compiler/js-graph.h" |
| 20 #include "src/compiler/node.h" | 21 #include "src/compiler/node.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 64 using namespace v8::internal::compiler; | 65 using namespace v8::internal::compiler; |
| 65 using namespace v8::internal::wasm; | 66 using namespace v8::internal::wasm; |
| 66 | 67 |
| 67 const uint32_t kMaxGlobalsSize = 128; | 68 const uint32_t kMaxGlobalsSize = 128; |
| 68 | 69 |
| 69 // A helper for module environments that adds the ability to allocate memory | 70 // A helper for module environments that adds the ability to allocate memory |
| 70 // and global variables. Contains a built-in {WasmModule} and | 71 // and global variables. Contains a built-in {WasmModule} and |
| 71 // {WasmInstance}. | 72 // {WasmInstance}. |
| 72 class TestingModule : public ModuleEnv { | 73 class TestingModule : public ModuleEnv { |
| 73 public: | 74 public: |
| 74 explicit TestingModule(WasmExecutionMode mode = kExecuteCompiled) | 75 explicit TestingModule(Zone* zone, WasmExecutionMode mode = kExecuteCompiled) |
| 75 : ModuleEnv(&module_, &instance_), | 76 : ModuleEnv(&module_, &instance_), |
| 76 execution_mode_(mode), | 77 execution_mode_(mode), |
| 77 instance_(&module_), | 78 instance_(&module_), |
| 78 isolate_(CcTest::InitIsolateOnce()), | 79 isolate_(CcTest::InitIsolateOnce()), |
| 79 global_offset(0), | 80 global_offset(0), |
| 80 interpreter_(mode == kExecuteInterpreted | 81 interpreter_(mode == kExecuteInterpreted |
| 81 ? new WasmInterpreter( | 82 ? new WasmInterpreter( |
| 82 ModuleBytesEnv(&module_, &instance_, | 83 ModuleBytesEnv(&module_, &instance_, |
| 83 Vector<const byte>::empty()), | 84 Vector<const byte>::empty()), |
| 84 &allocator_) | 85 zone->allocator()) |
| 85 : nullptr) { | 86 : nullptr) { |
| 86 instance->module = &module_; | 87 instance->module = &module_; |
| 87 instance->globals_start = global_data; | 88 instance->globals_start = global_data; |
| 88 module_.globals_size = kMaxGlobalsSize; | 89 module_.globals_size = kMaxGlobalsSize; |
| 89 instance->mem_start = nullptr; | 90 instance->mem_start = nullptr; |
| 90 instance->mem_size = 0; | 91 instance->mem_size = 0; |
| 91 memset(global_data, 0, sizeof(global_data)); | 92 memset(global_data, 0, sizeof(global_data)); |
| 92 } | 93 } |
| 93 | 94 |
| 94 ~TestingModule() { | 95 ~TestingModule() { |
| 95 if (instance->mem_start) { | 96 if (instance->mem_start) { |
| 96 free(instance->mem_start); | 97 free(instance->mem_start); |
| 97 } | 98 } |
| 98 if (interpreter_) delete interpreter_; | 99 if (interpreter_) delete interpreter_; |
| 99 } | 100 } |
| 100 | 101 |
| 101 void ChangeOriginToAsmjs() { module_.origin = kAsmJsOrigin; } | 102 void ChangeOriginToAsmjs() { module_.origin = kAsmJsOrigin; } |
| 102 | 103 |
| 103 byte* AddMemory(uint32_t size) { | 104 byte* AddMemory(uint32_t size) { |
| 104 CHECK_NULL(instance->mem_start); | 105 CHECK_NULL(instance->mem_start); |
| 105 CHECK_EQ(0u, instance->mem_size); | 106 CHECK_EQ(0, instance->mem_size); |
| 106 instance->mem_start = reinterpret_cast<byte*>(malloc(size)); | 107 instance->mem_start = reinterpret_cast<byte*>(malloc(size)); |
| 107 CHECK(instance->mem_start); | 108 CHECK(instance->mem_start); |
| 108 memset(instance->mem_start, 0, size); | 109 memset(instance->mem_start, 0, size); |
| 109 instance->mem_size = size; | 110 instance->mem_size = size; |
| 110 return raw_mem_start<byte>(); | 111 return raw_mem_start<byte>(); |
| 111 } | 112 } |
| 112 | 113 |
| 113 template <typename T> | 114 template <typename T> |
| 114 T* AddMemoryElems(uint32_t count) { | 115 T* AddMemoryElems(uint32_t count) { |
| 115 AddMemory(count * sizeof(T)); | 116 AddMemory(count * sizeof(T)); |
| 116 return raw_mem_start<T>(); | 117 return raw_mem_start<T>(); |
| 117 } | 118 } |
| 118 | 119 |
| 119 template <typename T> | 120 template <typename T> |
| 120 T* AddGlobal(LocalType type) { | 121 T* AddGlobal( |
| 122 LocalType type = WasmOpcodes::LocalTypeFor(MachineTypeForC<T>())) { | |
| 121 const WasmGlobal* global = AddGlobal(type); | 123 const WasmGlobal* global = AddGlobal(type); |
| 122 return reinterpret_cast<T*>(instance->globals_start + global->offset); | 124 return reinterpret_cast<T*>(instance->globals_start + global->offset); |
| 123 } | 125 } |
| 124 | 126 |
| 125 byte AddSignature(FunctionSig* sig) { | 127 byte AddSignature(FunctionSig* sig) { |
| 126 module_.signatures.push_back(sig); | 128 module_.signatures.push_back(sig); |
| 127 size_t size = module->signatures.size(); | 129 size_t size = module->signatures.size(); |
| 128 CHECK(size < 127); | 130 CHECK(size < 127); |
| 129 return static_cast<byte>(size - 1); | 131 return static_cast<byte>(size - 1); |
| 130 } | 132 } |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 for (uint32_t i = 0; i < table_size; ++i) { | 238 for (uint32_t i = 0; i < table_size; ++i) { |
| 237 table.values.push_back(function_indexes[i]); | 239 table.values.push_back(function_indexes[i]); |
| 238 table.map.FindOrInsert(module_.functions[function_indexes[i]].sig); | 240 table.map.FindOrInsert(module_.functions[function_indexes[i]].sig); |
| 239 } | 241 } |
| 240 | 242 |
| 241 instance->function_tables.push_back( | 243 instance->function_tables.push_back( |
| 242 isolate_->factory()->NewFixedArray(table_size * 2)); | 244 isolate_->factory()->NewFixedArray(table_size * 2)); |
| 243 } | 245 } |
| 244 | 246 |
| 245 void PopulateIndirectFunctionTable() { | 247 void PopulateIndirectFunctionTable() { |
| 248 if (execution_mode_ == kExecuteInterpreted) return; | |
| 246 // Initialize the fixed arrays in instance->function_tables. | 249 // Initialize the fixed arrays in instance->function_tables. |
| 247 for (uint32_t i = 0; i < instance->function_tables.size(); i++) { | 250 for (uint32_t i = 0; i < instance->function_tables.size(); i++) { |
| 248 WasmIndirectFunctionTable& table = module_.function_tables[i]; | 251 WasmIndirectFunctionTable& table = module_.function_tables[i]; |
| 249 Handle<FixedArray> array = instance->function_tables[i]; | 252 Handle<FixedArray> array = instance->function_tables[i]; |
| 250 int table_size = static_cast<int>(table.values.size()); | 253 int table_size = static_cast<int>(table.values.size()); |
| 251 for (int j = 0; j < table_size; j++) { | 254 for (int j = 0; j < table_size; j++) { |
| 252 WasmFunction& function = module_.functions[table.values[j]]; | 255 WasmFunction& function = module_.functions[table.values[j]]; |
| 253 array->set(j, Smi::FromInt(table.map.Find(function.sig))); | 256 array->set(j, Smi::FromInt(table.map.Find(function.sig))); |
| 254 array->set(j + table_size, | 257 array->set(j + table_size, |
| 255 *instance->function_code[function.func_index]); | 258 *instance->function_code[function.func_index]); |
| 256 } | 259 } |
| 257 } | 260 } |
| 258 } | 261 } |
| 259 | 262 |
| 260 WasmFunction* GetFunctionAt(int index) { return &module_.functions[index]; } | 263 WasmFunction* GetFunctionAt(int index) { return &module_.functions[index]; } |
| 261 | 264 |
| 262 WasmInterpreter* interpreter() { return interpreter_; } | 265 WasmInterpreter* interpreter() { return interpreter_; } |
| 263 WasmExecutionMode execution_mode() { return execution_mode_; } | 266 WasmExecutionMode execution_mode() { return execution_mode_; } |
| 267 Isolate* isolate() { return isolate_; } | |
| 264 | 268 |
| 265 private: | 269 private: |
| 266 WasmExecutionMode execution_mode_; | 270 WasmExecutionMode execution_mode_; |
| 267 WasmModule module_; | 271 WasmModule module_; |
| 268 WasmInstance instance_; | 272 WasmInstance instance_; |
| 269 Isolate* isolate_; | 273 Isolate* isolate_; |
| 270 v8::internal::AccountingAllocator allocator_; | |
| 271 uint32_t global_offset; | 274 uint32_t global_offset; |
| 272 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. | 275 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. |
| 273 WasmInterpreter* interpreter_; | 276 WasmInterpreter* interpreter_; |
| 274 | 277 |
| 275 const WasmGlobal* AddGlobal(LocalType type) { | 278 const WasmGlobal* AddGlobal(LocalType type) { |
| 276 byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type)); | 279 byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type)); |
| 277 global_offset = (global_offset + size - 1) & ~(size - 1); // align | 280 global_offset = (global_offset + size - 1) & ~(size - 1); // align |
| 278 module_.globals.push_back( | 281 module_.globals.push_back( |
| 279 {type, true, WasmInitExpr(), global_offset, false, false}); | 282 {type, true, WasmInitExpr(), global_offset, false, false}); |
| 280 global_offset += size; | 283 global_offset += size; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 307 str << ", msg = " << result.error_msg.get(); | 310 str << ", msg = " << result.error_msg.get(); |
| 308 FATAL(str.str().c_str()); | 311 FATAL(str.str().c_str()); |
| 309 } | 312 } |
| 310 builder.Int64LoweringForTesting(); | 313 builder.Int64LoweringForTesting(); |
| 311 if (!CpuFeatures::SupportsSimd128()) { | 314 if (!CpuFeatures::SupportsSimd128()) { |
| 312 builder.SimdScalarLoweringForTesting(); | 315 builder.SimdScalarLoweringForTesting(); |
| 313 } | 316 } |
| 314 } | 317 } |
| 315 | 318 |
| 316 template <typename ReturnType> | 319 template <typename ReturnType> |
| 317 class WasmFunctionWrapper : public HandleAndZoneScope, | 320 class WasmFunctionWrapper : private GraphAndBuilders { |
| 318 private GraphAndBuilders { | |
| 319 public: | 321 public: |
| 320 WasmFunctionWrapper() | 322 explicit WasmFunctionWrapper(Zone* zone, int num_params) |
| 321 : GraphAndBuilders(main_zone()), | 323 : GraphAndBuilders(zone), |
| 322 inner_code_node_(nullptr), | 324 inner_code_node_(nullptr), |
| 323 signature_(nullptr) { | 325 signature_(nullptr), |
| 326 num_params_(num_params) { | |
| 324 // One additional parameter for the pointer to the return value memory. | 327 // One additional parameter for the pointer to the return value memory. |
| 325 Signature<MachineType>::Builder sig_builder( | 328 Signature<MachineType>::Builder sig_builder(zone, 1, num_params + 1); |
| 326 zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1); | |
| 327 | 329 |
| 328 sig_builder.AddReturn(MachineType::Int32()); | 330 sig_builder.AddReturn(MachineType::Int32()); |
| 329 for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) { | 331 for (int i = 0; i < num_params + 1; i++) { |
| 330 sig_builder.AddParam(MachineType::Pointer()); | 332 sig_builder.AddParam(MachineType::Pointer()); |
| 331 } | 333 } |
| 332 signature_ = sig_builder.Build(); | 334 signature_ = sig_builder.Build(); |
| 333 } | 335 } |
| 334 | 336 |
| 335 void Init(CallDescriptor* descriptor, MachineType p0 = MachineType::None(), | 337 template <typename... ParamTypes> |
| 336 MachineType p1 = MachineType::None(), | 338 void Init(CallDescriptor* descriptor) { |
| 337 MachineType p2 = MachineType::None(), | 339 DCHECK_NOT_NULL(descriptor); |
| 338 MachineType p3 = MachineType::None()) { | 340 // Create the TF graph for the wrapper. |
| 339 // Create the TF graph for the wrapper. The wrapper always takes four | |
| 340 // pointers as parameters, but may not pass the values of all pointers to | |
| 341 // the actual test function. | |
| 342 | 341 |
| 343 // Function, effect, and control. | 342 // Function, effect, and control. |
| 344 Node** parameters = | 343 Node** parameters = zone()->template NewArray<Node*>(num_params_ + 3); |
| 345 zone()->template NewArray<Node*>(WASM_RUNNER_MAX_NUM_PARAMETERS + 3); | |
| 346 graph()->SetStart(graph()->NewNode(common()->Start(6))); | 344 graph()->SetStart(graph()->NewNode(common()->Start(6))); |
| 347 Node* effect = graph()->start(); | 345 Node* effect = graph()->start(); |
| 348 int parameter_count = 0; | 346 int parameter_count = 0; |
| 349 | 347 |
| 350 // Dummy node which gets replaced in SetInnerCode. | 348 // Dummy node which gets replaced in SetInnerCode. |
| 351 inner_code_node_ = graph()->NewNode(common()->Int32Constant(0)); | 349 inner_code_node_ = graph()->NewNode(common()->Int32Constant(0)); |
| 352 parameters[parameter_count++] = inner_code_node_; | 350 parameters[parameter_count++] = inner_code_node_; |
| 353 | 351 |
| 354 if (p0 != MachineType::None()) { | 352 std::array<MachineType, sizeof...(ParamTypes)> mach_types{ |
|
titzer
2016/12/14 17:31:14
Can you factor this std::array creation into a met
Clemens Hammacher
2016/12/14 20:41:38
Done. It turned out that also the ReturnType was o
| |
| 353 {MachineTypeForC<ParamTypes>()...}}; | |
| 354 int param_idx = 0; | |
| 355 for (MachineType t : mach_types) { | |
| 356 DCHECK_NE(MachineType::None(), t); | |
| 355 parameters[parameter_count] = graph()->NewNode( | 357 parameters[parameter_count] = graph()->NewNode( |
| 356 machine()->Load(p0), | 358 machine()->Load(t), |
| 357 graph()->NewNode(common()->Parameter(0), graph()->start()), | 359 graph()->NewNode(common()->Parameter(param_idx++), graph()->start()), |
| 358 graph()->NewNode(common()->Int32Constant(0)), effect, | 360 graph()->NewNode(common()->Int32Constant(0)), effect, |
| 359 graph()->start()); | 361 graph()->start()); |
| 360 effect = parameters[parameter_count++]; | 362 effect = parameters[parameter_count++]; |
| 361 } | |
| 362 if (p1 != MachineType::None()) { | |
| 363 parameters[parameter_count] = graph()->NewNode( | |
| 364 machine()->Load(p1), | |
| 365 graph()->NewNode(common()->Parameter(1), graph()->start()), | |
| 366 graph()->NewNode(common()->Int32Constant(0)), effect, | |
| 367 graph()->start()); | |
| 368 effect = parameters[parameter_count++]; | |
| 369 } | |
| 370 if (p2 != MachineType::None()) { | |
| 371 parameters[parameter_count] = graph()->NewNode( | |
| 372 machine()->Load(p2), | |
| 373 graph()->NewNode(common()->Parameter(2), graph()->start()), | |
| 374 graph()->NewNode(common()->Int32Constant(0)), effect, | |
| 375 graph()->start()); | |
| 376 effect = parameters[parameter_count++]; | |
| 377 } | |
| 378 if (p3 != MachineType::None()) { | |
| 379 parameters[parameter_count] = graph()->NewNode( | |
| 380 machine()->Load(p3), | |
| 381 graph()->NewNode(common()->Parameter(3), graph()->start()), | |
| 382 graph()->NewNode(common()->Int32Constant(0)), effect, | |
| 383 graph()->start()); | |
| 384 effect = parameters[parameter_count++]; | |
| 385 } | 363 } |
| 386 | 364 |
| 387 parameters[parameter_count++] = effect; | 365 parameters[parameter_count++] = effect; |
| 388 parameters[parameter_count++] = graph()->start(); | 366 parameters[parameter_count++] = graph()->start(); |
| 389 Node* call = graph()->NewNode(common()->Call(descriptor), parameter_count, | 367 Node* call = graph()->NewNode(common()->Call(descriptor), parameter_count, |
| 390 parameters); | 368 parameters); |
| 391 | 369 |
| 392 effect = graph()->NewNode( | 370 effect = graph()->NewNode( |
| 393 machine()->Store( | 371 machine()->Store( |
| 394 StoreRepresentation(MachineTypeForC<ReturnType>().representation(), | 372 StoreRepresentation(MachineTypeForC<ReturnType>().representation(), |
| 395 WriteBarrierKind::kNoWriteBarrier)), | 373 WriteBarrierKind::kNoWriteBarrier)), |
| 396 graph()->NewNode(common()->Parameter(WASM_RUNNER_MAX_NUM_PARAMETERS), | 374 graph()->NewNode(common()->Parameter(num_params_), graph()->start()), |
| 397 graph()->start()), | |
| 398 graph()->NewNode(common()->Int32Constant(0)), call, effect, | 375 graph()->NewNode(common()->Int32Constant(0)), call, effect, |
| 399 graph()->start()); | 376 graph()->start()); |
| 400 Node* zero = graph()->NewNode(common()->Int32Constant(0)); | 377 Node* zero = graph()->NewNode(common()->Int32Constant(0)); |
| 401 Node* r = graph()->NewNode( | 378 Node* r = graph()->NewNode( |
| 402 common()->Return(), zero, | 379 common()->Return(), zero, |
| 403 graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)), | 380 graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)), |
| 404 effect, graph()->start()); | 381 effect, graph()->start()); |
| 405 graph()->SetEnd(graph()->NewNode(common()->End(2), r, graph()->start())); | 382 graph()->SetEnd(graph()->NewNode(common()->End(2), r, graph()->start())); |
| 406 } | 383 } |
| 407 | 384 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 446 | 423 |
| 447 return code_; | 424 return code_; |
| 448 } | 425 } |
| 449 | 426 |
| 450 Signature<MachineType>* signature() const { return signature_; } | 427 Signature<MachineType>* signature() const { return signature_; } |
| 451 | 428 |
| 452 private: | 429 private: |
| 453 Node* inner_code_node_; | 430 Node* inner_code_node_; |
| 454 Handle<Code> code_; | 431 Handle<Code> code_; |
| 455 Signature<MachineType>* signature_; | 432 Signature<MachineType>* signature_; |
| 433 int num_params_; | |
| 456 }; | 434 }; |
| 457 | 435 |
| 458 // A helper for compiling WASM functions for testing. This class can create a | 436 // A helper for compiling WASM functions for testing. |
| 459 // standalone function if {module} is NULL or a function within a | 437 // It contains the internal state for compilation (i.e. TurboFan graph) and |
| 460 // {TestingModule}. It contains the internal state for compilation (i.e. | 438 // interpretation (by adding to the interpreter manually). |
| 461 // TurboFan graph) and interpretation (by adding to the interpreter manually). | 439 class WasmFunctionCompiler : private GraphAndBuilders { |
| 462 class WasmFunctionCompiler : public HandleAndZoneScope, | |
| 463 private GraphAndBuilders { | |
| 464 public: | 440 public: |
| 465 explicit WasmFunctionCompiler( | 441 Isolate* isolate() { return testing_module_->isolate(); } |
| 466 FunctionSig* sig, WasmExecutionMode mode, | |
| 467 Vector<const char> debug_name = ArrayVector("<WASM UNNAMED>")) | |
| 468 : GraphAndBuilders(main_zone()), | |
| 469 execution_mode_(mode), | |
| 470 jsgraph(this->isolate(), this->graph(), this->common(), nullptr, | |
| 471 nullptr, this->machine()), | |
| 472 sig(sig), | |
| 473 descriptor_(nullptr), | |
| 474 testing_module_(nullptr), | |
| 475 debug_name_(debug_name), | |
| 476 local_decls(main_zone(), sig), | |
| 477 source_position_table_(this->graph()), | |
| 478 interpreter_(nullptr) { | |
| 479 // Create our own function. | |
| 480 function_ = new WasmFunction(); | |
| 481 function_->sig = sig; | |
| 482 function_->func_index = 0; | |
| 483 function_->sig_index = 0; | |
| 484 if (mode == kExecuteInterpreted) { | |
| 485 ModuleBytesEnv empty_env(nullptr, nullptr, Vector<const byte>::empty()); | |
| 486 interpreter_ = new WasmInterpreter(empty_env, zone()->allocator()); | |
| 487 int index = interpreter_->AddFunctionForTesting(function_); | |
| 488 CHECK_EQ(0, index); | |
| 489 } | |
| 490 } | |
| 491 | |
| 492 explicit WasmFunctionCompiler( | |
| 493 FunctionSig* sig, TestingModule* module, | |
| 494 Vector<const char> debug_name = ArrayVector("<WASM UNNAMED>")) | |
| 495 : GraphAndBuilders(main_zone()), | |
| 496 execution_mode_(module->execution_mode()), | |
| 497 jsgraph(this->isolate(), this->graph(), this->common(), nullptr, | |
| 498 nullptr, this->machine()), | |
| 499 sig(sig), | |
| 500 descriptor_(nullptr), | |
| 501 testing_module_(module), | |
| 502 debug_name_(debug_name), | |
| 503 local_decls(main_zone(), sig), | |
| 504 source_position_table_(this->graph()), | |
| 505 interpreter_(module->interpreter()) { | |
| 506 // Get a new function from the testing module. | |
| 507 int index = module->AddFunction(sig, Handle<Code>::null()); | |
| 508 function_ = testing_module_->GetFunctionAt(index); | |
| 509 } | |
| 510 | |
| 511 ~WasmFunctionCompiler() { | |
| 512 if (testing_module_) return; // testing module owns the below things. | |
| 513 delete function_; | |
| 514 if (interpreter_) delete interpreter_; | |
| 515 } | |
| 516 | |
| 517 WasmExecutionMode execution_mode_; | |
| 518 JSGraph jsgraph; | |
| 519 FunctionSig* sig; | |
| 520 // The call descriptor is initialized when the function is compiled. | |
| 521 CallDescriptor* descriptor_; | |
| 522 TestingModule* testing_module_; | |
| 523 Vector<const char> debug_name_; | |
| 524 WasmFunction* function_; | |
| 525 LocalDeclEncoder local_decls; | |
| 526 SourcePositionTable source_position_table_; | |
| 527 WasmInterpreter* interpreter_; | |
| 528 | |
| 529 Isolate* isolate() { return main_isolate(); } | |
| 530 Graph* graph() const { return main_graph_; } | 442 Graph* graph() const { return main_graph_; } |
| 531 Zone* zone() const { return graph()->zone(); } | 443 Zone* zone() const { return graph()->zone(); } |
| 532 CommonOperatorBuilder* common() { return &main_common_; } | 444 CommonOperatorBuilder* common() { return &main_common_; } |
| 533 MachineOperatorBuilder* machine() { return &main_machine_; } | 445 MachineOperatorBuilder* machine() { return &main_machine_; } |
| 534 void InitializeDescriptor() { | 446 void InitializeDescriptor() { |
| 535 if (descriptor_ == nullptr) { | 447 if (descriptor_ == nullptr) { |
| 536 descriptor_ = testing_module_->GetWasmCallDescriptor(main_zone(), sig); | 448 descriptor_ = testing_module_->GetWasmCallDescriptor(zone(), sig); |
| 537 } | 449 } |
| 538 } | 450 } |
| 539 CallDescriptor* descriptor() { return descriptor_; } | 451 CallDescriptor* descriptor() { return descriptor_; } |
| 540 uint32_t function_index() { return function_->func_index; } | 452 uint32_t function_index() { return function_->func_index; } |
| 541 | 453 |
| 542 void Build(const byte* start, const byte* end) { | 454 void Build(const byte* start, const byte* end) { |
| 543 // Build the TurboFan graph. | 455 local_decls.Prepend(zone(), &start, &end); |
| 544 local_decls.Prepend(main_zone(), &start, &end); | |
| 545 TestBuildingGraph(main_zone(), &jsgraph, testing_module_, sig, | |
| 546 &source_position_table_, start, end); | |
| 547 if (interpreter_) { | 456 if (interpreter_) { |
| 548 // Add the code to the interpreter. | 457 // Add the code to the interpreter. |
| 549 CHECK(interpreter_->SetFunctionCodeForTesting(function_, start, end)); | 458 CHECK(interpreter_->SetFunctionCodeForTesting(function_, start, end)); |
| 459 return; | |
| 550 } | 460 } |
| 461 | |
| 462 // Build the TurboFan graph. | |
| 463 TestBuildingGraph(zone(), &jsgraph, testing_module_, sig, | |
| 464 &source_position_table_, start, end); | |
| 465 Handle<Code> code = Compile(); | |
| 466 testing_module_->SetFunctionCode(function_index(), code); | |
| 551 } | 467 } |
| 552 | 468 |
| 553 byte AllocateLocal(LocalType type) { | 469 byte AllocateLocal(LocalType type) { |
| 554 uint32_t index = local_decls.AddLocals(1, type); | 470 uint32_t index = local_decls.AddLocals(1, type); |
| 555 byte result = static_cast<byte>(index); | 471 byte result = static_cast<byte>(index); |
| 556 DCHECK_EQ(index, result); | 472 DCHECK_EQ(index, result); |
| 557 return result; | 473 return result; |
| 558 } | 474 } |
| 559 | 475 |
| 476 void SetSigIndex(int sig_index) { function_->sig_index = sig_index; } | |
| 477 | |
| 478 private: | |
| 479 template <typename ReturnType, typename... ParamTypes> | |
| 480 friend class WasmRunner; | |
| 481 | |
| 482 explicit WasmFunctionCompiler(Zone* zone, FunctionSig* sig, | |
| 483 TestingModule* module) | |
| 484 : GraphAndBuilders(zone), | |
| 485 jsgraph(module->isolate(), this->graph(), this->common(), nullptr, | |
| 486 nullptr, this->machine()), | |
| 487 sig(sig), | |
| 488 descriptor_(nullptr), | |
| 489 testing_module_(module), | |
| 490 local_decls(zone, sig), | |
| 491 source_position_table_(this->graph()), | |
| 492 interpreter_(module->interpreter()) { | |
| 493 // Get a new function from the testing module. | |
| 494 int index = module->AddFunction(sig, Handle<Code>::null()); | |
| 495 function_ = testing_module_->GetFunctionAt(index); | |
| 496 } | |
| 497 | |
| 560 Handle<Code> Compile() { | 498 Handle<Code> Compile() { |
| 561 InitializeDescriptor(); | 499 InitializeDescriptor(); |
| 562 CallDescriptor* desc = descriptor_; | 500 CallDescriptor* desc = descriptor_; |
| 563 if (kPointerSize == 4) { | 501 if (kPointerSize == 4) { |
| 564 desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc); | 502 desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc); |
| 565 } | 503 } |
| 566 CompilationInfo info(debug_name_, this->isolate(), this->zone(), | 504 CompilationInfo info(CStrVector("wasm"), this->isolate(), this->zone(), |
| 567 Code::ComputeFlags(Code::WASM_FUNCTION)); | 505 Code::ComputeFlags(Code::WASM_FUNCTION)); |
| 568 std::unique_ptr<CompilationJob> job(Pipeline::NewWasmCompilationJob( | 506 std::unique_ptr<CompilationJob> job(Pipeline::NewWasmCompilationJob( |
| 569 &info, &jsgraph, desc, &source_position_table_, nullptr)); | 507 &info, &jsgraph, desc, &source_position_table_, nullptr)); |
| 570 if (job->ExecuteJob() != CompilationJob::SUCCEEDED || | 508 if (job->ExecuteJob() != CompilationJob::SUCCEEDED || |
| 571 job->FinalizeJob() != CompilationJob::SUCCEEDED) | 509 job->FinalizeJob() != CompilationJob::SUCCEEDED) |
| 572 return Handle<Code>::null(); | 510 return Handle<Code>::null(); |
| 573 | 511 |
| 574 Handle<Code> code = info.code(); | 512 Handle<Code> code = info.code(); |
| 575 | 513 |
| 576 // Length is always 2, since usually <wasm_obj, func_index> is stored in | 514 // Length is always 2, since usually <wasm_obj, func_index> is stored in |
| 577 // the deopt data. Here, we only store the function index. | 515 // the deopt data. Here, we only store the function index. |
| 578 DCHECK(code->deoptimization_data() == nullptr || | 516 DCHECK(code->deoptimization_data() == nullptr || |
| 579 code->deoptimization_data()->length() == 0); | 517 code->deoptimization_data()->length() == 0); |
| 580 Handle<FixedArray> deopt_data = | 518 Handle<FixedArray> deopt_data = |
| 581 isolate()->factory()->NewFixedArray(2, TENURED); | 519 isolate()->factory()->NewFixedArray(2, TENURED); |
| 582 deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index()))); | 520 deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index()))); |
| 583 deopt_data->set_length(2); | 521 deopt_data->set_length(2); |
| 584 code->set_deoptimization_data(*deopt_data); | 522 code->set_deoptimization_data(*deopt_data); |
| 585 | 523 |
| 586 #ifdef ENABLE_DISASSEMBLER | 524 #ifdef ENABLE_DISASSEMBLER |
| 587 if (FLAG_print_opt_code) { | 525 if (FLAG_print_opt_code) { |
| 588 OFStream os(stdout); | 526 OFStream os(stdout); |
| 589 code->Disassemble("wasm code", os); | 527 code->Disassemble("wasm code", os); |
| 590 } | 528 } |
| 591 #endif | 529 #endif |
| 592 | 530 |
| 593 return code; | 531 return code; |
| 594 } | 532 } |
| 595 | 533 |
| 596 uint32_t CompileAndAdd(uint16_t sig_index = 0) { | 534 JSGraph jsgraph; |
| 597 CHECK(testing_module_); | 535 FunctionSig* sig; |
| 598 function_->sig_index = sig_index; | 536 // The call descriptor is initialized when the function is compiled. |
| 599 Handle<Code> code = Compile(); | 537 CallDescriptor* descriptor_; |
| 600 testing_module_->SetFunctionCode(function_index(), code); | 538 TestingModule* testing_module_; |
| 601 return function_index(); | 539 Vector<const char> debug_name_; |
| 602 } | 540 WasmFunction* function_; |
| 603 | 541 LocalDeclEncoder local_decls; |
| 604 // Set the context, such that e.g. runtime functions can be called. | 542 SourcePositionTable source_position_table_; |
| 605 void SetModuleContext() { | 543 WasmInterpreter* interpreter_; |
| 606 if (!testing_module_->instance->context.is_null()) { | |
| 607 CHECK(testing_module_->instance->context.is_identical_to( | |
| 608 main_isolate()->native_context())); | |
| 609 return; | |
| 610 } | |
| 611 testing_module_->instance->context = main_isolate()->native_context(); | |
| 612 } | |
| 613 }; | 544 }; |
| 614 | 545 |
| 615 // A helper class to build graphs from Wasm bytecode, generate machine | 546 // A helper class to build a module around Wasm bytecode, generate machine |
| 616 // code, and run that code. | 547 // code, and run that code. |
| 617 template <typename ReturnType> | 548 template <typename MainReturnType, typename... MainParamTypes> |
| 618 class WasmRunner { | 549 class WasmRunner : public HandleAndZoneScope { |
|
titzer
2016/12/14 17:31:14
Can you factor out a base class to avoid duplicati
Clemens Hammacher
2016/12/14 20:41:38
Done.
| |
| 619 public: | 550 public: |
| 620 WasmRunner(WasmExecutionMode execution_mode, | 551 explicit WasmRunner(WasmExecutionMode execution_mode) |
| 621 MachineType p0 = MachineType::None(), | 552 : zone_(&allocator_, ZONE_NAME), |
| 622 MachineType p1 = MachineType::None(), | 553 module_(&zone_, execution_mode), |
| 623 MachineType p2 = MachineType::None(), | 554 wrapper_(&zone_, sizeof...(MainParamTypes)) { |
| 624 MachineType p3 = MachineType::None()) | 555 NewFunction<MainReturnType, MainParamTypes...>(); |
| 625 : zone(&allocator_, ZONE_NAME), | |
| 626 compiled_(false), | |
| 627 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, | |
| 628 GetParameterCount(p0, p1, p2, p3), storage_), | |
| 629 compiler_(&signature_, execution_mode) { | |
| 630 InitSigStorage(p0, p1, p2, p3); | |
| 631 } | |
| 632 | |
| 633 WasmRunner(TestingModule* module, MachineType p0 = MachineType::None(), | |
| 634 MachineType p1 = MachineType::None(), | |
| 635 MachineType p2 = MachineType::None(), | |
| 636 MachineType p3 = MachineType::None()) | |
| 637 : zone(&allocator_, ZONE_NAME), | |
| 638 compiled_(false), | |
| 639 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, | |
| 640 GetParameterCount(p0, p1, p2, p3), storage_), | |
| 641 compiler_(&signature_, module), | |
| 642 possible_nondeterminism_(false) { | |
| 643 DCHECK(module); | |
| 644 InitSigStorage(p0, p1, p2, p3); | |
| 645 } | |
| 646 | |
| 647 void InitSigStorage(MachineType p0, MachineType p1, MachineType p2, | |
| 648 MachineType p3) { | |
| 649 int index = 0; | |
| 650 MachineType ret = MachineTypeForC<ReturnType>(); | |
| 651 if (ret != MachineType::None()) { | |
| 652 storage_[index++] = WasmOpcodes::LocalTypeFor(ret); | |
| 653 } | |
| 654 if (p0 != MachineType::None()) | |
| 655 storage_[index++] = WasmOpcodes::LocalTypeFor(p0); | |
| 656 if (p1 != MachineType::None()) | |
| 657 storage_[index++] = WasmOpcodes::LocalTypeFor(p1); | |
| 658 if (p2 != MachineType::None()) | |
| 659 storage_[index++] = WasmOpcodes::LocalTypeFor(p2); | |
| 660 if (p3 != MachineType::None()) | |
| 661 storage_[index++] = WasmOpcodes::LocalTypeFor(p3); | |
| 662 | |
| 663 compiler_.InitializeDescriptor(); | |
| 664 wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3); | |
| 665 } | 556 } |
| 666 | 557 |
| 667 // Builds a graph from the given Wasm code and generates the machine | 558 // Builds a graph from the given Wasm code and generates the machine |
| 668 // code and call wrapper for that graph. This method must not be called | 559 // code and call wrapper for that graph. This method must not be called |
| 669 // more than once. | 560 // more than once. |
| 670 void Build(const byte* start, const byte* end) { | 561 void Build(const byte* start, const byte* end) { |
| 671 CHECK(!compiled_); | 562 CHECK(!compiled_); |
| 672 compiled_ = true; | 563 compiled_ = true; |
| 673 compiler_.Build(start, end); | 564 functions_[0]->Build(start, end); |
| 674 | |
| 675 if (!interpret()) { | |
| 676 // Compile machine code and install it into the module. | |
| 677 Handle<Code> code = compiler_.Compile(); | |
| 678 | |
| 679 if (compiler_.testing_module_) { | |
| 680 // Update the table of function code in the module. | |
| 681 compiler_.testing_module_->SetFunctionCode( | |
| 682 compiler_.function_->func_index, code); | |
| 683 } | |
| 684 | |
| 685 wrapper_.SetInnerCode(code); | |
| 686 } | |
| 687 } | 565 } |
| 688 | 566 |
| 689 ReturnType Call() { | 567 // Resets the state for building the next function. |
| 690 if (interpret()) { | 568 // The main function called will always be the first function. |
| 691 return CallInterpreter(Vector<WasmVal>(nullptr, 0)); | 569 template <typename NextReturnType, typename... NextParamTypes> |
| 692 } else { | 570 WasmFunctionCompiler& NewFunction() { |
| 693 return Call(0, 0, 0, 0); | 571 return NewFunction(CreateSig<NextReturnType, NextParamTypes...>()); |
| 694 } | |
| 695 } | 572 } |
| 696 | 573 |
| 697 template <typename P0> | 574 // Resets the state for building the next function. |
| 698 ReturnType Call(P0 p0) { | 575 // The main function called will be the last generated function. |
| 699 if (interpret()) { | 576 // Returns the index of the previously built function. |
| 700 WasmVal args[] = {WasmVal(p0)}; | 577 WasmFunctionCompiler& NewFunction(FunctionSig* sig) { |
| 701 return CallInterpreter(ArrayVector(args)); | 578 functions_.emplace_back(new WasmFunctionCompiler(&zone_, sig, &module_)); |
| 702 } else { | 579 return *functions_.back(); |
| 703 return Call(p0, 0, 0, 0); | |
| 704 } | |
| 705 } | 580 } |
| 706 | 581 |
| 707 template <typename P0, typename P1> | 582 MainReturnType Call(MainParamTypes... p) { |
| 708 ReturnType Call(P0 p0, P1 p1) { | 583 DCHECK(compiled_); |
| 709 if (interpret()) { | 584 if (interpret()) return CallInterpreter(p...); |
| 710 WasmVal args[] = {WasmVal(p0), WasmVal(p1)}; | 585 |
| 711 return CallInterpreter(ArrayVector(args)); | 586 wrapper_.template Init<MainParamTypes...>(functions_[0]->descriptor()); |
| 712 } else { | 587 wrapper_.SetInnerCode( |
| 713 return Call(p0, p1, 0, 0); | 588 module_.GetFunctionCode(functions_[0]->function_index())); |
| 714 } | 589 CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(), |
| 590 wrapper_.GetWrapperCode(), wrapper_.signature()); | |
| 591 MainReturnType return_value; | |
| 592 int32_t result = runner.Call(static_cast<void*>(&p)..., | |
| 593 static_cast<void*>(&return_value)); | |
| 594 CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result); | |
| 595 return return_value; | |
| 715 } | 596 } |
| 716 | 597 |
| 717 template <typename P0, typename P1, typename P2> | 598 MainReturnType CallInterpreter(MainParamTypes... p) { |
| 718 ReturnType Call(P0 p0, P1 p1, P2 p2) { | |
| 719 if (interpret()) { | |
| 720 WasmVal args[] = {WasmVal(p0), WasmVal(p1), WasmVal(p2)}; | |
| 721 return CallInterpreter(ArrayVector(args)); | |
| 722 } else { | |
| 723 return Call(p0, p1, p2, 0); | |
| 724 } | |
| 725 } | |
| 726 | |
| 727 template <typename P0, typename P1, typename P2, typename P3> | |
| 728 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) { | |
| 729 if (interpret()) { | |
| 730 WasmVal args[] = {WasmVal(p0), WasmVal(p1), WasmVal(p2), WasmVal(p3)}; | |
| 731 return CallInterpreter(ArrayVector(args)); | |
| 732 } else { | |
| 733 CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(), | |
| 734 wrapper_.GetWrapperCode(), | |
| 735 wrapper_.signature()); | |
| 736 ReturnType return_value; | |
| 737 int32_t result = runner.Call<void*, void*, void*, void*, void*>( | |
| 738 &p0, &p1, &p2, &p3, &return_value); | |
| 739 CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result); | |
| 740 return return_value; | |
| 741 } | |
| 742 } | |
| 743 | |
| 744 ReturnType CallInterpreter(Vector<WasmVal> args) { | |
| 745 CHECK_EQ(args.length(), | |
| 746 static_cast<int>(compiler_.function_->sig->parameter_count())); | |
| 747 WasmInterpreter::Thread* thread = interpreter()->GetThread(0); | 599 WasmInterpreter::Thread* thread = interpreter()->GetThread(0); |
| 748 thread->Reset(); | 600 thread->Reset(); |
| 749 thread->PushFrame(compiler_.function_, args.start()); | 601 std::array<WasmVal, sizeof...(p)> args{{WasmVal(p)...}}; |
| 602 thread->PushFrame(functions_[0]->function_, args.data()); | |
| 750 if (thread->Run() == WasmInterpreter::FINISHED) { | 603 if (thread->Run() == WasmInterpreter::FINISHED) { |
| 751 WasmVal val = thread->GetReturnValue(); | 604 WasmVal val = thread->GetReturnValue(); |
| 752 possible_nondeterminism_ |= thread->PossibleNondeterminism(); | 605 possible_nondeterminism_ |= thread->PossibleNondeterminism(); |
| 753 return val.to<ReturnType>(); | 606 return val.to<MainReturnType>(); |
| 754 } else if (thread->state() == WasmInterpreter::TRAPPED) { | 607 } else if (thread->state() == WasmInterpreter::TRAPPED) { |
| 755 // TODO(titzer): return the correct trap code | 608 // TODO(titzer): return the correct trap code |
| 756 int64_t result = 0xdeadbeefdeadbeef; | 609 int64_t result = 0xdeadbeefdeadbeef; |
| 757 return static_cast<ReturnType>(result); | 610 return static_cast<MainReturnType>(result); |
| 758 } else { | 611 } else { |
| 759 // TODO(titzer): falling off end | 612 // TODO(titzer): falling off end |
| 760 ReturnType val = 0; | 613 MainReturnType val = 0; |
| 761 return val; | 614 return val; |
| 762 } | 615 } |
| 763 } | 616 } |
| 764 | 617 |
| 765 byte AllocateLocal(LocalType type) { return compiler_.AllocateLocal(type); } | 618 byte AllocateLocal(LocalType type) { |
| 619 return functions_[0]->AllocateLocal(type); | |
| 620 } | |
| 766 | 621 |
| 767 WasmFunction* function() { return compiler_.function_; } | 622 WasmFunction* function() { return functions_[0]->function_; } |
| 768 WasmInterpreter* interpreter() { return compiler_.interpreter_; } | 623 WasmInterpreter* interpreter() { return functions_[0]->interpreter_; } |
| 769 bool possible_nondeterminism() { return possible_nondeterminism_; } | 624 bool possible_nondeterminism() { return possible_nondeterminism_; } |
| 625 TestingModule& module() { return module_; } | |
| 626 Zone* zone() { return &zone_; } | |
| 770 | 627 |
| 771 protected: | 628 // Set the context, such that e.g. runtime functions can be called. |
| 629 void SetModuleContext() { | |
| 630 if (!module_.instance->context.is_null()) { | |
| 631 CHECK(module_.instance->context.is_identical_to( | |
| 632 main_isolate()->native_context())); | |
| 633 return; | |
| 634 } | |
| 635 module_.instance->context = main_isolate()->native_context(); | |
| 636 } | |
| 637 | |
| 638 private: | |
| 639 template <typename ReturnType, typename... ParamTypes> | |
| 640 FunctionSig* CreateSig() { | |
| 641 MachineType ret_and_params[] = {MachineTypeForC<ReturnType>(), | |
| 642 MachineTypeForC<ParamTypes>()...}; | |
| 643 size_t return_count = ret_and_params[0] == MachineType::None() ? 0 : 1; | |
|
titzer
2016/12/14 17:31:14
Same here. Can you factor this out to be an entryp
Clemens Hammacher
2016/12/14 20:41:38
Done.
| |
| 644 size_t param_count = sizeof...(ParamTypes); | |
| 645 | |
| 646 // Allocate storage array in zone. | |
| 647 LocalType* sig_types = | |
| 648 zone_.NewArray<LocalType>(return_count + param_count); | |
| 649 | |
| 650 // Convert machine types to local types, and check that there are no | |
| 651 // MachineType::None()'s in the parameters. | |
| 652 if (return_count) | |
| 653 sig_types[0] = WasmOpcodes::LocalTypeFor(ret_and_params[0]); | |
| 654 for (size_t i = 0; i < param_count; ++i) { | |
| 655 CHECK_NE(MachineType::None(), ret_and_params[i + 1]); | |
| 656 sig_types[i + return_count] = | |
| 657 WasmOpcodes::LocalTypeFor(ret_and_params[i + 1]); | |
| 658 } | |
| 659 return new (&zone_) FunctionSig(return_count, param_count, sig_types); | |
| 660 } | |
| 772 v8::internal::AccountingAllocator allocator_; | 661 v8::internal::AccountingAllocator allocator_; |
| 773 Zone zone; | 662 Zone zone_; |
| 774 bool compiled_; | 663 TestingModule module_; |
| 775 LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS]; | 664 std::vector<std::unique_ptr<WasmFunctionCompiler>> functions_; |
| 776 FunctionSig signature_; | 665 WasmFunctionWrapper<MainReturnType> wrapper_; |
| 777 WasmFunctionCompiler compiler_; | 666 bool compiled_ = false; |
| 778 WasmFunctionWrapper<ReturnType> wrapper_; | 667 bool possible_nondeterminism_ = false; |
| 779 bool possible_nondeterminism_; | |
| 780 | 668 |
| 781 bool interpret() { return compiler_.execution_mode_ == kExecuteInterpreted; } | 669 bool interpret() { return module_.execution_mode() == kExecuteInterpreted; } |
| 782 | |
| 783 static size_t GetParameterCount(MachineType p0, MachineType p1, | |
| 784 MachineType p2, MachineType p3) { | |
| 785 if (p0 == MachineType::None()) return 0; | |
| 786 if (p1 == MachineType::None()) return 1; | |
| 787 if (p2 == MachineType::None()) return 2; | |
| 788 if (p3 == MachineType::None()) return 3; | |
| 789 return 4; | |
| 790 } | |
| 791 }; | 670 }; |
| 792 | 671 |
| 793 // A macro to define tests that run in different engine configurations. | 672 // A macro to define tests that run in different engine configurations. |
| 794 #define WASM_EXEC_TEST(name) \ | 673 #define WASM_EXEC_TEST(name) \ |
| 795 void RunWasm_##name(WasmExecutionMode execution_mode); \ | 674 void RunWasm_##name(WasmExecutionMode execution_mode); \ |
| 796 TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \ | 675 TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \ |
| 797 TEST(RunWasmInterpreted_##name) { RunWasm_##name(kExecuteInterpreted); } \ | 676 TEST(RunWasmInterpreted_##name) { RunWasm_##name(kExecuteInterpreted); } \ |
| 798 void RunWasm_##name(WasmExecutionMode execution_mode) | 677 void RunWasm_##name(WasmExecutionMode execution_mode) |
| 799 | 678 |
| 800 #define WASM_EXEC_COMPILED_TEST(name) \ | 679 #define WASM_EXEC_COMPILED_TEST(name) \ |
| 801 void RunWasm_##name(WasmExecutionMode execution_mode); \ | 680 void RunWasm_##name(WasmExecutionMode execution_mode); \ |
| 802 TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \ | 681 TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \ |
| 803 void RunWasm_##name(WasmExecutionMode execution_mode) | 682 void RunWasm_##name(WasmExecutionMode execution_mode) |
| 804 | 683 |
| 805 } // namespace | 684 } // namespace |
| 806 | 685 |
| 807 #endif | 686 #endif |
| OLD | NEW |