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

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

Issue 2551043002: [wasm] Make WasmRunner the central test structure (Closed)
Patch Set: Fix simd lowering test 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 <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
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
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
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
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
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