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

Side by Side Diff: test/cctest/wasm/test-run-wasm.cc

Issue 1581393003: Reland of [wasm] Add tests for JS wrappers to test-run-wasm. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 11 months 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/cctest.gyp ('k') | test/cctest/wasm/test-run-wasm-js.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 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 #include <stdint.h> 5 #include <stdint.h>
6 #include <stdlib.h> 6 #include <stdlib.h>
7 #include <string.h> 7 #include <string.h>
8 8
9 #include "src/base/utils/random-number-generator.h"
10
11 #include "src/compiler/graph-visualizer.h"
12 #include "src/compiler/js-graph.h"
13 #include "src/compiler/wasm-compiler.h"
14
15 #include "src/wasm/ast-decoder.h"
16 #include "src/wasm/wasm-macro-gen.h" 9 #include "src/wasm/wasm-macro-gen.h"
17 #include "src/wasm/wasm-module.h"
18 #include "src/wasm/wasm-opcodes.h"
19 10
20 #include "test/cctest/cctest.h" 11 #include "test/cctest/cctest.h"
21 #include "test/cctest/compiler/codegen-tester.h"
22 #include "test/cctest/compiler/graph-builder-tester.h"
23 #include "test/cctest/compiler/value-helper.h" 12 #include "test/cctest/compiler/value-helper.h"
24
25 #include "test/cctest/wasm/test-signatures.h" 13 #include "test/cctest/wasm/test-signatures.h"
26 14 #include "test/cctest/wasm/wasm-run-utils.h"
27 // TODO(titzer): pull WASM_64 up to a common header.
28 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64
29 #define WASM_64 1
30 #else
31 #define WASM_64 0
32 #endif
33
34 // TODO(titzer): check traps more robustly in tests.
35 // Currently, in tests, we just return 0xdeadbeef from the function in which
36 // the trap occurs if the runtime context is not available to throw a JavaScript
37 // exception.
38 #define CHECK_TRAP32(x) \
39 CHECK_EQ(0xdeadbeef, (bit_cast<uint32_t>(x)) & 0xFFFFFFFF)
40 #define CHECK_TRAP64(x) \
41 CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF)
42 #define CHECK_TRAP(x) CHECK_TRAP32(x)
43
44 15
45 using namespace v8::base; 16 using namespace v8::base;
46 using namespace v8::internal; 17 using namespace v8::internal;
47 using namespace v8::internal::compiler; 18 using namespace v8::internal::compiler;
48 using namespace v8::internal::wasm; 19 using namespace v8::internal::wasm;
49 20
50 static void init_env(FunctionEnv* env, FunctionSig* sig) {
51 env->module = nullptr;
52 env->sig = sig;
53 env->local_int32_count = 0;
54 env->local_int64_count = 0;
55 env->local_float32_count = 0;
56 env->local_float64_count = 0;
57 env->SumLocals();
58 }
59
60 const uint32_t kMaxGlobalsSize = 128;
61
62 // A helper for module environments that adds the ability to allocate memory
63 // and global variables.
64 class TestingModule : public ModuleEnv {
65 public:
66 TestingModule() : mem_size(0), global_offset(0) {
67 globals_area = 0;
68 mem_start = 0;
69 mem_end = 0;
70 module = nullptr;
71 linker = nullptr;
72 function_code = nullptr;
73 asm_js = false;
74 memset(global_data, 0, sizeof(global_data));
75 }
76
77 ~TestingModule() {
78 if (mem_start) {
79 free(raw_mem_start<byte>());
80 }
81 if (function_code) delete function_code;
82 if (module) delete module;
83 }
84
85 byte* AddMemory(size_t size) {
86 CHECK_EQ(0, mem_start);
87 CHECK_EQ(0, mem_size);
88 mem_start = reinterpret_cast<uintptr_t>(malloc(size));
89 CHECK(mem_start);
90 byte* raw = raw_mem_start<byte>();
91 memset(raw, 0, size);
92 mem_end = mem_start + size;
93 mem_size = size;
94 return raw_mem_start<byte>();
95 }
96
97 template <typename T>
98 T* AddMemoryElems(size_t count) {
99 AddMemory(count * sizeof(T));
100 return raw_mem_start<T>();
101 }
102
103 template <typename T>
104 T* AddGlobal(MachineType mem_type) {
105 WasmGlobal* global = AddGlobal(mem_type);
106 return reinterpret_cast<T*>(globals_area + global->offset);
107 }
108
109 byte AddSignature(FunctionSig* sig) {
110 AllocModule();
111 if (!module->signatures) {
112 module->signatures = new std::vector<FunctionSig*>();
113 }
114 module->signatures->push_back(sig);
115 size_t size = module->signatures->size();
116 CHECK(size < 127);
117 return static_cast<byte>(size - 1);
118 }
119
120 template <typename T>
121 T* raw_mem_start() {
122 DCHECK(mem_start);
123 return reinterpret_cast<T*>(mem_start);
124 }
125
126 template <typename T>
127 T* raw_mem_end() {
128 DCHECK(mem_end);
129 return reinterpret_cast<T*>(mem_end);
130 }
131
132 template <typename T>
133 T raw_mem_at(int i) {
134 DCHECK(mem_start);
135 return reinterpret_cast<T*>(mem_start)[i];
136 }
137
138 template <typename T>
139 T raw_val_at(int i) {
140 T val;
141 memcpy(&val, reinterpret_cast<void*>(mem_start + i), sizeof(T));
142 return val;
143 }
144
145 // Zero-initialize the memory.
146 void BlankMemory() {
147 byte* raw = raw_mem_start<byte>();
148 memset(raw, 0, mem_size);
149 }
150
151 // Pseudo-randomly intialize the memory.
152 void RandomizeMemory(unsigned int seed = 88) {
153 byte* raw = raw_mem_start<byte>();
154 byte* end = raw_mem_end<byte>();
155 v8::base::RandomNumberGenerator rng;
156 rng.SetSeed(seed);
157 rng.NextBytes(raw, end - raw);
158 }
159
160 WasmFunction* AddFunction(FunctionSig* sig, Handle<Code> code) {
161 AllocModule();
162 if (module->functions == nullptr) {
163 module->functions = new std::vector<WasmFunction>();
164 function_code = new std::vector<Handle<Code>>();
165 }
166 module->functions->push_back({sig, 0, 0, 0, 0, 0, 0, 0, false, false});
167 function_code->push_back(code);
168 return &module->functions->back();
169 }
170
171 private:
172 size_t mem_size;
173 uint32_t global_offset;
174 byte global_data[kMaxGlobalsSize];
175
176 WasmGlobal* AddGlobal(MachineType mem_type) {
177 AllocModule();
178 if (globals_area == 0) {
179 globals_area = reinterpret_cast<uintptr_t>(global_data);
180 module->globals = new std::vector<WasmGlobal>();
181 }
182 byte size = WasmOpcodes::MemSize(mem_type);
183 global_offset = (global_offset + size - 1) & ~(size - 1); // align
184 module->globals->push_back({0, mem_type, global_offset, false});
185 global_offset += size;
186 // limit number of globals.
187 CHECK_LT(global_offset, kMaxGlobalsSize);
188 return &module->globals->back();
189 }
190 void AllocModule() {
191 if (module == nullptr) {
192 module = new WasmModule();
193 module->globals = nullptr;
194 module->functions = nullptr;
195 module->data_segments = nullptr;
196 }
197 }
198 };
199
200
201 static void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, FunctionEnv* env,
202 const byte* start, const byte* end) {
203 compiler::WasmGraphBuilder builder(zone, jsgraph, env->sig);
204 TreeResult result = BuildTFGraph(&builder, env, start, end);
205 if (result.failed()) {
206 ptrdiff_t pc = result.error_pc - result.start;
207 ptrdiff_t pt = result.error_pt - result.start;
208 std::ostringstream str;
209 str << "Verification failed: " << result.error_code << " pc = +" << pc;
210 if (result.error_pt) str << ", pt = +" << pt;
211 str << ", msg = " << result.error_msg.get();
212 FATAL(str.str().c_str());
213 }
214 if (FLAG_trace_turbo_graph) {
215 OFStream os(stdout);
216 os << AsRPO(*jsgraph->graph());
217 }
218 }
219
220
221 // A helper for compiling functions that are only internally callable WASM code.
222 class WasmFunctionCompiler : public HandleAndZoneScope,
223 private GraphAndBuilders {
224 public:
225 explicit WasmFunctionCompiler(FunctionSig* sig)
226 : GraphAndBuilders(main_zone()),
227 jsgraph(this->isolate(), this->graph(), this->common(), nullptr,
228 nullptr, this->machine()),
229 descriptor_(nullptr) {
230 init_env(&env, sig);
231 }
232
233 JSGraph jsgraph;
234 FunctionEnv env;
235 // The call descriptor is initialized when the function is compiled.
236 CallDescriptor* descriptor_;
237
238 Isolate* isolate() { return main_isolate(); }
239 Graph* graph() const { return main_graph_; }
240 Zone* zone() const { return graph()->zone(); }
241 CommonOperatorBuilder* common() { return &main_common_; }
242 MachineOperatorBuilder* machine() { return &main_machine_; }
243 CallDescriptor* descriptor() { return descriptor_; }
244
245 void Build(const byte* start, const byte* end) {
246 TestBuildingGraph(main_zone(), &jsgraph, &env, start, end);
247 }
248
249 byte AllocateLocal(LocalType type) {
250 int result = static_cast<int>(env.total_locals);
251 env.AddLocals(type, 1);
252 byte b = static_cast<byte>(result);
253 CHECK_EQ(result, b);
254 return b;
255 }
256
257 Handle<Code> Compile(ModuleEnv* module) {
258 descriptor_ = module->GetWasmCallDescriptor(this->zone(), env.sig);
259 CompilationInfo info("wasm compile", this->isolate(), this->zone());
260 Handle<Code> result =
261 Pipeline::GenerateCodeForTesting(&info, descriptor_, this->graph());
262 #ifdef ENABLE_DISASSEMBLER
263 if (!result.is_null() && FLAG_print_opt_code) {
264 OFStream os(stdout);
265 result->Disassemble("wasm code", os);
266 }
267 #endif
268
269 return result;
270 }
271
272 uint32_t CompileAndAdd(TestingModule* module) {
273 uint32_t index = 0;
274 if (module->module && module->module->functions) {
275 index = static_cast<uint32_t>(module->module->functions->size());
276 }
277 module->AddFunction(env.sig, Compile(module));
278 return index;
279 }
280 };
281
282
283 // A helper class to build graphs from Wasm bytecode, generate machine
284 // code, and run that code.
285 template <typename ReturnType>
286 class WasmRunner {
287 public:
288 WasmRunner(MachineType p0 = MachineType::None(),
289 MachineType p1 = MachineType::None(),
290 MachineType p2 = MachineType::None(),
291 MachineType p3 = MachineType::None())
292 : signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1,
293 GetParameterCount(p0, p1, p2, p3), storage_),
294 compiler_(&signature_),
295 call_wrapper_(p0, p1, p2, p3),
296 compilation_done_(false) {
297 int index = 0;
298 MachineType ret = MachineTypeForC<ReturnType>();
299 if (ret != MachineType::None()) {
300 storage_[index++] = WasmOpcodes::LocalTypeFor(ret);
301 }
302 if (p0 != MachineType::None())
303 storage_[index++] = WasmOpcodes::LocalTypeFor(p0);
304 if (p1 != MachineType::None())
305 storage_[index++] = WasmOpcodes::LocalTypeFor(p1);
306 if (p2 != MachineType::None())
307 storage_[index++] = WasmOpcodes::LocalTypeFor(p2);
308 if (p3 != MachineType::None())
309 storage_[index++] = WasmOpcodes::LocalTypeFor(p3);
310 }
311
312
313 FunctionEnv* env() { return &compiler_.env; }
314
315
316 // Builds a graph from the given Wasm code, and generates the machine
317 // code and call wrapper for that graph. This method must not be called
318 // more than once.
319 void Build(const byte* start, const byte* end) {
320 DCHECK(!compilation_done_);
321 compilation_done_ = true;
322 // Build the TF graph.
323 compiler_.Build(start, end);
324 // Generate code.
325 Handle<Code> code = compiler_.Compile(env()->module);
326
327 // Construct the call wrapper.
328 Node* inputs[5];
329 int input_count = 0;
330 inputs[input_count++] = call_wrapper_.HeapConstant(code);
331 for (size_t i = 0; i < signature_.parameter_count(); i++) {
332 inputs[input_count++] = call_wrapper_.Parameter(i);
333 }
334
335 call_wrapper_.Return(call_wrapper_.AddNode(
336 call_wrapper_.common()->Call(compiler_.descriptor()), input_count,
337 inputs));
338 }
339
340
341 ReturnType Call() { return call_wrapper_.Call(); }
342
343
344 template <typename P0>
345 ReturnType Call(P0 p0) {
346 return call_wrapper_.Call(p0);
347 }
348
349
350 template <typename P0, typename P1>
351 ReturnType Call(P0 p0, P1 p1) {
352 return call_wrapper_.Call(p0, p1);
353 }
354
355
356 template <typename P0, typename P1, typename P2>
357 ReturnType Call(P0 p0, P1 p1, P2 p2) {
358 return call_wrapper_.Call(p0, p1, p2);
359 }
360
361
362 template <typename P0, typename P1, typename P2, typename P3>
363 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) {
364 return call_wrapper_.Call(p0, p1, p2, p3);
365 }
366
367
368 byte AllocateLocal(LocalType type) {
369 int result = static_cast<int>(env()->total_locals);
370 env()->AddLocals(type, 1);
371 byte b = static_cast<byte>(result);
372 CHECK_EQ(result, b);
373 return b;
374 }
375
376
377 private:
378 LocalType storage_[5];
379 FunctionSig signature_;
380 WasmFunctionCompiler compiler_;
381 BufferedRawMachineAssemblerTester<ReturnType> call_wrapper_;
382 bool compilation_done_;
383
384 static size_t GetParameterCount(MachineType p0, MachineType p1,
385 MachineType p2, MachineType p3) {
386 if (p0 == MachineType::None()) return 0;
387 if (p1 == MachineType::None()) return 1;
388 if (p2 == MachineType::None()) return 2;
389 if (p3 == MachineType::None()) return 3;
390 return 4;
391 }
392 };
393
394 #define BUILD(r, ...) \ 21 #define BUILD(r, ...) \
395 do { \ 22 do { \
396 byte code[] = {__VA_ARGS__}; \ 23 byte code[] = {__VA_ARGS__}; \
397 r.Build(code, code + arraysize(code)); \ 24 r.Build(code, code + arraysize(code)); \
398 } while (false) 25 } while (false)
399 26
400 27
401 TEST(Run_WasmInt8Const) { 28 TEST(Run_WasmInt8Const) {
402 WasmRunner<int8_t> r; 29 WasmRunner<int8_t> r;
403 const byte kExpectedValue = 121; 30 const byte kExpectedValue = 121;
(...skipping 2485 matching lines...) Expand 10 before | Expand all | Expand 10 after
2889 } 2516 }
2890 } 2517 }
2891 2518
2892 #define ADD_CODE(vec, ...) \ 2519 #define ADD_CODE(vec, ...) \
2893 do { \ 2520 do { \
2894 byte __buf[] = {__VA_ARGS__}; \ 2521 byte __buf[] = {__VA_ARGS__}; \
2895 for (size_t i = 0; i < sizeof(__buf); i++) vec.push_back(__buf[i]); \ 2522 for (size_t i = 0; i < sizeof(__buf); i++) vec.push_back(__buf[i]); \
2896 } while (false) 2523 } while (false)
2897 2524
2898 2525
2899 void Run_WasmMixedCall_N(int start) { 2526 static void Run_WasmMixedCall_N(int start) {
2900 const int kExpected = 6333; 2527 const int kExpected = 6333;
2901 const int kElemSize = 8; 2528 const int kElemSize = 8;
2902 TestSignatures sigs; 2529 TestSignatures sigs;
2903 2530
2904 #if WASM_64 2531 #if WASM_64
2905 static MachineType mixed[] = { 2532 static MachineType mixed[] = {
2906 MachineType::Int32(), MachineType::Float32(), MachineType::Int64(), 2533 MachineType::Int32(), MachineType::Float32(), MachineType::Int64(),
2907 MachineType::Float64(), MachineType::Float32(), MachineType::Int64(), 2534 MachineType::Float64(), MachineType::Float32(), MachineType::Int64(),
2908 MachineType::Int32(), MachineType::Float64(), MachineType::Float32(), 2535 MachineType::Int32(), MachineType::Float64(), MachineType::Float32(),
2909 MachineType::Float64(), MachineType::Int32(), MachineType::Int64(), 2536 MachineType::Float64(), MachineType::Int32(), MachineType::Int64(),
(...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after
3618 TEST(Run_Wasm_F32CopySign) { 3245 TEST(Run_Wasm_F32CopySign) {
3619 WasmRunner<float> r(MachineType::Float32(), MachineType::Float32()); 3246 WasmRunner<float> r(MachineType::Float32(), MachineType::Float32());
3620 BUILD(r, WASM_F32_COPYSIGN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); 3247 BUILD(r, WASM_F32_COPYSIGN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
3621 3248
3622 FOR_FLOAT32_INPUTS(i) { 3249 FOR_FLOAT32_INPUTS(i) {
3623 FOR_FLOAT32_INPUTS(j) { CheckFloatEq(copysign(*i, *j), r.Call(*i, *j)); } 3250 FOR_FLOAT32_INPUTS(j) { CheckFloatEq(copysign(*i, *j), r.Call(*i, *j)); }
3624 } 3251 }
3625 } 3252 }
3626 3253
3627 #endif 3254 #endif
OLDNEW
« no previous file with comments | « test/cctest/cctest.gyp ('k') | test/cctest/wasm/test-run-wasm-js.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698