blob: 1f758bb8535dcf5ec316210a4a2b70829aa35aa9 [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
Ben Murdoch61f157c2016-09-16 13:49:30 +010012#include "src/base/accounting-allocator.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/base/utils/random-number-generator.h"
14
15#include "src/compiler/graph-visualizer.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010016#include "src/compiler/int64-lowering.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017#include "src/compiler/js-graph.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010018#include "src/compiler/node.h"
19#include "src/compiler/pipeline.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020#include "src/compiler/wasm-compiler.h"
Ben Murdochc5610432016-08-08 18:44:38 +010021#include "src/compiler/zone-pool.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022
23#include "src/wasm/ast-decoder.h"
Ben Murdoch61f157c2016-09-16 13:49:30 +010024#include "src/wasm/wasm-interpreter.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025#include "src/wasm/wasm-js.h"
Ben Murdochc5610432016-08-08 18:44:38 +010026#include "src/wasm/wasm-macro-gen.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000027#include "src/wasm/wasm-module.h"
28#include "src/wasm/wasm-opcodes.h"
29
Ben Murdoch097c5b22016-05-18 11:27:45 +010030#include "src/zone.h"
31
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000032#include "test/cctest/cctest.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010033#include "test/cctest/compiler/call-tester.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034#include "test/cctest/compiler/graph-builder-tester.h"
35
Ben Murdoch097c5b22016-05-18 11:27:45 +010036static const uint32_t kMaxFunctions = 10;
37
Ben Murdoch61f157c2016-09-16 13:49:30 +010038enum WasmExecutionMode { kExecuteInterpreted, kExecuteCompiled };
39
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000040// TODO(titzer): check traps more robustly in tests.
41// Currently, in tests, we just return 0xdeadbeef from the function in which
42// the trap occurs if the runtime context is not available to throw a JavaScript
43// exception.
44#define CHECK_TRAP32(x) \
45 CHECK_EQ(0xdeadbeef, (bit_cast<uint32_t>(x)) & 0xFFFFFFFF)
46#define CHECK_TRAP64(x) \
47 CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF)
48#define CHECK_TRAP(x) CHECK_TRAP32(x)
49
Ben Murdoch097c5b22016-05-18 11:27:45 +010050#define WASM_RUNNER_MAX_NUM_PARAMETERS 4
51#define WASM_WRAPPER_RETURN_VALUE 8754
52
Ben Murdochda12d292016-06-02 14:46:10 +010053#define BUILD(r, ...) \
54 do { \
55 byte code[] = {__VA_ARGS__}; \
56 r.Build(code, code + arraysize(code)); \
57 } while (false)
58
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059namespace {
60using namespace v8::base;
61using namespace v8::internal;
62using namespace v8::internal::compiler;
63using namespace v8::internal::wasm;
64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065const uint32_t kMaxGlobalsSize = 128;
66
67// A helper for module environments that adds the ability to allocate memory
Ben Murdoch097c5b22016-05-18 11:27:45 +010068// and global variables. Contains a built-in {WasmModule} and
69// {WasmModuleInstance}.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070class TestingModule : public ModuleEnv {
71 public:
Ben Murdoch61f157c2016-09-16 13:49:30 +010072 explicit TestingModule(WasmExecutionMode mode = kExecuteCompiled)
73 : execution_mode_(mode),
74 instance_(&module_),
75 isolate_(CcTest::InitIsolateOnce()),
76 global_offset(0),
77 interpreter_(mode == kExecuteInterpreted
78 ? new WasmInterpreter(&instance_, &allocator_)
79 : nullptr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010080 module = &module_;
81 instance = &instance_;
82 instance->module = &module_;
83 instance->globals_start = global_data;
Ben Murdoch61f157c2016-09-16 13:49:30 +010084 module_.globals_size = kMaxGlobalsSize;
Ben Murdoch097c5b22016-05-18 11:27:45 +010085 instance->mem_start = nullptr;
86 instance->mem_size = 0;
Ben Murdochda12d292016-06-02 14:46:10 +010087 origin = kWasmOrigin;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 memset(global_data, 0, sizeof(global_data));
89 }
90
91 ~TestingModule() {
Ben Murdoch097c5b22016-05-18 11:27:45 +010092 if (instance->mem_start) {
93 free(instance->mem_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094 }
Ben Murdoch61f157c2016-09-16 13:49:30 +010095 if (interpreter_) delete interpreter_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 }
97
Ben Murdoch61f157c2016-09-16 13:49:30 +010098 byte* AddMemory(uint32_t size) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010099 CHECK_NULL(instance->mem_start);
100 CHECK_EQ(0, instance->mem_size);
101 instance->mem_start = reinterpret_cast<byte*>(malloc(size));
102 CHECK(instance->mem_start);
103 memset(instance->mem_start, 0, size);
104 instance->mem_size = size;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 return raw_mem_start<byte>();
106 }
107
108 template <typename T>
Ben Murdoch61f157c2016-09-16 13:49:30 +0100109 T* AddMemoryElems(uint32_t count) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 AddMemory(count * sizeof(T));
111 return raw_mem_start<T>();
112 }
113
114 template <typename T>
115 T* AddGlobal(MachineType mem_type) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100116 const WasmGlobal* global = AddGlobal(mem_type);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100117 return reinterpret_cast<T*>(instance->globals_start + global->offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118 }
119
120 byte AddSignature(FunctionSig* sig) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100121 module_.signatures.push_back(sig);
Ben Murdochda12d292016-06-02 14:46:10 +0100122 size_t size = module->signatures.size();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123 CHECK(size < 127);
124 return static_cast<byte>(size - 1);
125 }
126
127 template <typename T>
128 T* raw_mem_start() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100129 DCHECK(instance->mem_start);
130 return reinterpret_cast<T*>(instance->mem_start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000131 }
132
133 template <typename T>
134 T* raw_mem_end() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100135 DCHECK(instance->mem_start);
136 return reinterpret_cast<T*>(instance->mem_start + instance->mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 }
138
139 template <typename T>
140 T raw_mem_at(int i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100141 DCHECK(instance->mem_start);
142 return reinterpret_cast<T*>(instance->mem_start)[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 }
144
145 template <typename T>
146 T raw_val_at(int i) {
147 T val;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100148 memcpy(&val, reinterpret_cast<void*>(instance->mem_start + i), sizeof(T));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 return val;
150 }
151
152 // Zero-initialize the memory.
153 void BlankMemory() {
154 byte* raw = raw_mem_start<byte>();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100155 memset(raw, 0, instance->mem_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156 }
157
158 // Pseudo-randomly intialize the memory.
159 void RandomizeMemory(unsigned int seed = 88) {
160 byte* raw = raw_mem_start<byte>();
161 byte* end = raw_mem_end<byte>();
162 v8::base::RandomNumberGenerator rng;
163 rng.SetSeed(seed);
164 rng.NextBytes(raw, end - raw);
165 }
166
Ben Murdochc5610432016-08-08 18:44:38 +0100167 uint32_t AddFunction(FunctionSig* sig, Handle<Code> code) {
Ben Murdochda12d292016-06-02 14:46:10 +0100168 if (module->functions.size() == 0) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100169 // TODO(titzer): Reserving space here to avoid the underlying WasmFunction
170 // structs from moving.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100171 module_.functions.reserve(kMaxFunctions);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 }
Ben Murdochda12d292016-06-02 14:46:10 +0100173 uint32_t index = static_cast<uint32_t>(module->functions.size());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100174 module_.functions.push_back({sig, index, 0, 0, 0, 0, 0});
Ben Murdochda12d292016-06-02 14:46:10 +0100175 instance->function_code.push_back(code);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100176 if (interpreter_) {
177 const WasmFunction* function = &module->functions.back();
178 int interpreter_index = interpreter_->AddFunctionForTesting(function);
179 CHECK_EQ(index, static_cast<uint32_t>(interpreter_index));
180 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100181 DCHECK_LT(index, kMaxFunctions); // limited for testing.
182 return index;
183 }
184
Ben Murdochc5610432016-08-08 18:44:38 +0100185 uint32_t AddJsFunction(FunctionSig* sig, const char* source) {
186 Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
187 *v8::Local<v8::Function>::Cast(CompileRun(source))));
188 uint32_t index = AddFunction(sig, Handle<Code>::null());
Ben Murdochc5610432016-08-08 18:44:38 +0100189 WasmName module_name = ArrayVector("test");
190 WasmName function_name;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100191 Handle<Code> code = CompileWasmToJSWrapper(isolate_, jsfunc, sig,
Ben Murdochc5610432016-08-08 18:44:38 +0100192 module_name, function_name);
193 instance->function_code[index] = code;
194 return index;
195 }
196
197 Handle<JSFunction> WrapCode(uint32_t index) {
Ben Murdochc5610432016-08-08 18:44:38 +0100198 // Wrap the code so it can be called as a JS function.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100199 Handle<String> name = isolate_->factory()->NewStringFromStaticChars("main");
200 Handle<JSObject> module_object = Handle<JSObject>(0, isolate_);
Ben Murdochc5610432016-08-08 18:44:38 +0100201 Handle<Code> code = instance->function_code[index];
Ben Murdoch61f157c2016-09-16 13:49:30 +0100202 WasmJs::InstallWasmFunctionMap(isolate_, isolate_->native_context());
203 return compiler::CompileJSToWasmWrapper(isolate_, this, name, code,
Ben Murdochc5610432016-08-08 18:44:38 +0100204 module_object, index);
205 }
206
Ben Murdoch097c5b22016-05-18 11:27:45 +0100207 void SetFunctionCode(uint32_t index, Handle<Code> code) {
Ben Murdochda12d292016-06-02 14:46:10 +0100208 instance->function_code[index] = code;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100209 }
210
211 void AddIndirectFunctionTable(int* functions, int table_size) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100212 Handle<FixedArray> fixed =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100213 isolate_->factory()->NewFixedArray(2 * table_size);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100214 instance->function_table = fixed;
Ben Murdochda12d292016-06-02 14:46:10 +0100215 DCHECK_EQ(0u, module->function_table.size());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100216 for (int i = 0; i < table_size; i++) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100217 module_.function_table.push_back(functions[i]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100218 }
219 }
220
221 void PopulateIndirectFunctionTable() {
222 if (instance->function_table.is_null()) return;
Ben Murdochda12d292016-06-02 14:46:10 +0100223 int table_size = static_cast<int>(module->function_table.size());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100224 for (int i = 0; i < table_size; i++) {
Ben Murdochda12d292016-06-02 14:46:10 +0100225 int function_index = module->function_table[i];
Ben Murdoch61f157c2016-09-16 13:49:30 +0100226 const WasmFunction* function = &module->functions[function_index];
Ben Murdoch097c5b22016-05-18 11:27:45 +0100227 instance->function_table->set(i, Smi::FromInt(function->sig_index));
Ben Murdochda12d292016-06-02 14:46:10 +0100228 instance->function_table->set(i + table_size,
229 *instance->function_code[function_index]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100230 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100232 WasmFunction* GetFunctionAt(int index) { return &module_.functions[index]; }
233
234 WasmInterpreter* interpreter() { return interpreter_; }
235 WasmExecutionMode execution_mode() { return execution_mode_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236
237 private:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100238 WasmExecutionMode execution_mode_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100239 WasmModule module_;
240 WasmModuleInstance instance_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100241 Isolate* isolate_;
242 v8::base::AccountingAllocator allocator_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000243 uint32_t global_offset;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100244 V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100245 WasmInterpreter* interpreter_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246
Ben Murdoch61f157c2016-09-16 13:49:30 +0100247 const WasmGlobal* AddGlobal(MachineType mem_type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248 byte size = WasmOpcodes::MemSize(mem_type);
249 global_offset = (global_offset + size - 1) & ~(size - 1); // align
Ben Murdoch61f157c2016-09-16 13:49:30 +0100250 module_.globals.push_back({0, 0, mem_type, global_offset, false});
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251 global_offset += size;
252 // limit number of globals.
253 CHECK_LT(global_offset, kMaxGlobalsSize);
Ben Murdochda12d292016-06-02 14:46:10 +0100254 return &module->globals.back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256};
257
Ben Murdochda12d292016-06-02 14:46:10 +0100258inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module,
Ben Murdochc5610432016-08-08 18:44:38 +0100259 FunctionSig* sig,
260 SourcePositionTable* source_position_table,
261 const byte* start, const byte* end) {
262 compiler::WasmGraphBuilder builder(zone, jsgraph, sig, source_position_table);
Ben Murdochda12d292016-06-02 14:46:10 +0100263 TreeResult result =
264 BuildTFGraph(zone->allocator(), &builder, module, sig, start, end);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265 if (result.failed()) {
266 ptrdiff_t pc = result.error_pc - result.start;
267 ptrdiff_t pt = result.error_pt - result.start;
268 std::ostringstream str;
269 str << "Verification failed: " << result.error_code << " pc = +" << pc;
270 if (result.error_pt) str << ", pt = +" << pt;
271 str << ", msg = " << result.error_msg.get();
272 FATAL(str.str().c_str());
273 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100274 builder.Int64LoweringForTesting();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000275 if (FLAG_trace_turbo_graph) {
276 OFStream os(stdout);
277 os << AsRPO(*jsgraph->graph());
278 }
279}
280
Ben Murdoch097c5b22016-05-18 11:27:45 +0100281template <typename ReturnType>
282class WasmFunctionWrapper : public HandleAndZoneScope,
283 private GraphAndBuilders {
284 public:
285 WasmFunctionWrapper()
286 : GraphAndBuilders(main_zone()),
287 inner_code_node_(nullptr),
288 signature_(nullptr) {
289 // One additional parameter for the pointer to the return value memory.
290 Signature<MachineType>::Builder sig_builder(
291 zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292
Ben Murdoch097c5b22016-05-18 11:27:45 +0100293 sig_builder.AddReturn(MachineType::Int32());
294 for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) {
295 sig_builder.AddParam(MachineType::Pointer());
296 }
297 signature_ = sig_builder.Build();
298 }
299
300 void Init(CallDescriptor* descriptor, MachineType p0 = MachineType::None(),
301 MachineType p1 = MachineType::None(),
302 MachineType p2 = MachineType::None(),
303 MachineType p3 = MachineType::None()) {
304 // Create the TF graph for the wrapper. The wrapper always takes four
305 // pointers as parameters, but may not pass the values of all pointers to
306 // the actual test function.
307
308 // Function, effect, and control.
309 Node** parameters =
310 zone()->template NewArray<Node*>(WASM_RUNNER_MAX_NUM_PARAMETERS + 3);
311 graph()->SetStart(graph()->NewNode(common()->Start(6)));
312 Node* effect = graph()->start();
313 int parameter_count = 0;
314
315 // Dummy node which gets replaced in SetInnerCode.
316 inner_code_node_ = graph()->NewNode(common()->Int32Constant(0));
317 parameters[parameter_count++] = inner_code_node_;
318
319 if (p0 != MachineType::None()) {
320 parameters[parameter_count] = graph()->NewNode(
321 machine()->Load(p0),
322 graph()->NewNode(common()->Parameter(0), graph()->start()),
323 graph()->NewNode(common()->Int32Constant(0)), effect,
324 graph()->start());
325 effect = parameters[parameter_count++];
326 }
327 if (p1 != MachineType::None()) {
328 parameters[parameter_count] = graph()->NewNode(
329 machine()->Load(p0),
330 graph()->NewNode(common()->Parameter(1), graph()->start()),
331 graph()->NewNode(common()->Int32Constant(0)), effect,
332 graph()->start());
333 effect = parameters[parameter_count++];
334 }
335 if (p2 != MachineType::None()) {
336 parameters[parameter_count] = graph()->NewNode(
337 machine()->Load(p0),
338 graph()->NewNode(common()->Parameter(2), graph()->start()),
339 graph()->NewNode(common()->Int32Constant(0)), effect,
340 graph()->start());
341 effect = parameters[parameter_count++];
342 }
343 if (p3 != MachineType::None()) {
344 parameters[parameter_count] = graph()->NewNode(
345 machine()->Load(p0),
346 graph()->NewNode(common()->Parameter(3), graph()->start()),
347 graph()->NewNode(common()->Int32Constant(0)), effect,
348 graph()->start());
349 effect = parameters[parameter_count++];
350 }
351
352 parameters[parameter_count++] = effect;
353 parameters[parameter_count++] = graph()->start();
354 Node* call = graph()->NewNode(common()->Call(descriptor), parameter_count,
355 parameters);
356
357 effect = graph()->NewNode(
358 machine()->Store(
359 StoreRepresentation(MachineTypeForC<ReturnType>().representation(),
360 WriteBarrierKind::kNoWriteBarrier)),
361 graph()->NewNode(common()->Parameter(WASM_RUNNER_MAX_NUM_PARAMETERS),
362 graph()->start()),
363 graph()->NewNode(common()->Int32Constant(0)), call, effect,
364 graph()->start());
365 Node* r = graph()->NewNode(
366 common()->Return(),
367 graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)),
368 effect, graph()->start());
369 graph()->SetEnd(graph()->NewNode(common()->End(2), r, graph()->start()));
370 }
371
372 void SetInnerCode(Handle<Code> code_handle) {
373 NodeProperties::ChangeOp(inner_code_node_,
374 common()->HeapConstant(code_handle));
375 }
376
377 Handle<Code> GetWrapperCode() {
378 if (code_.is_null()) {
379 Isolate* isolate = CcTest::InitIsolateOnce();
380
381 CallDescriptor* descriptor =
382 Linkage::GetSimplifiedCDescriptor(zone(), signature_, true);
383
384 if (kPointerSize == 4) {
385 // One additional parameter for the pointer of the return value.
386 Signature<MachineRepresentation>::Builder rep_builder(
387 zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1);
388
389 rep_builder.AddReturn(MachineRepresentation::kWord32);
390 for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) {
391 rep_builder.AddParam(MachineRepresentation::kWord32);
392 }
393 Int64Lowering r(graph(), machine(), common(), zone(),
394 rep_builder.Build());
395 r.LowerGraph();
396 }
397
Ben Murdochc5610432016-08-08 18:44:38 +0100398 CompilationInfo info(ArrayVector("testing"), isolate, graph()->zone());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100399 code_ =
400 Pipeline::GenerateCodeForTesting(&info, descriptor, graph(), nullptr);
401 CHECK(!code_.is_null());
402#ifdef ENABLE_DISASSEMBLER
403 if (FLAG_print_opt_code) {
404 OFStream os(stdout);
405 code_->Disassemble("wasm wrapper", os);
406 }
407#endif
408 }
409
410 return code_;
411 }
412
413 Signature<MachineType>* signature() const { return signature_; }
414
415 private:
416 Node* inner_code_node_;
417 Handle<Code> code_;
418 Signature<MachineType>* signature_;
419};
420
421// A helper for compiling WASM functions for testing. This class can create a
422// standalone function if {module} is NULL or a function within a
423// {TestingModule}. It contains the internal state for compilation (i.e.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100424// TurboFan graph) and interpretation (by adding to the interpreter manually).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000425class WasmFunctionCompiler : public HandleAndZoneScope,
426 private GraphAndBuilders {
427 public:
Ben Murdochc5610432016-08-08 18:44:38 +0100428 explicit WasmFunctionCompiler(
Ben Murdoch61f157c2016-09-16 13:49:30 +0100429 FunctionSig* sig, WasmExecutionMode mode,
430 Vector<const char> debug_name = ArrayVector("<WASM UNNAMED>"))
431 : GraphAndBuilders(main_zone()),
432 execution_mode_(mode),
433 jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
434 nullptr, this->machine()),
435 sig(sig),
436 descriptor_(nullptr),
437 testing_module_(nullptr),
438 debug_name_(debug_name),
439 local_decls(main_zone(), sig),
440 source_position_table_(this->graph()),
441 interpreter_(nullptr) {
442 // Create our own function.
443 function_ = new WasmFunction();
444 function_->sig = sig;
445 function_->func_index = 0;
446 function_->sig_index = 0;
447 if (mode == kExecuteInterpreted) {
448 interpreter_ = new WasmInterpreter(nullptr, zone()->allocator());
449 int index = interpreter_->AddFunctionForTesting(function_);
450 CHECK_EQ(0, index);
451 }
452 }
453
454 explicit WasmFunctionCompiler(
Ben Murdochc5610432016-08-08 18:44:38 +0100455 FunctionSig* sig, TestingModule* module,
456 Vector<const char> debug_name = ArrayVector("<WASM UNNAMED>"))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000457 : GraphAndBuilders(main_zone()),
Ben Murdoch61f157c2016-09-16 13:49:30 +0100458 execution_mode_(module->execution_mode()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
460 nullptr, this->machine()),
Ben Murdochda12d292016-06-02 14:46:10 +0100461 sig(sig),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100462 descriptor_(nullptr),
Ben Murdochc5610432016-08-08 18:44:38 +0100463 testing_module_(module),
464 debug_name_(debug_name),
465 local_decls(main_zone(), sig),
Ben Murdoch61f157c2016-09-16 13:49:30 +0100466 source_position_table_(this->graph()),
467 interpreter_(module->interpreter()) {
468 // Get a new function from the testing module.
469 int index = module->AddFunction(sig, Handle<Code>::null());
470 function_ = testing_module_->GetFunctionAt(index);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100471 }
472
473 ~WasmFunctionCompiler() {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100474 if (testing_module_) return; // testing module owns the below things.
475 delete function_;
476 if (interpreter_) delete interpreter_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 }
478
Ben Murdoch61f157c2016-09-16 13:49:30 +0100479 WasmExecutionMode execution_mode_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 JSGraph jsgraph;
Ben Murdochda12d292016-06-02 14:46:10 +0100481 FunctionSig* sig;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482 // The call descriptor is initialized when the function is compiled.
483 CallDescriptor* descriptor_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100484 TestingModule* testing_module_;
Ben Murdochc5610432016-08-08 18:44:38 +0100485 Vector<const char> debug_name_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100486 WasmFunction* function_;
Ben Murdochda12d292016-06-02 14:46:10 +0100487 LocalDeclEncoder local_decls;
Ben Murdochc5610432016-08-08 18:44:38 +0100488 SourcePositionTable source_position_table_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100489 WasmInterpreter* interpreter_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490
491 Isolate* isolate() { return main_isolate(); }
492 Graph* graph() const { return main_graph_; }
493 Zone* zone() const { return graph()->zone(); }
494 CommonOperatorBuilder* common() { return &main_common_; }
495 MachineOperatorBuilder* machine() { return &main_machine_; }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100496 void InitializeDescriptor() {
497 if (descriptor_ == nullptr) {
Ben Murdochda12d292016-06-02 14:46:10 +0100498 descriptor_ = testing_module_->GetWasmCallDescriptor(main_zone(), sig);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100499 }
500 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000501 CallDescriptor* descriptor() { return descriptor_; }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100502 uint32_t function_index() { return function_->func_index; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000503
504 void Build(const byte* start, const byte* end) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100505 // Build the TurboFan graph.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100506 local_decls.Prepend(main_zone(), &start, &end);
Ben Murdochc5610432016-08-08 18:44:38 +0100507 TestBuildingGraph(main_zone(), &jsgraph, testing_module_, sig,
508 &source_position_table_, start, end);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100509 if (interpreter_) {
510 // Add the code to the interpreter.
511 CHECK(interpreter_->SetFunctionCodeForTesting(function_, start, end));
512 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000513 }
514
515 byte AllocateLocal(LocalType type) {
Ben Murdochc5610432016-08-08 18:44:38 +0100516 uint32_t index = local_decls.AddLocals(1, type);
Ben Murdochda12d292016-06-02 14:46:10 +0100517 byte result = static_cast<byte>(index);
518 DCHECK_EQ(index, result);
519 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000520 }
521
Ben Murdoch097c5b22016-05-18 11:27:45 +0100522 Handle<Code> Compile() {
523 InitializeDescriptor();
524 CallDescriptor* desc = descriptor_;
525 if (kPointerSize == 4) {
526 desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc);
527 }
Ben Murdochc5610432016-08-08 18:44:38 +0100528 CompilationInfo info(debug_name_, this->isolate(), this->zone(),
529 Code::ComputeFlags(Code::WASM_FUNCTION));
530 v8::base::SmartPointer<CompilationJob> job(Pipeline::NewWasmCompilationJob(
531 &info, graph(), desc, &source_position_table_));
532 if (job->OptimizeGraph() != CompilationJob::SUCCEEDED ||
533 job->GenerateCode() != CompilationJob::SUCCEEDED)
534 return Handle<Code>::null();
535
536 Handle<Code> code = info.code();
537
Ben Murdoch61f157c2016-09-16 13:49:30 +0100538 // Length is always 2, since usually <wasm_obj, func_index> is stored in
539 // the deopt data. Here, we only store the function index.
Ben Murdochc5610432016-08-08 18:44:38 +0100540 DCHECK(code->deoptimization_data() == nullptr ||
541 code->deoptimization_data()->length() == 0);
542 Handle<FixedArray> deopt_data =
543 isolate()->factory()->NewFixedArray(2, TENURED);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100544 deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index())));
Ben Murdochc5610432016-08-08 18:44:38 +0100545 deopt_data->set_length(2);
546 code->set_deoptimization_data(*deopt_data);
547
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000548#ifdef ENABLE_DISASSEMBLER
Ben Murdochc5610432016-08-08 18:44:38 +0100549 if (FLAG_print_opt_code) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000550 OFStream os(stdout);
Ben Murdochc5610432016-08-08 18:44:38 +0100551 code->Disassemble("wasm code", os);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552 }
553#endif
554
Ben Murdochc5610432016-08-08 18:44:38 +0100555 return code;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000556 }
557
Ben Murdoch097c5b22016-05-18 11:27:45 +0100558 uint32_t CompileAndAdd(uint16_t sig_index = 0) {
559 CHECK(testing_module_);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100560 function_->sig_index = sig_index;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100561 Handle<Code> code = Compile();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100562 testing_module_->SetFunctionCode(function_index(), code);
563 return function_index();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000564 }
Ben Murdochc5610432016-08-08 18:44:38 +0100565
566 // Set the context, such that e.g. runtime functions can be called.
567 void SetModuleContext() {
568 if (!testing_module_->instance->context.is_null()) {
569 CHECK(testing_module_->instance->context.is_identical_to(
570 main_isolate()->native_context()));
571 return;
572 }
573 testing_module_->instance->context = main_isolate()->native_context();
574 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000575};
576
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577// A helper class to build graphs from Wasm bytecode, generate machine
578// code, and run that code.
579template <typename ReturnType>
580class WasmRunner {
581 public:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100582 WasmRunner(WasmExecutionMode execution_mode,
583 MachineType p0 = MachineType::None(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000584 MachineType p1 = MachineType::None(),
585 MachineType p2 = MachineType::None(),
586 MachineType p3 = MachineType::None())
Ben Murdochda12d292016-06-02 14:46:10 +0100587 : zone(&allocator_),
588 compiled_(false),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100589 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000590 GetParameterCount(p0, p1, p2, p3), storage_),
Ben Murdoch61f157c2016-09-16 13:49:30 +0100591 compiler_(&signature_, execution_mode) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100592 InitSigStorage(p0, p1, p2, p3);
593 }
594
595 WasmRunner(TestingModule* module, MachineType p0 = MachineType::None(),
596 MachineType p1 = MachineType::None(),
597 MachineType p2 = MachineType::None(),
598 MachineType p3 = MachineType::None())
Ben Murdochda12d292016-06-02 14:46:10 +0100599 : zone(&allocator_),
600 compiled_(false),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100601 signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
602 GetParameterCount(p0, p1, p2, p3), storage_),
603 compiler_(&signature_, module) {
604 DCHECK(module);
605 InitSigStorage(p0, p1, p2, p3);
606 }
607
608 void InitSigStorage(MachineType p0, MachineType p1, MachineType p2,
609 MachineType p3) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000610 int index = 0;
611 MachineType ret = MachineTypeForC<ReturnType>();
612 if (ret != MachineType::None()) {
613 storage_[index++] = WasmOpcodes::LocalTypeFor(ret);
614 }
615 if (p0 != MachineType::None())
616 storage_[index++] = WasmOpcodes::LocalTypeFor(p0);
617 if (p1 != MachineType::None())
618 storage_[index++] = WasmOpcodes::LocalTypeFor(p1);
619 if (p2 != MachineType::None())
620 storage_[index++] = WasmOpcodes::LocalTypeFor(p2);
621 if (p3 != MachineType::None())
622 storage_[index++] = WasmOpcodes::LocalTypeFor(p3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623
Ben Murdoch097c5b22016-05-18 11:27:45 +0100624 compiler_.InitializeDescriptor();
625 wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3);
626 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000627
Ben Murdoch097c5b22016-05-18 11:27:45 +0100628 // Builds a graph from the given Wasm code and generates the machine
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000629 // code and call wrapper for that graph. This method must not be called
630 // more than once.
631 void Build(const byte* start, const byte* end) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100632 CHECK(!compiled_);
633 compiled_ = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000634 compiler_.Build(start, end);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000635
Ben Murdoch61f157c2016-09-16 13:49:30 +0100636 if (!interpret()) {
637 // Compile machine code and install it into the module.
638 Handle<Code> code = compiler_.Compile();
639
640 if (compiler_.testing_module_) {
641 // Update the table of function code in the module.
642 compiler_.testing_module_->SetFunctionCode(
643 compiler_.function_->func_index, code);
644 }
645
646 wrapper_.SetInnerCode(code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000647 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000648 }
649
Ben Murdoch61f157c2016-09-16 13:49:30 +0100650 ReturnType Call() {
651 if (interpret()) {
652 return CallInterpreter(Vector<WasmVal>(nullptr, 0));
653 } else {
654 return Call(0, 0, 0, 0);
655 }
656 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000657
658 template <typename P0>
659 ReturnType Call(P0 p0) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100660 if (interpret()) {
661 WasmVal args[] = {WasmVal(p0)};
662 return CallInterpreter(ArrayVector(args));
663 } else {
664 return Call(p0, 0, 0, 0);
665 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000666 }
667
668 template <typename P0, typename P1>
669 ReturnType Call(P0 p0, P1 p1) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100670 if (interpret()) {
671 WasmVal args[] = {WasmVal(p0), WasmVal(p1)};
672 return CallInterpreter(ArrayVector(args));
673 } else {
674 return Call(p0, p1, 0, 0);
675 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000676 }
677
678 template <typename P0, typename P1, typename P2>
679 ReturnType Call(P0 p0, P1 p1, P2 p2) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100680 if (interpret()) {
681 WasmVal args[] = {WasmVal(p0), WasmVal(p1), WasmVal(p2)};
682 return CallInterpreter(ArrayVector(args));
683 } else {
684 return Call(p0, p1, p2, 0);
685 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000686 }
687
688 template <typename P0, typename P1, typename P2, typename P3>
689 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100690 if (interpret()) {
691 WasmVal args[] = {WasmVal(p0), WasmVal(p1), WasmVal(p2), WasmVal(p3)};
692 return CallInterpreter(ArrayVector(args));
693 } else {
694 CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
695 wrapper_.GetWrapperCode(),
696 wrapper_.signature());
697 ReturnType return_value;
698 int32_t result = runner.Call<void*, void*, void*, void*, void*>(
699 &p0, &p1, &p2, &p3, &return_value);
700 CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result);
701 return return_value;
702 }
703 }
704
705 ReturnType CallInterpreter(Vector<WasmVal> args) {
706 CHECK_EQ(args.length(),
707 static_cast<int>(compiler_.function_->sig->parameter_count()));
708 WasmInterpreter::Thread* thread = interpreter()->GetThread(0);
709 thread->Reset();
710 thread->PushFrame(compiler_.function_, args.start());
711 if (thread->Run() == WasmInterpreter::FINISHED) {
712 WasmVal val = thread->GetReturnValue();
713 return val.to<ReturnType>();
714 } else if (thread->state() == WasmInterpreter::TRAPPED) {
715 // TODO(titzer): return the correct trap code
716 int64_t result = 0xdeadbeefdeadbeef;
717 return static_cast<ReturnType>(result);
718 } else {
719 // TODO(titzer): falling off end
720 ReturnType val = 0;
721 return val;
722 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000723 }
724
Ben Murdochda12d292016-06-02 14:46:10 +0100725 byte AllocateLocal(LocalType type) { return compiler_.AllocateLocal(type); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000726
Ben Murdoch61f157c2016-09-16 13:49:30 +0100727 WasmFunction* function() { return compiler_.function_; }
728 WasmInterpreter* interpreter() { return compiler_.interpreter_; }
729
Ben Murdoch097c5b22016-05-18 11:27:45 +0100730 protected:
Ben Murdochda12d292016-06-02 14:46:10 +0100731 v8::base::AccountingAllocator allocator_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100732 Zone zone;
733 bool compiled_;
734 LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000735 FunctionSig signature_;
736 WasmFunctionCompiler compiler_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100737 WasmFunctionWrapper<ReturnType> wrapper_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000738
Ben Murdoch61f157c2016-09-16 13:49:30 +0100739 bool interpret() { return compiler_.execution_mode_ == kExecuteInterpreted; }
740
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000741 static size_t GetParameterCount(MachineType p0, MachineType p1,
742 MachineType p2, MachineType p3) {
743 if (p0 == MachineType::None()) return 0;
744 if (p1 == MachineType::None()) return 1;
745 if (p2 == MachineType::None()) return 2;
746 if (p3 == MachineType::None()) return 3;
747 return 4;
748 }
749};
750
Ben Murdochc5610432016-08-08 18:44:38 +0100751// A macro to define tests that run in different engine configurations.
752// Currently only supports compiled tests, but a future
753// RunWasmInterpreted_##name version will allow each test to also run in the
754// interpreter.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100755#define WASM_EXEC_TEST(name) \
756 void RunWasm_##name(WasmExecutionMode execution_mode); \
757 TEST(RunWasmCompiled_##name) { RunWasm_##name(kExecuteCompiled); } \
758 TEST(RunWasmInterpreted_##name) { RunWasm_##name(kExecuteInterpreted); } \
759 void RunWasm_##name(WasmExecutionMode execution_mode)
Ben Murdochc5610432016-08-08 18:44:38 +0100760
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761} // namespace
762
763#endif