blob: 1e85f46887cb7783e6c30cef057a092295edb93d [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 Murdochda12d292016-06-02 14:46:10 +010054#define BUILD(r, ...) \
55 do { \
56 byte code[] = {__VA_ARGS__}; \
57 r.Build(code, code + arraysize(code)); \
58 } while (false)
59
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060namespace {
61using namespace v8::base;
62using namespace v8::internal;
63using namespace v8::internal::compiler;
64using namespace v8::internal::wasm;
65
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000066const uint32_t kMaxGlobalsSize = 128;
67
68// A helper for module environments that adds the ability to allocate memory
Ben Murdoch097c5b22016-05-18 11:27:45 +010069// and global variables. Contains a built-in {WasmModule} and
70// {WasmModuleInstance}.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000071class TestingModule : public ModuleEnv {
72 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +010073 TestingModule() : instance_(&module_), global_offset(0) {
74 module_.shared_isolate = CcTest::InitIsolateOnce();
75 module = &module_;
76 instance = &instance_;
77 instance->module = &module_;
78 instance->globals_start = global_data;
79 instance->globals_size = kMaxGlobalsSize;
80 instance->mem_start = nullptr;
81 instance->mem_size = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082 linker = nullptr;
Ben Murdochda12d292016-06-02 14:46:10 +010083 origin = kWasmOrigin;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 memset(global_data, 0, sizeof(global_data));
85 }
86
87 ~TestingModule() {
Ben Murdoch097c5b22016-05-18 11:27:45 +010088 if (instance->mem_start) {
89 free(instance->mem_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000090 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 }
92
93 byte* AddMemory(size_t size) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010094 CHECK_NULL(instance->mem_start);
95 CHECK_EQ(0, instance->mem_size);
96 instance->mem_start = reinterpret_cast<byte*>(malloc(size));
97 CHECK(instance->mem_start);
98 memset(instance->mem_start, 0, size);
99 instance->mem_size = size;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000100 return raw_mem_start<byte>();
101 }
102
103 template <typename T>
104 T* AddMemoryElems(size_t count) {
105 AddMemory(count * sizeof(T));
106 return raw_mem_start<T>();
107 }
108
109 template <typename T>
110 T* AddGlobal(MachineType mem_type) {
111 WasmGlobal* global = AddGlobal(mem_type);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100112 return reinterpret_cast<T*>(instance->globals_start + global->offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113 }
114
115 byte AddSignature(FunctionSig* sig) {
Ben Murdochda12d292016-06-02 14:46:10 +0100116 module->signatures.push_back(sig);
117 size_t size = module->signatures.size();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118 CHECK(size < 127);
119 return static_cast<byte>(size - 1);
120 }
121
122 template <typename T>
123 T* raw_mem_start() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100124 DCHECK(instance->mem_start);
125 return reinterpret_cast<T*>(instance->mem_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000126 }
127
128 template <typename T>
129 T* raw_mem_end() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100130 DCHECK(instance->mem_start);
131 return reinterpret_cast<T*>(instance->mem_start + instance->mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 }
133
134 template <typename T>
135 T raw_mem_at(int i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100136 DCHECK(instance->mem_start);
137 return reinterpret_cast<T*>(instance->mem_start)[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 }
139
140 template <typename T>
141 T raw_val_at(int i) {
142 T val;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100143 memcpy(&val, reinterpret_cast<void*>(instance->mem_start + i), sizeof(T));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144 return val;
145 }
146
147 // Zero-initialize the memory.
148 void BlankMemory() {
149 byte* raw = raw_mem_start<byte>();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100150 memset(raw, 0, instance->mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 }
152
153 // Pseudo-randomly intialize the memory.
154 void RandomizeMemory(unsigned int seed = 88) {
155 byte* raw = raw_mem_start<byte>();
156 byte* end = raw_mem_end<byte>();
157 v8::base::RandomNumberGenerator rng;
158 rng.SetSeed(seed);
159 rng.NextBytes(raw, end - raw);
160 }
161
Ben Murdoch097c5b22016-05-18 11:27:45 +0100162 int AddFunction(FunctionSig* sig, Handle<Code> code) {
Ben Murdochda12d292016-06-02 14:46:10 +0100163 if (module->functions.size() == 0) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100164 // TODO(titzer): Reserving space here to avoid the underlying WasmFunction
165 // structs from moving.
Ben Murdochda12d292016-06-02 14:46:10 +0100166 module->functions.reserve(kMaxFunctions);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000167 }
Ben Murdochda12d292016-06-02 14:46:10 +0100168 uint32_t index = static_cast<uint32_t>(module->functions.size());
169 module->functions.push_back(
170 {sig, index, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false});
171 instance->function_code.push_back(code);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100172 DCHECK_LT(index, kMaxFunctions); // limited for testing.
173 return index;
174 }
175
176 void SetFunctionCode(uint32_t index, Handle<Code> code) {
Ben Murdochda12d292016-06-02 14:46:10 +0100177 instance->function_code[index] = code;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100178 }
179
180 void AddIndirectFunctionTable(int* functions, int table_size) {
181 Isolate* isolate = module->shared_isolate;
182 Handle<FixedArray> fixed =
183 isolate->factory()->NewFixedArray(2 * table_size);
184 instance->function_table = fixed;
Ben Murdochda12d292016-06-02 14:46:10 +0100185 DCHECK_EQ(0u, module->function_table.size());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100186 for (int i = 0; i < table_size; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +0100187 module->function_table.push_back(functions[i]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100188 }
189 }
190
191 void PopulateIndirectFunctionTable() {
192 if (instance->function_table.is_null()) return;
Ben Murdochda12d292016-06-02 14:46:10 +0100193 int table_size = static_cast<int>(module->function_table.size());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100194 for (int i = 0; i < table_size; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +0100195 int function_index = module->function_table[i];
196 WasmFunction* function = &module->functions[function_index];
Ben Murdoch097c5b22016-05-18 11:27:45 +0100197 instance->function_table->set(i, Smi::FromInt(function->sig_index));
Ben Murdochda12d292016-06-02 14:46:10 +0100198 instance->function_table->set(i + table_size,
199 *instance->function_code[function_index]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100200 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 }
202
203 private:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100204 WasmModule module_;
205 WasmModuleInstance instance_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000206 uint32_t global_offset;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100207 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208
209 WasmGlobal* AddGlobal(MachineType mem_type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000210 byte size = WasmOpcodes::MemSize(mem_type);
211 global_offset = (global_offset + size - 1) & ~(size - 1); // align
Ben Murdochda12d292016-06-02 14:46:10 +0100212 module->globals.push_back({0, 0, mem_type, global_offset, false});
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213 global_offset += size;
214 // limit number of globals.
215 CHECK_LT(global_offset, kMaxGlobalsSize);
Ben Murdochda12d292016-06-02 14:46:10 +0100216 return &module->globals.back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218};
219
Ben Murdochda12d292016-06-02 14:46:10 +0100220inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module,
221 FunctionSig* sig, const byte* start,
222 const byte* end) {
223 compiler::WasmGraphBuilder builder(zone, jsgraph, sig);
224 TreeResult result =
225 BuildTFGraph(zone->allocator(), &builder, module, sig, start, end);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000226 if (result.failed()) {
227 ptrdiff_t pc = result.error_pc - result.start;
228 ptrdiff_t pt = result.error_pt - result.start;
229 std::ostringstream str;
230 str << "Verification failed: " << result.error_code << " pc = +" << pc;
231 if (result.error_pt) str << ", pt = +" << pt;
232 str << ", msg = " << result.error_msg.get();
233 FATAL(str.str().c_str());
234 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100235 builder.Int64LoweringForTesting();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236 if (FLAG_trace_turbo_graph) {
237 OFStream os(stdout);
238 os << AsRPO(*jsgraph->graph());
239 }
240}
241
Ben Murdoch097c5b22016-05-18 11:27:45 +0100242template <typename ReturnType>
243class WasmFunctionWrapper : public HandleAndZoneScope,
244 private GraphAndBuilders {
245 public:
246 WasmFunctionWrapper()
247 : GraphAndBuilders(main_zone()),
248 inner_code_node_(nullptr),
249 signature_(nullptr) {
250 // One additional parameter for the pointer to the return value memory.
251 Signature<MachineType>::Builder sig_builder(
252 zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253
Ben Murdoch097c5b22016-05-18 11:27:45 +0100254 sig_builder.AddReturn(MachineType::Int32());
255 for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) {
256 sig_builder.AddParam(MachineType::Pointer());
257 }
258 signature_ = sig_builder.Build();
259 }
260
261 void Init(CallDescriptor* descriptor, MachineType p0 = MachineType::None(),
262 MachineType p1 = MachineType::None(),
263 MachineType p2 = MachineType::None(),
264 MachineType p3 = MachineType::None()) {
265 // Create the TF graph for the wrapper. The wrapper always takes four
266 // pointers as parameters, but may not pass the values of all pointers to
267 // the actual test function.
268
269 // Function, effect, and control.
270 Node** parameters =
271 zone()->template NewArray<Node*>(WASM_RUNNER_MAX_NUM_PARAMETERS + 3);
272 graph()->SetStart(graph()->NewNode(common()->Start(6)));
273 Node* effect = graph()->start();
274 int parameter_count = 0;
275
276 // Dummy node which gets replaced in SetInnerCode.
277 inner_code_node_ = graph()->NewNode(common()->Int32Constant(0));
278 parameters[parameter_count++] = inner_code_node_;
279
280 if (p0 != MachineType::None()) {
281 parameters[parameter_count] = graph()->NewNode(
282 machine()->Load(p0),
283 graph()->NewNode(common()->Parameter(0), graph()->start()),
284 graph()->NewNode(common()->Int32Constant(0)), effect,
285 graph()->start());
286 effect = parameters[parameter_count++];
287 }
288 if (p1 != MachineType::None()) {
289 parameters[parameter_count] = graph()->NewNode(
290 machine()->Load(p0),
291 graph()->NewNode(common()->Parameter(1), graph()->start()),
292 graph()->NewNode(common()->Int32Constant(0)), effect,
293 graph()->start());
294 effect = parameters[parameter_count++];
295 }
296 if (p2 != MachineType::None()) {
297 parameters[parameter_count] = graph()->NewNode(
298 machine()->Load(p0),
299 graph()->NewNode(common()->Parameter(2), graph()->start()),
300 graph()->NewNode(common()->Int32Constant(0)), effect,
301 graph()->start());
302 effect = parameters[parameter_count++];
303 }
304 if (p3 != MachineType::None()) {
305 parameters[parameter_count] = graph()->NewNode(
306 machine()->Load(p0),
307 graph()->NewNode(common()->Parameter(3), graph()->start()),
308 graph()->NewNode(common()->Int32Constant(0)), effect,
309 graph()->start());
310 effect = parameters[parameter_count++];
311 }
312
313 parameters[parameter_count++] = effect;
314 parameters[parameter_count++] = graph()->start();
315 Node* call = graph()->NewNode(common()->Call(descriptor), parameter_count,
316 parameters);
317
318 effect = graph()->NewNode(
319 machine()->Store(
320 StoreRepresentation(MachineTypeForC<ReturnType>().representation(),
321 WriteBarrierKind::kNoWriteBarrier)),
322 graph()->NewNode(common()->Parameter(WASM_RUNNER_MAX_NUM_PARAMETERS),
323 graph()->start()),
324 graph()->NewNode(common()->Int32Constant(0)), call, effect,
325 graph()->start());
326 Node* r = graph()->NewNode(
327 common()->Return(),
328 graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)),
329 effect, graph()->start());
330 graph()->SetEnd(graph()->NewNode(common()->End(2), r, graph()->start()));
331 }
332
333 void SetInnerCode(Handle<Code> code_handle) {
334 NodeProperties::ChangeOp(inner_code_node_,
335 common()->HeapConstant(code_handle));
336 }
337
338 Handle<Code> GetWrapperCode() {
339 if (code_.is_null()) {
340 Isolate* isolate = CcTest::InitIsolateOnce();
341
342 CallDescriptor* descriptor =
343 Linkage::GetSimplifiedCDescriptor(zone(), signature_, true);
344
345 if (kPointerSize == 4) {
346 // One additional parameter for the pointer of the return value.
347 Signature<MachineRepresentation>::Builder rep_builder(
348 zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1);
349
350 rep_builder.AddReturn(MachineRepresentation::kWord32);
351 for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) {
352 rep_builder.AddParam(MachineRepresentation::kWord32);
353 }
354 Int64Lowering r(graph(), machine(), common(), zone(),
355 rep_builder.Build());
356 r.LowerGraph();
357 }
358
359 CompilationInfo info("testing", isolate, graph()->zone());
360 code_ =
361 Pipeline::GenerateCodeForTesting(&info, descriptor, graph(), nullptr);
362 CHECK(!code_.is_null());
363#ifdef ENABLE_DISASSEMBLER
364 if (FLAG_print_opt_code) {
365 OFStream os(stdout);
366 code_->Disassemble("wasm wrapper", os);
367 }
368#endif
369 }
370
371 return code_;
372 }
373
374 Signature<MachineType>* signature() const { return signature_; }
375
376 private:
377 Node* inner_code_node_;
378 Handle<Code> code_;
379 Signature<MachineType>* signature_;
380};
381
382// A helper for compiling WASM functions for testing. This class can create a
383// standalone function if {module} is NULL or a function within a
384// {TestingModule}. It contains the internal state for compilation (i.e.
385// TurboFan graph) and, later, interpretation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000386class WasmFunctionCompiler : public HandleAndZoneScope,
387 private GraphAndBuilders {
388 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100389 explicit WasmFunctionCompiler(FunctionSig* sig, TestingModule* module)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000390 : GraphAndBuilders(main_zone()),
391 jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
392 nullptr, this->machine()),
Ben Murdochda12d292016-06-02 14:46:10 +0100393 sig(sig),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100394 descriptor_(nullptr),
395 testing_module_(module) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100396 if (module) {
397 // Get a new function from the testing module.
398 function_ = nullptr;
399 function_index_ = module->AddFunction(sig, Handle<Code>::null());
400 } else {
401 // Create our own function.
402 function_ = new WasmFunction();
403 function_->sig = sig;
404 function_index_ = 0;
405 }
406 }
407
408 ~WasmFunctionCompiler() {
409 if (function_) delete function_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410 }
411
412 JSGraph jsgraph;
Ben Murdochda12d292016-06-02 14:46:10 +0100413 FunctionSig* sig;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000414 // The call descriptor is initialized when the function is compiled.
415 CallDescriptor* descriptor_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100416 TestingModule* testing_module_;
417 WasmFunction* function_;
418 int function_index_;
Ben Murdochda12d292016-06-02 14:46:10 +0100419 LocalDeclEncoder local_decls;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000420
421 Isolate* isolate() { return main_isolate(); }
422 Graph* graph() const { return main_graph_; }
423 Zone* zone() const { return graph()->zone(); }
424 CommonOperatorBuilder* common() { return &main_common_; }
425 MachineOperatorBuilder* machine() { return &main_machine_; }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100426 void InitializeDescriptor() {
427 if (descriptor_ == nullptr) {
Ben Murdochda12d292016-06-02 14:46:10 +0100428 descriptor_ = testing_module_->GetWasmCallDescriptor(main_zone(), sig);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100429 }
430 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000431 CallDescriptor* descriptor() { return descriptor_; }
432
433 void Build(const byte* start, const byte* end) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100434 // Build the TurboFan graph.
Ben Murdochda12d292016-06-02 14:46:10 +0100435 local_decls.Prepend(&start, &end);
436 TestBuildingGraph(main_zone(), &jsgraph, testing_module_, sig, start, end);
437 delete[] start;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 }
439
440 byte AllocateLocal(LocalType type) {
Ben Murdochda12d292016-06-02 14:46:10 +0100441 uint32_t index = local_decls.AddLocals(1, type, sig);
442 byte result = static_cast<byte>(index);
443 DCHECK_EQ(index, result);
444 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445 }
446
Ben Murdoch097c5b22016-05-18 11:27:45 +0100447 Handle<Code> Compile() {
448 InitializeDescriptor();
449 CallDescriptor* desc = descriptor_;
450 if (kPointerSize == 4) {
451 desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc);
452 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000453 CompilationInfo info("wasm compile", this->isolate(), this->zone());
454 Handle<Code> result =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100455 Pipeline::GenerateCodeForTesting(&info, desc, this->graph());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456#ifdef ENABLE_DISASSEMBLER
457 if (!result.is_null() && FLAG_print_opt_code) {
458 OFStream os(stdout);
459 result->Disassemble("wasm code", os);
460 }
461#endif
462
463 return result;
464 }
465
Ben Murdoch097c5b22016-05-18 11:27:45 +0100466 uint32_t CompileAndAdd(uint16_t sig_index = 0) {
467 CHECK(testing_module_);
468 function()->sig_index = sig_index;
469 Handle<Code> code = Compile();
470 testing_module_->SetFunctionCode(function_index_, code);
471 return static_cast<uint32_t>(function_index_);
472 }
473
474 WasmFunction* function() {
475 if (function_) return function_;
Ben Murdochda12d292016-06-02 14:46:10 +0100476 return &testing_module_->module->functions[function_index_];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 }
478};
479
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480// A helper class to build graphs from Wasm bytecode, generate machine
481// code, and run that code.
482template <typename ReturnType>
483class WasmRunner {
484 public:
485 WasmRunner(MachineType p0 = MachineType::None(),
486 MachineType p1 = MachineType::None(),
487 MachineType p2 = MachineType::None(),
488 MachineType p3 = MachineType::None())
Ben Murdochda12d292016-06-02 14:46:10 +0100489 : zone(&allocator_),
490 compiled_(false),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100491 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492 GetParameterCount(p0, p1, p2, p3), storage_),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100493 compiler_(&signature_, nullptr) {
494 InitSigStorage(p0, p1, p2, p3);
495 }
496
497 WasmRunner(TestingModule* module, MachineType p0 = MachineType::None(),
498 MachineType p1 = MachineType::None(),
499 MachineType p2 = MachineType::None(),
500 MachineType p3 = MachineType::None())
Ben Murdochda12d292016-06-02 14:46:10 +0100501 : zone(&allocator_),
502 compiled_(false),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100503 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
504 GetParameterCount(p0, p1, p2, p3), storage_),
505 compiler_(&signature_, module) {
506 DCHECK(module);
507 InitSigStorage(p0, p1, p2, p3);
508 }
509
510 void InitSigStorage(MachineType p0, MachineType p1, MachineType p2,
511 MachineType p3) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512 int index = 0;
513 MachineType ret = MachineTypeForC<ReturnType>();
514 if (ret != MachineType::None()) {
515 storage_[index++] = WasmOpcodes::LocalTypeFor(ret);
516 }
517 if (p0 != MachineType::None())
518 storage_[index++] = WasmOpcodes::LocalTypeFor(p0);
519 if (p1 != MachineType::None())
520 storage_[index++] = WasmOpcodes::LocalTypeFor(p1);
521 if (p2 != MachineType::None())
522 storage_[index++] = WasmOpcodes::LocalTypeFor(p2);
523 if (p3 != MachineType::None())
524 storage_[index++] = WasmOpcodes::LocalTypeFor(p3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000525
Ben Murdoch097c5b22016-05-18 11:27:45 +0100526 compiler_.InitializeDescriptor();
527 wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3);
528 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000529
Ben Murdoch097c5b22016-05-18 11:27:45 +0100530 // Builds a graph from the given Wasm code and generates the machine
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000531 // code and call wrapper for that graph. This method must not be called
532 // more than once.
533 void Build(const byte* start, const byte* end) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100534 CHECK(!compiled_);
535 compiled_ = true;
536
537 // Build the TF graph within the compiler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 compiler_.Build(start, end);
539 // Generate code.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100540 Handle<Code> code = compiler_.Compile();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000541
Ben Murdoch097c5b22016-05-18 11:27:45 +0100542 if (compiler_.testing_module_) {
543 // Update the table of function code in the module.
544 compiler_.testing_module_->SetFunctionCode(compiler_.function_index_,
545 code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 }
547
Ben Murdoch097c5b22016-05-18 11:27:45 +0100548 wrapper_.SetInnerCode(code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000549 }
550
Ben Murdoch097c5b22016-05-18 11:27:45 +0100551 ReturnType Call() { return Call(0, 0, 0, 0); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552
553 template <typename P0>
554 ReturnType Call(P0 p0) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100555 return Call(p0, 0, 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000556 }
557
558 template <typename P0, typename P1>
559 ReturnType Call(P0 p0, P1 p1) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100560 return Call(p0, p1, 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000561 }
562
563 template <typename P0, typename P1, typename P2>
564 ReturnType Call(P0 p0, P1 p1, P2 p2) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 return Call(p0, p1, p2, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566 }
567
568 template <typename P0, typename P1, typename P2, typename P3>
569 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100570 CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
571 wrapper_.GetWrapperCode(), wrapper_.signature());
572 ReturnType return_value;
573 int32_t result = runner.Call<void*, void*, void*, void*, void*>(
574 &p0, &p1, &p2, &p3, &return_value);
575 CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result);
576 return return_value;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577 }
578
Ben Murdochda12d292016-06-02 14:46:10 +0100579 byte AllocateLocal(LocalType type) { return compiler_.AllocateLocal(type); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000580
Ben Murdoch097c5b22016-05-18 11:27:45 +0100581 protected:
Ben Murdochda12d292016-06-02 14:46:10 +0100582 v8::base::AccountingAllocator allocator_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100583 Zone zone;
584 bool compiled_;
585 LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000586 FunctionSig signature_;
587 WasmFunctionCompiler compiler_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100588 WasmFunctionWrapper<ReturnType> wrapper_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000589
590 static size_t GetParameterCount(MachineType p0, MachineType p1,
591 MachineType p2, MachineType p3) {
592 if (p0 == MachineType::None()) return 0;
593 if (p1 == MachineType::None()) return 1;
594 if (p2 == MachineType::None()) return 2;
595 if (p3 == MachineType::None()) return 3;
596 return 4;
597 }
598};
599
600} // namespace
601
602#endif