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

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

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

Powered by Google App Engine
This is Rietveld 408576698