blob: 7ee39818853a078ddcaaf1ddc34569ba332fb0d0 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
3// found in the LICENSE file.
4
5#ifndef WASM_RUN_UTILS_H
6#define WASM_RUN_UTILS_H
7
8#include <stdint.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include "src/base/utils/random-number-generator.h"
13
14#include "src/compiler/graph-visualizer.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010015#include "src/compiler/int64-lowering.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016#include "src/compiler/js-graph.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010017#include "src/compiler/node.h"
18#include "src/compiler/pipeline.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019#include "src/compiler/wasm-compiler.h"
20
21#include "src/wasm/ast-decoder.h"
22#include "src/wasm/wasm-js.h"
23#include "src/wasm/wasm-module.h"
24#include "src/wasm/wasm-opcodes.h"
25
Ben Murdoch097c5b22016-05-18 11:27:45 +010026#include "src/zone.h"
27
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028#include "test/cctest/cctest.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010029#include "test/cctest/compiler/call-tester.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030#include "test/cctest/compiler/graph-builder-tester.h"
31
32// TODO(titzer): pull WASM_64 up to a common header.
33#if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
34#define WASM_64 1
35#else
36#define WASM_64 0
37#endif
38
Ben Murdoch097c5b22016-05-18 11:27:45 +010039static const uint32_t kMaxFunctions = 10;
40
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000041// TODO(titzer): check traps more robustly in tests.
42// Currently, in tests, we just return 0xdeadbeef from the function in which
43// the trap occurs if the runtime context is not available to throw a JavaScript
44// exception.
45#define CHECK_TRAP32(x) \
46 CHECK_EQ(0xdeadbeef, (bit_cast<uint32_t>(x)) & 0xFFFFFFFF)
47#define CHECK_TRAP64(x) \
48 CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF)
49#define CHECK_TRAP(x) CHECK_TRAP32(x)
50
Ben Murdoch097c5b22016-05-18 11:27:45 +010051#define WASM_RUNNER_MAX_NUM_PARAMETERS 4
52#define WASM_WRAPPER_RETURN_VALUE 8754
53
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000054namespace {
55using namespace v8::base;
56using namespace v8::internal;
57using namespace v8::internal::compiler;
58using namespace v8::internal::wasm;
59
60inline void init_env(FunctionEnv* env, FunctionSig* sig) {
61 env->module = nullptr;
62 env->sig = sig;
Ben Murdoch097c5b22016-05-18 11:27:45 +010063 env->local_i32_count = 0;
64 env->local_i64_count = 0;
65 env->local_f32_count = 0;
66 env->local_f64_count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067 env->SumLocals();
68}
69
70const uint32_t kMaxGlobalsSize = 128;
71
72// A helper for module environments that adds the ability to allocate memory
Ben Murdoch097c5b22016-05-18 11:27:45 +010073// and global variables. Contains a built-in {WasmModule} and
74// {WasmModuleInstance}.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000075class TestingModule : public ModuleEnv {
76 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +010077 TestingModule() : instance_(&module_), global_offset(0) {
78 module_.shared_isolate = CcTest::InitIsolateOnce();
79 module = &module_;
80 instance = &instance_;
81 instance->module = &module_;
82 instance->globals_start = global_data;
83 instance->globals_size = kMaxGlobalsSize;
84 instance->mem_start = nullptr;
85 instance->mem_size = 0;
86 instance->function_code = nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000087 linker = nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 asm_js = false;
89 memset(global_data, 0, sizeof(global_data));
90 }
91
92 ~TestingModule() {
Ben Murdoch097c5b22016-05-18 11:27:45 +010093 if (instance->mem_start) {
94 free(instance->mem_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000095 }
Ben Murdoch097c5b22016-05-18 11:27:45 +010096 if (instance->function_code) {
97 delete instance->function_code;
98 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 }
100
101 byte* AddMemory(size_t size) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100102 CHECK_NULL(instance->mem_start);
103 CHECK_EQ(0, instance->mem_size);
104 instance->mem_start = reinterpret_cast<byte*>(malloc(size));
105 CHECK(instance->mem_start);
106 memset(instance->mem_start, 0, size);
107 instance->mem_size = size;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 return raw_mem_start<byte>();
109 }
110
111 template <typename T>
112 T* AddMemoryElems(size_t count) {
113 AddMemory(count * sizeof(T));
114 return raw_mem_start<T>();
115 }
116
117 template <typename T>
118 T* AddGlobal(MachineType mem_type) {
119 WasmGlobal* global = AddGlobal(mem_type);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100120 return reinterpret_cast<T*>(instance->globals_start + global->offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000121 }
122
123 byte AddSignature(FunctionSig* sig) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124 if (!module->signatures) {
125 module->signatures = new std::vector<FunctionSig*>();
126 }
127 module->signatures->push_back(sig);
128 size_t size = module->signatures->size();
129 CHECK(size < 127);
130 return static_cast<byte>(size - 1);
131 }
132
133 template <typename T>
134 T* raw_mem_start() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100135 DCHECK(instance->mem_start);
136 return reinterpret_cast<T*>(instance->mem_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 }
138
139 template <typename T>
140 T* raw_mem_end() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100141 DCHECK(instance->mem_start);
142 return reinterpret_cast<T*>(instance->mem_start + instance->mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 }
144
145 template <typename T>
146 T raw_mem_at(int i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100147 DCHECK(instance->mem_start);
148 return reinterpret_cast<T*>(instance->mem_start)[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 }
150
151 template <typename T>
152 T raw_val_at(int i) {
153 T val;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100154 memcpy(&val, reinterpret_cast<void*>(instance->mem_start + i), sizeof(T));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 return val;
156 }
157
158 // Zero-initialize the memory.
159 void BlankMemory() {
160 byte* raw = raw_mem_start<byte>();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100161 memset(raw, 0, instance->mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000162 }
163
164 // Pseudo-randomly intialize the memory.
165 void RandomizeMemory(unsigned int seed = 88) {
166 byte* raw = raw_mem_start<byte>();
167 byte* end = raw_mem_end<byte>();
168 v8::base::RandomNumberGenerator rng;
169 rng.SetSeed(seed);
170 rng.NextBytes(raw, end - raw);
171 }
172
Ben Murdoch097c5b22016-05-18 11:27:45 +0100173 int AddFunction(FunctionSig* sig, Handle<Code> code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000174 if (module->functions == nullptr) {
175 module->functions = new std::vector<WasmFunction>();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100176 // TODO(titzer): Reserving space here to avoid the underlying WasmFunction
177 // structs from moving.
178 module->functions->reserve(kMaxFunctions);
179 instance->function_code = new std::vector<Handle<Code>>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100181 uint32_t index = static_cast<uint32_t>(module->functions->size());
182 module->functions->push_back(
183 {sig, index, 0, 0, 0, 0, 0, 0, 0, false, false});
184 instance->function_code->push_back(code);
185 DCHECK_LT(index, kMaxFunctions); // limited for testing.
186 return index;
187 }
188
189 void SetFunctionCode(uint32_t index, Handle<Code> code) {
190 instance->function_code->at(index) = code;
191 }
192
193 void AddIndirectFunctionTable(int* functions, int table_size) {
194 Isolate* isolate = module->shared_isolate;
195 Handle<FixedArray> fixed =
196 isolate->factory()->NewFixedArray(2 * table_size);
197 instance->function_table = fixed;
198 module->function_table = new std::vector<uint16_t>();
199 for (int i = 0; i < table_size; i++) {
200 module->function_table->push_back(functions[i]);
201 }
202 }
203
204 void PopulateIndirectFunctionTable() {
205 if (instance->function_table.is_null()) return;
206 int table_size = static_cast<int>(module->function_table->size());
207 for (int i = 0; i < table_size; i++) {
208 int function_index = module->function_table->at(i);
209 WasmFunction* function = &module->functions->at(function_index);
210 instance->function_table->set(i, Smi::FromInt(function->sig_index));
211 instance->function_table->set(
212 i + table_size, *instance->function_code->at(function_index));
213 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 }
215
216 private:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100217 WasmModule module_;
218 WasmModuleInstance instance_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 uint32_t global_offset;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100220 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221
222 WasmGlobal* AddGlobal(MachineType mem_type) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100223 if (!module->globals) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 module->globals = new std::vector<WasmGlobal>();
225 }
226 byte size = WasmOpcodes::MemSize(mem_type);
227 global_offset = (global_offset + size - 1) & ~(size - 1); // align
228 module->globals->push_back({0, mem_type, global_offset, false});
229 global_offset += size;
230 // limit number of globals.
231 CHECK_LT(global_offset, kMaxGlobalsSize);
232 return &module->globals->back();
233 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000234};
235
236
237inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, FunctionEnv* env,
238 const byte* start, const byte* end) {
239 compiler::WasmGraphBuilder builder(zone, jsgraph, env->sig);
240 TreeResult result = BuildTFGraph(&builder, env, start, end);
241 if (result.failed()) {
242 ptrdiff_t pc = result.error_pc - result.start;
243 ptrdiff_t pt = result.error_pt - result.start;
244 std::ostringstream str;
245 str << "Verification failed: " << result.error_code << " pc = +" << pc;
246 if (result.error_pt) str << ", pt = +" << pt;
247 str << ", msg = " << result.error_msg.get();
248 FATAL(str.str().c_str());
249 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100250 builder.Int64LoweringForTesting();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251 if (FLAG_trace_turbo_graph) {
252 OFStream os(stdout);
253 os << AsRPO(*jsgraph->graph());
254 }
255}
256
Ben Murdoch097c5b22016-05-18 11:27:45 +0100257template <typename ReturnType>
258class WasmFunctionWrapper : public HandleAndZoneScope,
259 private GraphAndBuilders {
260 public:
261 WasmFunctionWrapper()
262 : GraphAndBuilders(main_zone()),
263 inner_code_node_(nullptr),
264 signature_(nullptr) {
265 // One additional parameter for the pointer to the return value memory.
266 Signature<MachineType>::Builder sig_builder(
267 zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000268
Ben Murdoch097c5b22016-05-18 11:27:45 +0100269 sig_builder.AddReturn(MachineType::Int32());
270 for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) {
271 sig_builder.AddParam(MachineType::Pointer());
272 }
273 signature_ = sig_builder.Build();
274 }
275
276 void Init(CallDescriptor* descriptor, MachineType p0 = MachineType::None(),
277 MachineType p1 = MachineType::None(),
278 MachineType p2 = MachineType::None(),
279 MachineType p3 = MachineType::None()) {
280 // Create the TF graph for the wrapper. The wrapper always takes four
281 // pointers as parameters, but may not pass the values of all pointers to
282 // the actual test function.
283
284 // Function, effect, and control.
285 Node** parameters =
286 zone()->template NewArray<Node*>(WASM_RUNNER_MAX_NUM_PARAMETERS + 3);
287 graph()->SetStart(graph()->NewNode(common()->Start(6)));
288 Node* effect = graph()->start();
289 int parameter_count = 0;
290
291 // Dummy node which gets replaced in SetInnerCode.
292 inner_code_node_ = graph()->NewNode(common()->Int32Constant(0));
293 parameters[parameter_count++] = inner_code_node_;
294
295 if (p0 != MachineType::None()) {
296 parameters[parameter_count] = graph()->NewNode(
297 machine()->Load(p0),
298 graph()->NewNode(common()->Parameter(0), graph()->start()),
299 graph()->NewNode(common()->Int32Constant(0)), effect,
300 graph()->start());
301 effect = parameters[parameter_count++];
302 }
303 if (p1 != MachineType::None()) {
304 parameters[parameter_count] = graph()->NewNode(
305 machine()->Load(p0),
306 graph()->NewNode(common()->Parameter(1), graph()->start()),
307 graph()->NewNode(common()->Int32Constant(0)), effect,
308 graph()->start());
309 effect = parameters[parameter_count++];
310 }
311 if (p2 != MachineType::None()) {
312 parameters[parameter_count] = graph()->NewNode(
313 machine()->Load(p0),
314 graph()->NewNode(common()->Parameter(2), graph()->start()),
315 graph()->NewNode(common()->Int32Constant(0)), effect,
316 graph()->start());
317 effect = parameters[parameter_count++];
318 }
319 if (p3 != MachineType::None()) {
320 parameters[parameter_count] = graph()->NewNode(
321 machine()->Load(p0),
322 graph()->NewNode(common()->Parameter(3), graph()->start()),
323 graph()->NewNode(common()->Int32Constant(0)), effect,
324 graph()->start());
325 effect = parameters[parameter_count++];
326 }
327
328 parameters[parameter_count++] = effect;
329 parameters[parameter_count++] = graph()->start();
330 Node* call = graph()->NewNode(common()->Call(descriptor), parameter_count,
331 parameters);
332
333 effect = graph()->NewNode(
334 machine()->Store(
335 StoreRepresentation(MachineTypeForC<ReturnType>().representation(),
336 WriteBarrierKind::kNoWriteBarrier)),
337 graph()->NewNode(common()->Parameter(WASM_RUNNER_MAX_NUM_PARAMETERS),
338 graph()->start()),
339 graph()->NewNode(common()->Int32Constant(0)), call, effect,
340 graph()->start());
341 Node* r = graph()->NewNode(
342 common()->Return(),
343 graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)),
344 effect, graph()->start());
345 graph()->SetEnd(graph()->NewNode(common()->End(2), r, graph()->start()));
346 }
347
348 void SetInnerCode(Handle<Code> code_handle) {
349 NodeProperties::ChangeOp(inner_code_node_,
350 common()->HeapConstant(code_handle));
351 }
352
353 Handle<Code> GetWrapperCode() {
354 if (code_.is_null()) {
355 Isolate* isolate = CcTest::InitIsolateOnce();
356
357 CallDescriptor* descriptor =
358 Linkage::GetSimplifiedCDescriptor(zone(), signature_, true);
359
360 if (kPointerSize == 4) {
361 // One additional parameter for the pointer of the return value.
362 Signature<MachineRepresentation>::Builder rep_builder(
363 zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1);
364
365 rep_builder.AddReturn(MachineRepresentation::kWord32);
366 for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) {
367 rep_builder.AddParam(MachineRepresentation::kWord32);
368 }
369 Int64Lowering r(graph(), machine(), common(), zone(),
370 rep_builder.Build());
371 r.LowerGraph();
372 }
373
374 CompilationInfo info("testing", isolate, graph()->zone());
375 code_ =
376 Pipeline::GenerateCodeForTesting(&info, descriptor, graph(), nullptr);
377 CHECK(!code_.is_null());
378#ifdef ENABLE_DISASSEMBLER
379 if (FLAG_print_opt_code) {
380 OFStream os(stdout);
381 code_->Disassemble("wasm wrapper", os);
382 }
383#endif
384 }
385
386 return code_;
387 }
388
389 Signature<MachineType>* signature() const { return signature_; }
390
391 private:
392 Node* inner_code_node_;
393 Handle<Code> code_;
394 Signature<MachineType>* signature_;
395};
396
397// A helper for compiling WASM functions for testing. This class can create a
398// standalone function if {module} is NULL or a function within a
399// {TestingModule}. It contains the internal state for compilation (i.e.
400// TurboFan graph) and, later, interpretation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000401class WasmFunctionCompiler : public HandleAndZoneScope,
402 private GraphAndBuilders {
403 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100404 explicit WasmFunctionCompiler(FunctionSig* sig, TestingModule* module)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000405 : GraphAndBuilders(main_zone()),
406 jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
407 nullptr, this->machine()),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100408 descriptor_(nullptr),
409 testing_module_(module) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410 init_env(&env, sig);
411 env.module = module;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100412 if (module) {
413 // Get a new function from the testing module.
414 function_ = nullptr;
415 function_index_ = module->AddFunction(sig, Handle<Code>::null());
416 } else {
417 // Create our own function.
418 function_ = new WasmFunction();
419 function_->sig = sig;
420 function_index_ = 0;
421 }
422 }
423
424 ~WasmFunctionCompiler() {
425 if (function_) delete function_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 }
427
428 JSGraph jsgraph;
429 FunctionEnv env;
430 // The call descriptor is initialized when the function is compiled.
431 CallDescriptor* descriptor_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100432 TestingModule* testing_module_;
433 WasmFunction* function_;
434 int function_index_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000435
436 Isolate* isolate() { return main_isolate(); }
437 Graph* graph() const { return main_graph_; }
438 Zone* zone() const { return graph()->zone(); }
439 CommonOperatorBuilder* common() { return &main_common_; }
440 MachineOperatorBuilder* machine() { return &main_machine_; }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100441 void InitializeDescriptor() {
442 if (descriptor_ == nullptr) {
443 descriptor_ = env.module->GetWasmCallDescriptor(main_zone(), env.sig);
444 }
445 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446 CallDescriptor* descriptor() { return descriptor_; }
447
448 void Build(const byte* start, const byte* end) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100449 // Transfer local counts before compiling.
450 function()->local_i32_count = env.local_i32_count;
451 function()->local_i64_count = env.local_i64_count;
452 function()->local_f32_count = env.local_f32_count;
453 function()->local_f64_count = env.local_f64_count;
454
455 // Build the TurboFan graph.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456 TestBuildingGraph(main_zone(), &jsgraph, &env, start, end);
457 }
458
459 byte AllocateLocal(LocalType type) {
460 int result = static_cast<int>(env.total_locals);
461 env.AddLocals(type, 1);
462 byte b = static_cast<byte>(result);
463 CHECK_EQ(result, b);
464 return b;
465 }
466
Ben Murdoch097c5b22016-05-18 11:27:45 +0100467 // TODO(titzer): remove me.
468 Handle<Code> Compile() {
469 InitializeDescriptor();
470 CallDescriptor* desc = descriptor_;
471 if (kPointerSize == 4) {
472 desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc);
473 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000474 CompilationInfo info("wasm compile", this->isolate(), this->zone());
475 Handle<Code> result =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100476 Pipeline::GenerateCodeForTesting(&info, desc, this->graph());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477#ifdef ENABLE_DISASSEMBLER
478 if (!result.is_null() && FLAG_print_opt_code) {
479 OFStream os(stdout);
480 result->Disassemble("wasm code", os);
481 }
482#endif
483
484 return result;
485 }
486
Ben Murdoch097c5b22016-05-18 11:27:45 +0100487 // TODO(titzer): remove me.
488 uint32_t CompileAndAdd(uint16_t sig_index = 0) {
489 CHECK(testing_module_);
490 function()->sig_index = sig_index;
491 Handle<Code> code = Compile();
492 testing_module_->SetFunctionCode(function_index_, code);
493 return static_cast<uint32_t>(function_index_);
494 }
495
496 WasmFunction* function() {
497 if (function_) return function_;
498 return &testing_module_->module->functions->at(function_index_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000499 }
500};
501
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000502// A helper class to build graphs from Wasm bytecode, generate machine
503// code, and run that code.
504template <typename ReturnType>
505class WasmRunner {
506 public:
507 WasmRunner(MachineType p0 = MachineType::None(),
508 MachineType p1 = MachineType::None(),
509 MachineType p2 = MachineType::None(),
510 MachineType p3 = MachineType::None())
Ben Murdoch097c5b22016-05-18 11:27:45 +0100511 : compiled_(false),
512
513 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000514 GetParameterCount(p0, p1, p2, p3), storage_),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100515 compiler_(&signature_, nullptr) {
516 InitSigStorage(p0, p1, p2, p3);
517 }
518
519 WasmRunner(TestingModule* module, MachineType p0 = MachineType::None(),
520 MachineType p1 = MachineType::None(),
521 MachineType p2 = MachineType::None(),
522 MachineType p3 = MachineType::None())
523 : compiled_(false),
524 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
525 GetParameterCount(p0, p1, p2, p3), storage_),
526 compiler_(&signature_, module) {
527 DCHECK(module);
528 InitSigStorage(p0, p1, p2, p3);
529 }
530
531 void InitSigStorage(MachineType p0, MachineType p1, MachineType p2,
532 MachineType p3) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000533 int index = 0;
534 MachineType ret = MachineTypeForC<ReturnType>();
535 if (ret != MachineType::None()) {
536 storage_[index++] = WasmOpcodes::LocalTypeFor(ret);
537 }
538 if (p0 != MachineType::None())
539 storage_[index++] = WasmOpcodes::LocalTypeFor(p0);
540 if (p1 != MachineType::None())
541 storage_[index++] = WasmOpcodes::LocalTypeFor(p1);
542 if (p2 != MachineType::None())
543 storage_[index++] = WasmOpcodes::LocalTypeFor(p2);
544 if (p3 != MachineType::None())
545 storage_[index++] = WasmOpcodes::LocalTypeFor(p3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546
Ben Murdoch097c5b22016-05-18 11:27:45 +0100547 compiler_.InitializeDescriptor();
548 wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3);
549 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000550
551 FunctionEnv* env() { return &compiler_.env; }
552
Ben Murdoch097c5b22016-05-18 11:27:45 +0100553 // Builds a graph from the given Wasm code and generates the machine
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554 // code and call wrapper for that graph. This method must not be called
555 // more than once.
556 void Build(const byte* start, const byte* end) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100557 CHECK(!compiled_);
558 compiled_ = true;
559
560 // Build the TF graph within the compiler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000561 compiler_.Build(start, end);
562 // Generate code.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100563 Handle<Code> code = compiler_.Compile();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000564
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 if (compiler_.testing_module_) {
566 // Update the table of function code in the module.
567 compiler_.testing_module_->SetFunctionCode(compiler_.function_index_,
568 code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 }
570
Ben Murdoch097c5b22016-05-18 11:27:45 +0100571 wrapper_.SetInnerCode(code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000572 }
573
Ben Murdoch097c5b22016-05-18 11:27:45 +0100574 ReturnType Call() { return Call(0, 0, 0, 0); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000575
576 template <typename P0>
577 ReturnType Call(P0 p0) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100578 return Call(p0, 0, 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 }
580
581 template <typename P0, typename P1>
582 ReturnType Call(P0 p0, P1 p1) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100583 return Call(p0, p1, 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000584 }
585
586 template <typename P0, typename P1, typename P2>
587 ReturnType Call(P0 p0, P1 p1, P2 p2) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100588 return Call(p0, p1, p2, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000589 }
590
591 template <typename P0, typename P1, typename P2, typename P3>
592 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100593 CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
594 wrapper_.GetWrapperCode(), wrapper_.signature());
595 ReturnType return_value;
596 int32_t result = runner.Call<void*, void*, void*, void*, void*>(
597 &p0, &p1, &p2, &p3, &return_value);
598 CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result);
599 return return_value;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600 }
601
602 byte AllocateLocal(LocalType type) {
603 int result = static_cast<int>(env()->total_locals);
604 env()->AddLocals(type, 1);
605 byte b = static_cast<byte>(result);
606 CHECK_EQ(result, b);
607 return b;
608 }
609
Ben Murdoch097c5b22016-05-18 11:27:45 +0100610 protected:
611 Zone zone;
612 bool compiled_;
613 LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000614 FunctionSig signature_;
615 WasmFunctionCompiler compiler_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100616 WasmFunctionWrapper<ReturnType> wrapper_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000617
618 static size_t GetParameterCount(MachineType p0, MachineType p1,
619 MachineType p2, MachineType p3) {
620 if (p0 == MachineType::None()) return 0;
621 if (p1 == MachineType::None()) return 1;
622 if (p2 == MachineType::None()) return 2;
623 if (p3 == MachineType::None()) return 3;
624 return 4;
625 }
626};
627
628} // namespace
629
630#endif