OLD | NEW |
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 <stdio.h> |
6 #include <stdlib.h> | 7 #include <stdlib.h> |
7 #include <string.h> | 8 #include <string.h> |
8 | 9 |
9 #include "src/wasm/wasm-macro-gen.h" | 10 #include "src/wasm/wasm-macro-gen.h" |
10 | 11 |
11 #include "test/cctest/cctest.h" | 12 #include "test/cctest/cctest.h" |
12 #include "test/cctest/wasm/test-signatures.h" | 13 #include "test/cctest/wasm/test-signatures.h" |
13 #include "test/cctest/wasm/wasm-run-utils.h" | 14 #include "test/cctest/wasm/wasm-run-utils.h" |
14 | 15 |
15 using namespace v8::base; | 16 using namespace v8::base; |
16 using namespace v8::internal; | 17 using namespace v8::internal; |
17 using namespace v8::internal::compiler; | 18 using namespace v8::internal::compiler; |
18 using namespace v8::internal::wasm; | 19 using namespace v8::internal::wasm; |
19 | 20 |
20 #define BUILD(r, ...) \ | 21 #define BUILD(r, ...) \ |
21 do { \ | 22 do { \ |
22 byte code[] = {__VA_ARGS__}; \ | 23 byte code[] = {__VA_ARGS__}; \ |
23 r.Build(code, code + arraysize(code)); \ | 24 r.Build(code, code + arraysize(code)); \ |
24 } while (false) | 25 } while (false) |
25 | 26 |
26 | 27 |
27 static uint32_t AddJsFunction(TestingModule* module, FunctionSig* sig, | 28 #define ADD_CODE(vec, ...) \ |
28 const char* source) { | 29 do { \ |
| 30 byte __buf[] = {__VA_ARGS__}; \ |
| 31 for (size_t i = 0; i < sizeof(__buf); i++) vec.push_back(__buf[i]); \ |
| 32 } while (false) |
| 33 |
| 34 |
| 35 namespace { |
| 36 // A helper for generating predictable but unique argument values that |
| 37 // are easy to debug (e.g. with misaligned stacks). |
| 38 class PredictableInputValues { |
| 39 public: |
| 40 int base_; |
| 41 explicit PredictableInputValues(int base) : base_(base) {} |
| 42 double arg_d(int which) { return base_ * which + ((which & 1) * 0.5); } |
| 43 float arg_f(int which) { return base_ * which + ((which & 1) * 0.25); } |
| 44 int32_t arg_i(int which) { return base_ * which + ((which & 1) * kMinInt); } |
| 45 int64_t arg_l(int which) { |
| 46 return base_ * which + ((which & 1) * (0x04030201LL << 32)); |
| 47 } |
| 48 }; |
| 49 |
| 50 |
| 51 uint32_t AddJsFunction(TestingModule* module, FunctionSig* sig, |
| 52 const char* source) { |
29 Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle( | 53 Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle( |
30 *v8::Local<v8::Function>::Cast(CompileRun(source)))); | 54 *v8::Local<v8::Function>::Cast(CompileRun(source)))); |
31 module->AddFunction(sig, Handle<Code>::null()); | 55 module->AddFunction(sig, Handle<Code>::null()); |
32 uint32_t index = static_cast<uint32_t>(module->module->functions->size() - 1); | 56 uint32_t index = static_cast<uint32_t>(module->module->functions->size() - 1); |
33 Isolate* isolate = CcTest::InitIsolateOnce(); | 57 Isolate* isolate = CcTest::InitIsolateOnce(); |
34 Handle<Code> code = CompileWasmToJSWrapper(isolate, module, jsfunc, index); | 58 Handle<Code> code = CompileWasmToJSWrapper(isolate, module, jsfunc, index); |
35 module->function_code->at(index) = code; | 59 module->function_code->at(index) = code; |
36 return index; | 60 return index; |
37 } | 61 } |
38 | 62 |
39 | 63 |
40 static Handle<JSFunction> WrapCode(ModuleEnv* module, uint32_t index) { | 64 uint32_t AddJSSelector(TestingModule* module, FunctionSig* sig, int which) { |
| 65 const int kMaxParams = 8; |
| 66 static const char* formals[kMaxParams] = { |
| 67 "", "a", "a,b", "a,b,c", |
| 68 "a,b,c,d", "a,b,c,d,e", "a,b,c,d,e,f", "a,b,c,d,e,f,g", |
| 69 }; |
| 70 CHECK_LT(which, static_cast<int>(sig->parameter_count())); |
| 71 CHECK_LT(static_cast<int>(sig->parameter_count()), kMaxParams); |
| 72 |
| 73 i::EmbeddedVector<char, 256> source; |
| 74 char param = 'a' + which; |
| 75 SNPrintF(source, "(function(%s) { return %c; })", |
| 76 formals[sig->parameter_count()], param); |
| 77 |
| 78 return AddJsFunction(module, sig, source.start()); |
| 79 } |
| 80 |
| 81 |
| 82 Handle<JSFunction> WrapCode(ModuleEnv* module, uint32_t index) { |
41 Isolate* isolate = module->module->shared_isolate; | 83 Isolate* isolate = module->module->shared_isolate; |
42 // Wrap the code so it can be called as a JS function. | 84 // Wrap the code so it can be called as a JS function. |
43 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); | 85 Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); |
44 Handle<JSObject> module_object = Handle<JSObject>(0, isolate); | 86 Handle<JSObject> module_object = Handle<JSObject>(0, isolate); |
45 Handle<Code> code = module->function_code->at(index); | 87 Handle<Code> code = module->function_code->at(index); |
46 WasmJs::InstallWasmFunctionMap(isolate, isolate->native_context()); | 88 WasmJs::InstallWasmFunctionMap(isolate, isolate->native_context()); |
47 return compiler::CompileJSToWasmWrapper(isolate, module, name, code, | 89 return compiler::CompileJSToWasmWrapper(isolate, module, name, code, |
48 module_object, index); | 90 module_object, index); |
49 } | 91 } |
50 | 92 |
51 | 93 |
52 static void EXPECT_CALL(double expected, Handle<JSFunction> jsfunc, double a, | 94 void EXPECT_CALL(double expected, Handle<JSFunction> jsfunc, |
53 double b) { | 95 Handle<Object>* buffer, int count) { |
54 Isolate* isolate = jsfunc->GetIsolate(); | 96 Isolate* isolate = jsfunc->GetIsolate(); |
55 Handle<Object> buffer[] = {isolate->factory()->NewNumber(a), | |
56 isolate->factory()->NewNumber(b)}; | |
57 Handle<Object> global(isolate->context()->global_object(), isolate); | 97 Handle<Object> global(isolate->context()->global_object(), isolate); |
58 MaybeHandle<Object> retval = | 98 MaybeHandle<Object> retval = |
59 Execution::Call(isolate, jsfunc, global, 2, buffer); | 99 Execution::Call(isolate, jsfunc, global, count, buffer); |
60 | 100 |
61 CHECK(!retval.is_null()); | 101 CHECK(!retval.is_null()); |
62 Handle<Object> result = retval.ToHandleChecked(); | 102 Handle<Object> result = retval.ToHandleChecked(); |
63 if (result->IsSmi()) { | 103 if (result->IsSmi()) { |
64 CHECK_EQ(expected, Smi::cast(*result)->value()); | 104 CHECK_EQ(expected, Smi::cast(*result)->value()); |
65 } else { | 105 } else { |
66 CHECK(result->IsHeapNumber()); | 106 CHECK(result->IsHeapNumber()); |
67 CHECK_EQ(expected, HeapNumber::cast(*result)->value()); | 107 CheckFloatEq(expected, HeapNumber::cast(*result)->value()); |
68 } | 108 } |
69 } | 109 } |
70 | 110 |
71 | 111 |
| 112 void EXPECT_CALL(double expected, Handle<JSFunction> jsfunc, double a, |
| 113 double b) { |
| 114 Isolate* isolate = jsfunc->GetIsolate(); |
| 115 Handle<Object> buffer[] = {isolate->factory()->NewNumber(a), |
| 116 isolate->factory()->NewNumber(b)}; |
| 117 EXPECT_CALL(expected, jsfunc, buffer, 2); |
| 118 } |
| 119 } // namespace |
| 120 |
72 TEST(Run_Int32Sub_jswrapped) { | 121 TEST(Run_Int32Sub_jswrapped) { |
73 TestSignatures sigs; | 122 TestSignatures sigs; |
74 TestingModule module; | 123 TestingModule module; |
75 WasmFunctionCompiler t(sigs.i_ii()); | 124 WasmFunctionCompiler t(sigs.i_ii()); |
76 BUILD(t, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); | 125 BUILD(t, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); |
77 Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); | 126 Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); |
78 | 127 |
79 EXPECT_CALL(33, jsfunc, 44, 11); | 128 EXPECT_CALL(33, jsfunc, 44, 11); |
80 EXPECT_CALL(-8723487, jsfunc, -8000000, 723487); | 129 EXPECT_CALL(-8723487, jsfunc, -8000000, 723487); |
81 } | 130 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 | 163 |
115 EXPECT_CALL(2, jsfunc, 9, 0); | 164 EXPECT_CALL(2, jsfunc, 9, 0); |
116 EXPECT_CALL(3, jsfunc, 11, 0); | 165 EXPECT_CALL(3, jsfunc, 11, 0); |
117 EXPECT_CALL(6, jsfunc, 0x3F, 0); | 166 EXPECT_CALL(6, jsfunc, 0x3F, 0); |
118 | 167 |
119 USE(AddJsFunction); | 168 USE(AddJsFunction); |
120 } | 169 } |
121 | 170 |
122 | 171 |
123 #if !V8_TARGET_ARCH_ARM64 | 172 #if !V8_TARGET_ARCH_ARM64 |
124 // TODO(titzer): fix wasm->JS calls on arm64 (wrapper issues) | 173 // TODO(titzer): dynamic frame alignment on arm64 |
125 | |
126 TEST(Run_CallJS_Add_jswrapped) { | 174 TEST(Run_CallJS_Add_jswrapped) { |
127 TestSignatures sigs; | 175 TestSignatures sigs; |
128 TestingModule module; | 176 TestingModule module; |
129 WasmFunctionCompiler t(sigs.i_i(), &module); | 177 WasmFunctionCompiler t(sigs.i_i(), &module); |
130 uint32_t js_index = | 178 uint32_t js_index = |
131 AddJsFunction(&module, sigs.i_i(), "(function(a) { return a + 99; })"); | 179 AddJsFunction(&module, sigs.i_i(), "(function(a) { return a + 99; })"); |
132 BUILD(t, WASM_CALL_FUNCTION(js_index, WASM_GET_LOCAL(0))); | 180 BUILD(t, WASM_CALL_FUNCTION(js_index, WASM_GET_LOCAL(0))); |
133 | 181 |
134 Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); | 182 Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); |
135 | 183 |
136 EXPECT_CALL(101, jsfunc, 2, -8); | 184 EXPECT_CALL(101, jsfunc, 2, -8); |
137 EXPECT_CALL(199, jsfunc, 100, -1); | 185 EXPECT_CALL(199, jsfunc, 100, -1); |
138 EXPECT_CALL(-666666801, jsfunc, -666666900, -1); | 186 EXPECT_CALL(-666666801, jsfunc, -666666900, -1); |
139 } | 187 } |
140 | |
141 #endif | 188 #endif |
| 189 |
| 190 |
| 191 void RunJSSelectTest(int which) { |
| 192 const int kMaxParams = 8; |
| 193 PredictableInputValues inputs(0x100); |
| 194 LocalType type = kAstF64; |
| 195 LocalType types[kMaxParams + 1] = {type, type, type, type, type, |
| 196 type, type, type, type}; |
| 197 for (int num_params = which + 1; num_params < kMaxParams; num_params++) { |
| 198 HandleScope scope(CcTest::InitIsolateOnce()); |
| 199 FunctionSig sig(1, num_params, types); |
| 200 |
| 201 TestingModule module; |
| 202 uint32_t js_index = AddJSSelector(&module, &sig, which); |
| 203 WasmFunctionCompiler t(&sig, &module); |
| 204 |
| 205 { |
| 206 std::vector<byte> code; |
| 207 ADD_CODE(code, kExprCallFunction, static_cast<byte>(js_index)); |
| 208 |
| 209 for (int i = 0; i < num_params; i++) { |
| 210 ADD_CODE(code, WASM_F64(inputs.arg_d(i))); |
| 211 } |
| 212 |
| 213 size_t end = code.size(); |
| 214 code.push_back(0); |
| 215 t.Build(&code[0], &code[end]); |
| 216 } |
| 217 |
| 218 Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); |
| 219 double expected = inputs.arg_d(which); |
| 220 EXPECT_CALL(expected, jsfunc, 0.0, 0.0); |
| 221 } |
| 222 } |
| 223 |
| 224 |
| 225 TEST(Run_JSSelect_0) { RunJSSelectTest(0); } |
| 226 |
| 227 TEST(Run_JSSelect_1) { RunJSSelectTest(1); } |
| 228 |
| 229 TEST(Run_JSSelect_2) { RunJSSelectTest(2); } |
| 230 |
| 231 TEST(Run_JSSelect_3) { RunJSSelectTest(3); } |
| 232 |
| 233 TEST(Run_JSSelect_4) { RunJSSelectTest(4); } |
| 234 |
| 235 TEST(Run_JSSelect_5) { RunJSSelectTest(5); } |
| 236 |
| 237 TEST(Run_JSSelect_6) { RunJSSelectTest(6); } |
| 238 |
| 239 TEST(Run_JSSelect_7) { RunJSSelectTest(7); } |
| 240 |
| 241 |
| 242 void RunWASMSelectTest(int which) { |
| 243 PredictableInputValues inputs(0x200); |
| 244 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 245 const int kMaxParams = 8; |
| 246 for (int num_params = which + 1; num_params < kMaxParams; num_params++) { |
| 247 LocalType type = kAstF64; |
| 248 LocalType types[kMaxParams + 1] = {type, type, type, type, type, |
| 249 type, type, type, type}; |
| 250 FunctionSig sig(1, num_params, types); |
| 251 |
| 252 TestingModule module; |
| 253 WasmFunctionCompiler t(&sig, &module); |
| 254 BUILD(t, WASM_GET_LOCAL(which)); |
| 255 Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); |
| 256 |
| 257 Handle<Object> args[] = { |
| 258 isolate->factory()->NewNumber(inputs.arg_d(0)), |
| 259 isolate->factory()->NewNumber(inputs.arg_d(1)), |
| 260 isolate->factory()->NewNumber(inputs.arg_d(2)), |
| 261 isolate->factory()->NewNumber(inputs.arg_d(3)), |
| 262 isolate->factory()->NewNumber(inputs.arg_d(4)), |
| 263 isolate->factory()->NewNumber(inputs.arg_d(5)), |
| 264 isolate->factory()->NewNumber(inputs.arg_d(6)), |
| 265 isolate->factory()->NewNumber(inputs.arg_d(7)), |
| 266 }; |
| 267 |
| 268 double expected = inputs.arg_d(which); |
| 269 EXPECT_CALL(expected, jsfunc, args, kMaxParams); |
| 270 } |
| 271 } |
| 272 |
| 273 |
| 274 TEST(Run_WASMSelect_0) { RunWASMSelectTest(0); } |
| 275 |
| 276 TEST(Run_WASMSelect_1) { RunWASMSelectTest(1); } |
| 277 |
| 278 TEST(Run_WASMSelect_2) { RunWASMSelectTest(2); } |
| 279 |
| 280 TEST(Run_WASMSelect_3) { RunWASMSelectTest(3); } |
| 281 |
| 282 TEST(Run_WASMSelect_4) { RunWASMSelectTest(4); } |
| 283 |
| 284 TEST(Run_WASMSelect_5) { RunWASMSelectTest(5); } |
| 285 |
| 286 TEST(Run_WASMSelect_6) { RunWASMSelectTest(6); } |
| 287 |
| 288 TEST(Run_WASMSelect_7) { RunWASMSelectTest(7); } |
| 289 |
| 290 |
| 291 void RunWASMSelectAlignTest(int num_args, int num_params) { |
| 292 PredictableInputValues inputs(0x300); |
| 293 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 294 const int kMaxParams = 4; |
| 295 DCHECK_LE(num_args, kMaxParams); |
| 296 LocalType type = kAstF64; |
| 297 LocalType types[kMaxParams + 1] = {type, type, type, type, type}; |
| 298 FunctionSig sig(1, num_params, types); |
| 299 |
| 300 for (int which = 0; which < num_params; which++) { |
| 301 TestingModule module; |
| 302 WasmFunctionCompiler t(&sig, &module); |
| 303 BUILD(t, WASM_GET_LOCAL(which)); |
| 304 Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); |
| 305 |
| 306 Handle<Object> args[] = { |
| 307 isolate->factory()->NewNumber(inputs.arg_d(0)), |
| 308 isolate->factory()->NewNumber(inputs.arg_d(1)), |
| 309 isolate->factory()->NewNumber(inputs.arg_d(2)), |
| 310 isolate->factory()->NewNumber(inputs.arg_d(3)), |
| 311 }; |
| 312 |
| 313 double nan = std::numeric_limits<double>::quiet_NaN(); |
| 314 double expected = which < num_args ? inputs.arg_d(which) : nan; |
| 315 EXPECT_CALL(expected, jsfunc, args, num_args); |
| 316 } |
| 317 } |
| 318 |
| 319 |
| 320 TEST(Run_WASMSelectAlign_0) { |
| 321 RunWASMSelectAlignTest(0, 1); |
| 322 RunWASMSelectAlignTest(0, 2); |
| 323 } |
| 324 |
| 325 |
| 326 TEST(Run_WASMSelectAlign_1) { |
| 327 RunWASMSelectAlignTest(1, 2); |
| 328 RunWASMSelectAlignTest(1, 3); |
| 329 } |
| 330 |
| 331 |
| 332 TEST(Run_WASMSelectAlign_2) { |
| 333 RunWASMSelectAlignTest(2, 3); |
| 334 RunWASMSelectAlignTest(2, 4); |
| 335 } |
| 336 |
| 337 |
| 338 TEST(Run_WASMSelectAlign_3) { |
| 339 RunWASMSelectAlignTest(3, 3); |
| 340 RunWASMSelectAlignTest(3, 4); |
| 341 } |
| 342 |
| 343 |
| 344 TEST(Run_WASMSelectAlign_4) { |
| 345 RunWASMSelectAlignTest(4, 3); |
| 346 RunWASMSelectAlignTest(4, 4); |
| 347 } |
| 348 |
| 349 |
| 350 void RunJSSelectAlignTest(int num_args, int num_params) { |
| 351 PredictableInputValues inputs(0x400); |
| 352 Isolate* isolate = CcTest::InitIsolateOnce(); |
| 353 Factory* factory = isolate->factory(); |
| 354 const int kMaxParams = 4; |
| 355 CHECK_LE(num_args, kMaxParams); |
| 356 CHECK_LE(num_params, kMaxParams); |
| 357 LocalType type = kAstF64; |
| 358 LocalType types[kMaxParams + 1] = {type, type, type, type, type}; |
| 359 FunctionSig sig(1, num_params, types); |
| 360 |
| 361 // Build the calling code. |
| 362 std::vector<byte> code; |
| 363 ADD_CODE(code, kExprCallFunction, 0); |
| 364 |
| 365 for (int i = 0; i < num_params; i++) { |
| 366 ADD_CODE(code, WASM_GET_LOCAL(i)); |
| 367 } |
| 368 |
| 369 size_t end = code.size(); |
| 370 code.push_back(0); |
| 371 |
| 372 // Call different select JS functions. |
| 373 for (int which = 0; which < num_params; which++) { |
| 374 HandleScope scope(isolate); |
| 375 TestingModule module; |
| 376 uint32_t js_index = AddJSSelector(&module, &sig, which); |
| 377 CHECK_EQ(0, js_index); |
| 378 WasmFunctionCompiler t(&sig, &module); |
| 379 t.Build(&code[0], &code[end]); |
| 380 |
| 381 Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); |
| 382 |
| 383 Handle<Object> args[] = { |
| 384 factory->NewNumber(inputs.arg_d(0)), |
| 385 factory->NewNumber(inputs.arg_d(1)), |
| 386 factory->NewNumber(inputs.arg_d(2)), |
| 387 factory->NewNumber(inputs.arg_d(3)), |
| 388 }; |
| 389 |
| 390 double nan = std::numeric_limits<double>::quiet_NaN(); |
| 391 double expected = which < num_args ? inputs.arg_d(which) : nan; |
| 392 EXPECT_CALL(expected, jsfunc, args, num_args); |
| 393 } |
| 394 } |
| 395 |
| 396 |
| 397 TEST(Run_JSSelectAlign_0) { |
| 398 RunJSSelectAlignTest(0, 1); |
| 399 RunJSSelectAlignTest(0, 2); |
| 400 } |
| 401 |
| 402 |
| 403 TEST(Run_JSSelectAlign_2) { |
| 404 RunJSSelectAlignTest(2, 3); |
| 405 RunJSSelectAlignTest(2, 4); |
| 406 } |
| 407 |
| 408 |
| 409 TEST(Run_JSSelectAlign_4) { |
| 410 RunJSSelectAlignTest(4, 3); |
| 411 RunJSSelectAlignTest(4, 4); |
| 412 } |
| 413 |
| 414 |
| 415 #if !V8_TARGET_ARCH_ARM64 |
| 416 // TODO(titzer): dynamic frame alignment on arm64 |
| 417 TEST(Run_JSSelectAlign_1) { |
| 418 RunJSSelectAlignTest(1, 2); |
| 419 RunJSSelectAlignTest(1, 3); |
| 420 } |
| 421 |
| 422 |
| 423 TEST(Run_JSSelectAlign_3) { |
| 424 RunJSSelectAlignTest(3, 3); |
| 425 RunJSSelectAlignTest(3, 4); |
| 426 } |
| 427 #endif |
OLD | NEW |