Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include <stdint.h>
6 : #include <stdio.h>
7 : #include <stdlib.h>
8 : #include <string.h>
9 :
10 : #include "src/api-inl.h"
11 : #include "src/assembler-inl.h"
12 : #include "src/objects/heap-number-inl.h"
13 : #include "test/cctest/cctest.h"
14 : #include "test/cctest/compiler/value-helper.h"
15 : #include "test/cctest/wasm/wasm-run-utils.h"
16 : #include "test/common/wasm/test-signatures.h"
17 : #include "test/common/wasm/wasm-macro-gen.h"
18 :
19 : namespace v8 {
20 : namespace internal {
21 : namespace wasm {
22 :
23 : #define ADD_CODE(vec, ...) \
24 : do { \
25 : byte __buf[] = {__VA_ARGS__}; \
26 : for (size_t i = 0; i < sizeof(__buf); i++) vec.push_back(__buf[i]); \
27 : } while (false)
28 :
29 : namespace {
30 : // A helper for generating predictable but unique argument values that
31 : // are easy to debug (e.g. with misaligned stacks).
32 : class PredictableInputValues {
33 : public:
34 : int base_;
35 : explicit PredictableInputValues(int base) : base_(base) {}
36 5364 : double arg_d(int which) { return base_ * which + ((which & 1) * 0.5); }
37 : float arg_f(int which) { return base_ * which + ((which & 1) * 0.25); }
38 : int32_t arg_i(int which) { return base_ * which + ((which & 1) * kMinInt); }
39 : int64_t arg_l(int which) {
40 : return base_ * which + ((which & 1) * (0x04030201LL << 32));
41 : }
42 : };
43 :
44 1944 : ManuallyImportedJSFunction CreateJSSelector(FunctionSig* sig, int which) {
45 : const int kMaxParams = 11;
46 : static const char* formals[kMaxParams] = {"",
47 : "a",
48 : "a,b",
49 : "a,b,c",
50 : "a,b,c,d",
51 : "a,b,c,d,e",
52 : "a,b,c,d,e,f",
53 : "a,b,c,d,e,f,g",
54 : "a,b,c,d,e,f,g,h",
55 : "a,b,c,d,e,f,g,h,i",
56 : "a,b,c,d,e,f,g,h,i,j"};
57 1944 : CHECK_LT(which, static_cast<int>(sig->parameter_count()));
58 1944 : CHECK_LT(static_cast<int>(sig->parameter_count()), kMaxParams);
59 :
60 : i::EmbeddedVector<char, 256> source;
61 1944 : char param = 'a' + which;
62 : SNPrintF(source, "(function(%s) { return %c; })",
63 1944 : formals[sig->parameter_count()], param);
64 :
65 : Handle<JSFunction> js_function =
66 : Handle<JSFunction>::cast(v8::Utils::OpenHandle(
67 3888 : *v8::Local<v8::Function>::Cast(CompileRun(source.start()))));
68 1944 : ManuallyImportedJSFunction import = {sig, js_function};
69 :
70 1944 : return import;
71 : }
72 : } // namespace
73 :
74 25899 : WASM_EXEC_TEST(Run_Int32Sub_jswrapped) {
75 12 : WasmRunner<int, int, int> r(execution_tier);
76 12 : BUILD(r, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
77 :
78 12 : r.CheckCallViaJS(33, 44, 11);
79 12 : r.CheckCallViaJS(-8723487, -8000000, 723487);
80 12 : }
81 :
82 25899 : WASM_EXEC_TEST(Run_Float32Div_jswrapped) {
83 12 : WasmRunner<float, float, float> r(execution_tier);
84 12 : BUILD(r, WASM_F32_DIV(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
85 :
86 12 : r.CheckCallViaJS(92, 46, 0.5);
87 12 : r.CheckCallViaJS(64, -16, -0.25);
88 12 : }
89 :
90 25899 : WASM_EXEC_TEST(Run_Float64Add_jswrapped) {
91 12 : WasmRunner<double, double, double> r(execution_tier);
92 12 : BUILD(r, WASM_F64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
93 :
94 12 : r.CheckCallViaJS(3, 2, 1);
95 12 : r.CheckCallViaJS(-5.5, -5.25, -0.25);
96 12 : }
97 :
98 25899 : WASM_EXEC_TEST(Run_I32Popcount_jswrapped) {
99 12 : WasmRunner<int, int> r(execution_tier);
100 12 : BUILD(r, WASM_I32_POPCNT(WASM_GET_LOCAL(0)));
101 :
102 12 : r.CheckCallViaJS(2, 9);
103 12 : r.CheckCallViaJS(3, 11);
104 12 : r.CheckCallViaJS(6, 0x3F);
105 12 : }
106 :
107 25899 : WASM_EXEC_TEST(Run_CallJS_Add_jswrapped) {
108 12 : TestSignatures sigs;
109 12 : HandleScope scope(CcTest::InitIsolateOnce());
110 : const char* source = "(function(a) { return a + 99; })";
111 : Handle<JSFunction> js_function =
112 : Handle<JSFunction>::cast(v8::Utils::OpenHandle(
113 12 : *v8::Local<v8::Function>::Cast(CompileRun(source))));
114 12 : ManuallyImportedJSFunction import = {sigs.i_i(), js_function};
115 24 : WasmRunner<int, int> r(execution_tier, &import);
116 : uint32_t js_index = 0;
117 12 : BUILD(r, WASM_CALL_FUNCTION(js_index, WASM_GET_LOCAL(0)));
118 :
119 12 : r.CheckCallViaJS(101, 2);
120 12 : r.CheckCallViaJS(199, 100);
121 12 : r.CheckCallViaJS(-666666801, -666666900);
122 12 : }
123 :
124 96 : void RunJSSelectTest(ExecutionTier tier, int which) {
125 : const int kMaxParams = 8;
126 : PredictableInputValues inputs(0x100);
127 : ValueType type = kWasmF64;
128 : ValueType types[kMaxParams + 1] = {type, type, type, type, type,
129 96 : type, type, type, type};
130 432 : for (int num_params = which + 1; num_params < kMaxParams; num_params++) {
131 336 : HandleScope scope(CcTest::InitIsolateOnce());
132 336 : FunctionSig sig(1, num_params, types);
133 :
134 336 : ManuallyImportedJSFunction import = CreateJSSelector(&sig, which);
135 672 : WasmRunner<void> r(tier, &import);
136 : uint32_t js_index = 0;
137 :
138 672 : WasmFunctionCompiler& t = r.NewFunction(&sig);
139 :
140 : {
141 : std::vector<byte> code;
142 :
143 2016 : for (int i = 0; i < num_params; i++) {
144 3360 : ADD_CODE(code, WASM_F64(inputs.arg_d(i)));
145 : }
146 :
147 336 : ADD_CODE(code, kExprCallFunction, static_cast<byte>(js_index));
148 :
149 336 : size_t end = code.size();
150 672 : code.push_back(0);
151 672 : t.Build(&code[0], &code[end]);
152 : }
153 :
154 : double expected = inputs.arg_d(which);
155 336 : r.CheckCallViaJS(expected, t.function_index(), nullptr, 0);
156 : }
157 96 : }
158 :
159 25899 : WASM_EXEC_TEST(Run_JSSelect_0) {
160 12 : CcTest::InitializeVM();
161 12 : RunJSSelectTest(execution_tier, 0);
162 0 : }
163 :
164 25899 : WASM_EXEC_TEST(Run_JSSelect_1) {
165 12 : CcTest::InitializeVM();
166 12 : RunJSSelectTest(execution_tier, 1);
167 0 : }
168 :
169 25899 : WASM_EXEC_TEST(Run_JSSelect_2) {
170 12 : CcTest::InitializeVM();
171 12 : RunJSSelectTest(execution_tier, 2);
172 0 : }
173 :
174 25899 : WASM_EXEC_TEST(Run_JSSelect_3) {
175 12 : CcTest::InitializeVM();
176 12 : RunJSSelectTest(execution_tier, 3);
177 0 : }
178 :
179 25899 : WASM_EXEC_TEST(Run_JSSelect_4) {
180 12 : CcTest::InitializeVM();
181 12 : RunJSSelectTest(execution_tier, 4);
182 0 : }
183 :
184 25899 : WASM_EXEC_TEST(Run_JSSelect_5) {
185 12 : CcTest::InitializeVM();
186 12 : RunJSSelectTest(execution_tier, 5);
187 0 : }
188 :
189 25899 : WASM_EXEC_TEST(Run_JSSelect_6) {
190 12 : CcTest::InitializeVM();
191 12 : RunJSSelectTest(execution_tier, 6);
192 0 : }
193 :
194 25899 : WASM_EXEC_TEST(Run_JSSelect_7) {
195 12 : CcTest::InitializeVM();
196 12 : RunJSSelectTest(execution_tier, 7);
197 0 : }
198 :
199 96 : void RunWASMSelectTest(ExecutionTier tier, int which) {
200 : PredictableInputValues inputs(0x200);
201 96 : Isolate* isolate = CcTest::InitIsolateOnce();
202 : const int kMaxParams = 8;
203 432 : for (int num_params = which + 1; num_params < kMaxParams; num_params++) {
204 : ValueType type = kWasmF64;
205 : ValueType types[kMaxParams + 1] = {type, type, type, type, type,
206 336 : type, type, type, type};
207 336 : FunctionSig sig(1, num_params, types);
208 :
209 336 : WasmRunner<void> r(tier);
210 672 : WasmFunctionCompiler& t = r.NewFunction(&sig);
211 336 : BUILD(t, WASM_GET_LOCAL(which));
212 :
213 : Handle<Object> args[] = {
214 : isolate->factory()->NewNumber(inputs.arg_d(0)),
215 : isolate->factory()->NewNumber(inputs.arg_d(1)),
216 : isolate->factory()->NewNumber(inputs.arg_d(2)),
217 : isolate->factory()->NewNumber(inputs.arg_d(3)),
218 : isolate->factory()->NewNumber(inputs.arg_d(4)),
219 : isolate->factory()->NewNumber(inputs.arg_d(5)),
220 : isolate->factory()->NewNumber(inputs.arg_d(6)),
221 : isolate->factory()->NewNumber(inputs.arg_d(7)),
222 336 : };
223 :
224 : double expected = inputs.arg_d(which);
225 336 : r.CheckCallViaJS(expected, t.function_index(), args, kMaxParams);
226 336 : }
227 96 : }
228 :
229 25899 : WASM_EXEC_TEST(Run_WASMSelect_0) {
230 12 : CcTest::InitializeVM();
231 12 : RunWASMSelectTest(execution_tier, 0);
232 0 : }
233 :
234 25899 : WASM_EXEC_TEST(Run_WASMSelect_1) {
235 12 : CcTest::InitializeVM();
236 12 : RunWASMSelectTest(execution_tier, 1);
237 0 : }
238 :
239 25899 : WASM_EXEC_TEST(Run_WASMSelect_2) {
240 12 : CcTest::InitializeVM();
241 12 : RunWASMSelectTest(execution_tier, 2);
242 0 : }
243 :
244 25899 : WASM_EXEC_TEST(Run_WASMSelect_3) {
245 12 : CcTest::InitializeVM();
246 12 : RunWASMSelectTest(execution_tier, 3);
247 0 : }
248 :
249 25899 : WASM_EXEC_TEST(Run_WASMSelect_4) {
250 12 : CcTest::InitializeVM();
251 12 : RunWASMSelectTest(execution_tier, 4);
252 0 : }
253 :
254 25899 : WASM_EXEC_TEST(Run_WASMSelect_5) {
255 12 : CcTest::InitializeVM();
256 12 : RunWASMSelectTest(execution_tier, 5);
257 0 : }
258 :
259 25899 : WASM_EXEC_TEST(Run_WASMSelect_6) {
260 12 : CcTest::InitializeVM();
261 12 : RunWASMSelectTest(execution_tier, 6);
262 0 : }
263 :
264 25899 : WASM_EXEC_TEST(Run_WASMSelect_7) {
265 12 : CcTest::InitializeVM();
266 12 : RunWASMSelectTest(execution_tier, 7);
267 0 : }
268 :
269 300 : void RunWASMSelectAlignTest(ExecutionTier tier, int num_args, int num_params) {
270 : PredictableInputValues inputs(0x300);
271 300 : Isolate* isolate = CcTest::InitIsolateOnce();
272 : const int kMaxParams = 10;
273 : DCHECK_LE(num_args, kMaxParams);
274 : ValueType type = kWasmF64;
275 : ValueType types[kMaxParams + 1] = {type, type, type, type, type, type,
276 300 : type, type, type, type, type};
277 300 : FunctionSig sig(1, num_params, types);
278 :
279 1944 : for (int which = 0; which < num_params; which++) {
280 1644 : WasmRunner<void> r(tier);
281 3288 : WasmFunctionCompiler& t = r.NewFunction(&sig);
282 1644 : BUILD(t, WASM_GET_LOCAL(which));
283 :
284 : Handle<Object> args[] = {isolate->factory()->NewNumber(inputs.arg_d(0)),
285 : isolate->factory()->NewNumber(inputs.arg_d(1)),
286 : isolate->factory()->NewNumber(inputs.arg_d(2)),
287 : isolate->factory()->NewNumber(inputs.arg_d(3)),
288 : isolate->factory()->NewNumber(inputs.arg_d(4)),
289 : isolate->factory()->NewNumber(inputs.arg_d(5)),
290 : isolate->factory()->NewNumber(inputs.arg_d(6)),
291 : isolate->factory()->NewNumber(inputs.arg_d(7)),
292 : isolate->factory()->NewNumber(inputs.arg_d(8)),
293 1644 : isolate->factory()->NewNumber(inputs.arg_d(9))};
294 :
295 : double nan = std::numeric_limits<double>::quiet_NaN();
296 1644 : double expected = which < num_args ? inputs.arg_d(which) : nan;
297 1644 : r.CheckCallViaJS(expected, t.function_index(), args, num_args);
298 1644 : }
299 300 : }
300 :
301 25899 : WASM_EXEC_TEST(Run_WASMSelectAlign_0) {
302 12 : CcTest::InitializeVM();
303 12 : RunWASMSelectAlignTest(execution_tier, 0, 1);
304 12 : RunWASMSelectAlignTest(execution_tier, 0, 2);
305 12 : }
306 :
307 25899 : WASM_EXEC_TEST(Run_WASMSelectAlign_1) {
308 12 : CcTest::InitializeVM();
309 12 : RunWASMSelectAlignTest(execution_tier, 1, 2);
310 12 : RunWASMSelectAlignTest(execution_tier, 1, 3);
311 12 : }
312 :
313 25899 : WASM_EXEC_TEST(Run_WASMSelectAlign_2) {
314 12 : CcTest::InitializeVM();
315 12 : RunWASMSelectAlignTest(execution_tier, 2, 3);
316 12 : RunWASMSelectAlignTest(execution_tier, 2, 4);
317 12 : }
318 :
319 25899 : WASM_EXEC_TEST(Run_WASMSelectAlign_3) {
320 12 : CcTest::InitializeVM();
321 12 : RunWASMSelectAlignTest(execution_tier, 3, 3);
322 12 : RunWASMSelectAlignTest(execution_tier, 3, 4);
323 12 : }
324 :
325 25899 : WASM_EXEC_TEST(Run_WASMSelectAlign_4) {
326 12 : CcTest::InitializeVM();
327 12 : RunWASMSelectAlignTest(execution_tier, 4, 3);
328 12 : RunWASMSelectAlignTest(execution_tier, 4, 4);
329 12 : }
330 :
331 25899 : WASM_EXEC_TEST(Run_WASMSelectAlign_7) {
332 12 : CcTest::InitializeVM();
333 12 : RunWASMSelectAlignTest(execution_tier, 7, 5);
334 12 : RunWASMSelectAlignTest(execution_tier, 7, 6);
335 12 : RunWASMSelectAlignTest(execution_tier, 7, 7);
336 12 : }
337 :
338 25899 : WASM_EXEC_TEST(Run_WASMSelectAlign_8) {
339 12 : CcTest::InitializeVM();
340 12 : RunWASMSelectAlignTest(execution_tier, 8, 5);
341 12 : RunWASMSelectAlignTest(execution_tier, 8, 6);
342 12 : RunWASMSelectAlignTest(execution_tier, 8, 7);
343 12 : RunWASMSelectAlignTest(execution_tier, 8, 8);
344 12 : }
345 :
346 25899 : WASM_EXEC_TEST(Run_WASMSelectAlign_9) {
347 12 : CcTest::InitializeVM();
348 12 : RunWASMSelectAlignTest(execution_tier, 9, 6);
349 12 : RunWASMSelectAlignTest(execution_tier, 9, 7);
350 12 : RunWASMSelectAlignTest(execution_tier, 9, 8);
351 12 : RunWASMSelectAlignTest(execution_tier, 9, 9);
352 12 : }
353 :
354 25899 : WASM_EXEC_TEST(Run_WASMSelectAlign_10) {
355 12 : CcTest::InitializeVM();
356 12 : RunWASMSelectAlignTest(execution_tier, 10, 7);
357 12 : RunWASMSelectAlignTest(execution_tier, 10, 8);
358 12 : RunWASMSelectAlignTest(execution_tier, 10, 9);
359 12 : RunWASMSelectAlignTest(execution_tier, 10, 10);
360 12 : }
361 :
362 312 : void RunJSSelectAlignTest(ExecutionTier tier, int num_args, int num_params) {
363 : PredictableInputValues inputs(0x400);
364 312 : Isolate* isolate = CcTest::InitIsolateOnce();
365 : Factory* factory = isolate->factory();
366 : const int kMaxParams = 10;
367 312 : CHECK_LE(num_args, kMaxParams);
368 312 : CHECK_LE(num_params, kMaxParams);
369 : ValueType type = kWasmF64;
370 : ValueType types[kMaxParams + 1] = {type, type, type, type, type, type,
371 312 : type, type, type, type, type};
372 312 : FunctionSig sig(1, num_params, types);
373 312 : i::AccountingAllocator allocator;
374 624 : Zone zone(&allocator, ZONE_NAME);
375 :
376 : // Build the calling code.
377 : std::vector<byte> code;
378 :
379 1920 : for (int i = 0; i < num_params; i++) {
380 1608 : ADD_CODE(code, WASM_GET_LOCAL(i));
381 : }
382 :
383 : uint8_t imported_js_index = 0;
384 312 : ADD_CODE(code, kExprCallFunction, imported_js_index);
385 :
386 312 : size_t end = code.size();
387 624 : code.push_back(0);
388 :
389 : // Call different select JS functions.
390 1920 : for (int which = 0; which < num_params; which++) {
391 : HandleScope scope(isolate);
392 1608 : ManuallyImportedJSFunction import = CreateJSSelector(&sig, which);
393 3216 : WasmRunner<void> r(tier, &import);
394 3216 : WasmFunctionCompiler& t = r.NewFunction(&sig);
395 3216 : t.Build(&code[0], &code[end]);
396 :
397 : Handle<Object> args[] = {
398 : factory->NewNumber(inputs.arg_d(0)),
399 : factory->NewNumber(inputs.arg_d(1)),
400 : factory->NewNumber(inputs.arg_d(2)),
401 : factory->NewNumber(inputs.arg_d(3)),
402 : factory->NewNumber(inputs.arg_d(4)),
403 : factory->NewNumber(inputs.arg_d(5)),
404 : factory->NewNumber(inputs.arg_d(6)),
405 : factory->NewNumber(inputs.arg_d(7)),
406 : factory->NewNumber(inputs.arg_d(8)),
407 : factory->NewNumber(inputs.arg_d(9)),
408 1608 : };
409 :
410 : double nan = std::numeric_limits<double>::quiet_NaN();
411 1608 : double expected = which < num_args ? inputs.arg_d(which) : nan;
412 1608 : r.CheckCallViaJS(expected, t.function_index(), args, num_args);
413 312 : }
414 312 : }
415 :
416 25899 : WASM_EXEC_TEST(Run_JSSelectAlign_0) {
417 12 : CcTest::InitializeVM();
418 12 : RunJSSelectAlignTest(execution_tier, 0, 1);
419 12 : RunJSSelectAlignTest(execution_tier, 0, 2);
420 12 : }
421 :
422 25899 : WASM_EXEC_TEST(Run_JSSelectAlign_1) {
423 12 : CcTest::InitializeVM();
424 12 : RunJSSelectAlignTest(execution_tier, 1, 2);
425 12 : RunJSSelectAlignTest(execution_tier, 1, 3);
426 12 : }
427 :
428 25899 : WASM_EXEC_TEST(Run_JSSelectAlign_2) {
429 12 : CcTest::InitializeVM();
430 12 : RunJSSelectAlignTest(execution_tier, 2, 3);
431 12 : RunJSSelectAlignTest(execution_tier, 2, 4);
432 12 : }
433 :
434 25899 : WASM_EXEC_TEST(Run_JSSelectAlign_3) {
435 12 : CcTest::InitializeVM();
436 12 : RunJSSelectAlignTest(execution_tier, 3, 3);
437 12 : RunJSSelectAlignTest(execution_tier, 3, 4);
438 12 : }
439 :
440 25899 : WASM_EXEC_TEST(Run_JSSelectAlign_4) {
441 12 : CcTest::InitializeVM();
442 12 : RunJSSelectAlignTest(execution_tier, 4, 3);
443 12 : RunJSSelectAlignTest(execution_tier, 4, 4);
444 12 : }
445 :
446 25899 : WASM_EXEC_TEST(Run_JSSelectAlign_7) {
447 12 : CcTest::InitializeVM();
448 12 : RunJSSelectAlignTest(execution_tier, 7, 3);
449 12 : RunJSSelectAlignTest(execution_tier, 7, 4);
450 12 : RunJSSelectAlignTest(execution_tier, 7, 4);
451 12 : RunJSSelectAlignTest(execution_tier, 7, 4);
452 12 : }
453 :
454 25899 : WASM_EXEC_TEST(Run_JSSelectAlign_8) {
455 12 : CcTest::InitializeVM();
456 12 : RunJSSelectAlignTest(execution_tier, 8, 5);
457 12 : RunJSSelectAlignTest(execution_tier, 8, 6);
458 12 : RunJSSelectAlignTest(execution_tier, 8, 7);
459 12 : RunJSSelectAlignTest(execution_tier, 8, 8);
460 12 : }
461 :
462 25899 : WASM_EXEC_TEST(Run_JSSelectAlign_9) {
463 12 : CcTest::InitializeVM();
464 12 : RunJSSelectAlignTest(execution_tier, 9, 6);
465 12 : RunJSSelectAlignTest(execution_tier, 9, 7);
466 12 : RunJSSelectAlignTest(execution_tier, 9, 8);
467 12 : RunJSSelectAlignTest(execution_tier, 9, 9);
468 12 : }
469 :
470 25899 : WASM_EXEC_TEST(Run_JSSelectAlign_10) {
471 12 : CcTest::InitializeVM();
472 12 : RunJSSelectAlignTest(execution_tier, 10, 7);
473 12 : RunJSSelectAlignTest(execution_tier, 10, 8);
474 12 : RunJSSelectAlignTest(execution_tier, 10, 9);
475 12 : RunJSSelectAlignTest(execution_tier, 10, 10);
476 12 : }
477 :
478 : #undef ADD_CODE
479 :
480 : } // namespace wasm
481 : } // namespace internal
482 77625 : } // namespace v8
|