OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // 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 | 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 #ifndef WASM_RUN_UTILS_H | 5 #ifndef WASM_RUN_UTILS_H |
6 #define WASM_RUN_UTILS_H | 6 #define WASM_RUN_UTILS_H |
7 | 7 |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 #include <stdlib.h> | 9 #include <stdlib.h> |
10 #include <string.h> | 10 #include <string.h> |
11 | 11 |
12 #include "src/base/utils/random-number-generator.h" | 12 #include "src/base/utils/random-number-generator.h" |
13 | 13 |
14 #include "src/compiler/graph-visualizer.h" | 14 #include "src/compiler/graph-visualizer.h" |
15 #include "src/compiler/int64-lowering.h" | 15 #include "src/compiler/int64-lowering.h" |
16 #include "src/compiler/js-graph.h" | 16 #include "src/compiler/js-graph.h" |
17 #include "src/compiler/node.h" | |
18 #include "src/compiler/pipeline.h" | |
17 #include "src/compiler/wasm-compiler.h" | 19 #include "src/compiler/wasm-compiler.h" |
18 | 20 |
19 #include "src/wasm/ast-decoder.h" | 21 #include "src/wasm/ast-decoder.h" |
20 #include "src/wasm/wasm-js.h" | 22 #include "src/wasm/wasm-js.h" |
21 #include "src/wasm/wasm-module.h" | 23 #include "src/wasm/wasm-module.h" |
22 #include "src/wasm/wasm-opcodes.h" | 24 #include "src/wasm/wasm-opcodes.h" |
23 | 25 |
26 #include "src/zone.h" | |
27 | |
24 #include "test/cctest/cctest.h" | 28 #include "test/cctest/cctest.h" |
25 #include "test/cctest/compiler/codegen-tester.h" | 29 #include "test/cctest/compiler/call-tester.h" |
26 #include "test/cctest/compiler/graph-builder-tester.h" | 30 #include "test/cctest/compiler/graph-builder-tester.h" |
27 | 31 |
28 // TODO(titzer): pull WASM_64 up to a common header. | 32 // TODO(titzer): pull WASM_64 up to a common header. |
29 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 | 33 #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 |
30 #define WASM_64 1 | 34 #define WASM_64 1 |
31 #else | 35 #else |
32 #define WASM_64 0 | 36 #define WASM_64 0 |
33 #endif | 37 #endif |
34 | 38 |
35 // TODO(titzer): check traps more robustly in tests. | 39 // TODO(titzer): check traps more robustly in tests. |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 str << ", msg = " << result.error_msg.get(); | 243 str << ", msg = " << result.error_msg.get(); |
240 FATAL(str.str().c_str()); | 244 FATAL(str.str().c_str()); |
241 } | 245 } |
242 builder.Int64LoweringForTesting(); | 246 builder.Int64LoweringForTesting(); |
243 if (FLAG_trace_turbo_graph) { | 247 if (FLAG_trace_turbo_graph) { |
244 OFStream os(stdout); | 248 OFStream os(stdout); |
245 os << AsRPO(*jsgraph->graph()); | 249 os << AsRPO(*jsgraph->graph()); |
246 } | 250 } |
247 } | 251 } |
248 | 252 |
253 template <typename ReturnType> | |
254 class WasmFunctionWrapper : public HandleAndZoneScope, | |
255 private GraphAndBuilders { | |
256 public: | |
257 WasmFunctionWrapper() | |
258 : GraphAndBuilders(main_zone()), | |
259 inner_code_node_(nullptr), | |
260 signature_(nullptr) { | |
261 Signature<MachineType>::Builder sig_builder(zone(), 1, 5); | |
262 | |
263 sig_builder.AddReturn(MachineType::Int32()); | |
264 for (int i = 0; i < 5; i++) { | |
265 sig_builder.AddParam(MachineType::Pointer()); | |
266 } | |
267 signature_ = sig_builder.Build(); | |
268 } | |
269 | |
270 void Init(CallDescriptor* descriptor, MachineType p0 = MachineType::None(), | |
271 MachineType p1 = MachineType::None(), | |
272 MachineType p2 = MachineType::None(), | |
273 MachineType p3 = MachineType::None()) { | |
274 // Create the TF graph for the wrapper. The wrapper always takes four | |
275 // pointers as parameters, but may not pass the values of all pointers to | |
276 // the actual test function. | |
277 | |
278 // Function, effect, and control. | |
279 Node** parameters = zone()->template NewArray<Node*>(4 + 3); | |
280 graph()->SetStart(graph()->NewNode(common()->Start(6))); | |
281 Node* effect = graph()->start(); | |
282 int parameter_count = 0; | |
283 | |
284 // Dummy node which gets replaced in SetInnerCode. | |
285 inner_code_node_ = graph()->NewNode(common()->Int32Constant(0)); | |
286 parameters[parameter_count++] = inner_code_node_; | |
287 | |
288 if (p0 != MachineType::None()) { | |
289 parameters[parameter_count] = graph()->NewNode( | |
290 machine()->Load(p0), | |
291 graph()->NewNode(common()->Parameter(0), graph()->start()), | |
292 graph()->NewNode(common()->Int32Constant(0)), effect, | |
293 graph()->start()); | |
294 effect = parameters[parameter_count++]; | |
295 } | |
296 if (p1 != MachineType::None()) { | |
297 parameters[parameter_count] = graph()->NewNode( | |
298 machine()->Load(p0), | |
299 graph()->NewNode(common()->Parameter(1), graph()->start()), | |
300 graph()->NewNode(common()->Int32Constant(0)), effect, | |
301 graph()->start()); | |
302 effect = parameters[parameter_count++]; | |
303 } | |
304 if (p2 != MachineType::None()) { | |
305 parameters[parameter_count] = graph()->NewNode( | |
306 machine()->Load(p0), | |
307 graph()->NewNode(common()->Parameter(2), graph()->start()), | |
308 graph()->NewNode(common()->Int32Constant(0)), effect, | |
309 graph()->start()); | |
310 effect = parameters[parameter_count++]; | |
311 } | |
312 if (p3 != MachineType::None()) { | |
313 parameters[parameter_count] = graph()->NewNode( | |
314 machine()->Load(p0), | |
315 graph()->NewNode(common()->Parameter(3), graph()->start()), | |
316 graph()->NewNode(common()->Int32Constant(0)), effect, | |
317 graph()->start()); | |
318 effect = parameters[parameter_count++]; | |
319 } | |
320 | |
321 parameters[parameter_count++] = effect; | |
322 parameters[parameter_count++] = graph()->start(); | |
323 Node* call = graph()->NewNode(common()->Call(descriptor), parameter_count, | |
324 parameters); | |
325 | |
326 effect = graph()->NewNode( | |
327 machine()->Store( | |
328 StoreRepresentation(MachineTypeForC<ReturnType>().representation(), | |
329 WriteBarrierKind::kNoWriteBarrier)), | |
330 graph()->NewNode(common()->Parameter(4), graph()->start()), | |
331 graph()->NewNode(common()->Int32Constant(0)), call, effect, | |
332 graph()->start()); | |
333 Node* r = graph()->NewNode(common()->Return(), | |
334 graph()->NewNode(common()->Int32Constant(7654)), | |
335 effect, graph()->start()); | |
336 graph()->SetEnd(graph()->NewNode(common()->End(2), r, graph()->start())); | |
337 } | |
338 | |
339 void SetInnerCode(Handle<Code> code_handle) { | |
340 NodeProperties::ChangeOp(inner_code_node_, | |
341 common()->HeapConstant(code_handle)); | |
342 } | |
343 | |
344 Handle<Code> GetWrapperCode() { | |
345 if (code_.is_null()) { | |
346 Isolate* isolate = CcTest::InitIsolateOnce(); | |
347 | |
348 CallDescriptor* descriptor = | |
349 Linkage::GetSimplifiedCDescriptor(zone(), signature_, true); | |
350 | |
351 CompilationInfo info("testing", isolate, graph()->zone()); | |
352 code_ = | |
353 Pipeline::GenerateCodeForTesting(&info, descriptor, graph(), nullptr); | |
354 CHECK(!code_.is_null()); | |
355 #ifdef ENABLE_DISASSEMBLER | |
356 if (FLAG_print_opt_code) { | |
357 OFStream os(stdout); | |
358 code_->Disassemble("wasm wrapper", os); | |
359 } | |
360 #endif | |
361 } | |
362 | |
363 return code_; | |
364 } | |
365 | |
366 Signature<MachineType>* signature() const { return signature_; } | |
367 | |
368 private: | |
369 Node* inner_code_node_; | |
370 Handle<Code> code_; | |
371 Signature<MachineType>* signature_; | |
372 }; | |
249 | 373 |
250 // A helper for compiling functions that are only internally callable WASM code. | 374 // A helper for compiling functions that are only internally callable WASM code. |
251 class WasmFunctionCompiler : public HandleAndZoneScope, | 375 class WasmFunctionCompiler : public HandleAndZoneScope, |
252 private GraphAndBuilders { | 376 private GraphAndBuilders { |
253 public: | 377 public: |
254 explicit WasmFunctionCompiler(FunctionSig* sig, ModuleEnv* module = nullptr) | 378 explicit WasmFunctionCompiler(FunctionSig* sig, ModuleEnv* module = nullptr) |
255 : GraphAndBuilders(main_zone()), | 379 : GraphAndBuilders(main_zone()), |
256 jsgraph(this->isolate(), this->graph(), this->common(), nullptr, | 380 jsgraph(this->isolate(), this->graph(), this->common(), nullptr, |
257 nullptr, this->machine()), | 381 nullptr, this->machine()), |
258 descriptor_(nullptr) { | 382 descriptor_(nullptr) { |
259 init_env(&env, sig); | 383 init_env(&env, sig); |
260 env.module = module; | 384 env.module = module; |
261 } | 385 } |
262 | 386 |
263 JSGraph jsgraph; | 387 JSGraph jsgraph; |
264 FunctionEnv env; | 388 FunctionEnv env; |
265 // The call descriptor is initialized when the function is compiled. | 389 // The call descriptor is initialized when the function is compiled. |
266 CallDescriptor* descriptor_; | 390 CallDescriptor* descriptor_; |
267 | 391 |
268 Isolate* isolate() { return main_isolate(); } | 392 Isolate* isolate() { return main_isolate(); } |
269 Graph* graph() const { return main_graph_; } | 393 Graph* graph() const { return main_graph_; } |
270 Zone* zone() const { return graph()->zone(); } | 394 Zone* zone() const { return graph()->zone(); } |
271 CommonOperatorBuilder* common() { return &main_common_; } | 395 CommonOperatorBuilder* common() { return &main_common_; } |
272 MachineOperatorBuilder* machine() { return &main_machine_; } | 396 MachineOperatorBuilder* machine() { return &main_machine_; } |
397 void InitializeDescriptor() { | |
398 if (descriptor_ == nullptr) { | |
399 descriptor_ = env.module->GetWasmCallDescriptor(main_zone(), env.sig); | |
400 } | |
401 } | |
273 CallDescriptor* descriptor() { return descriptor_; } | 402 CallDescriptor* descriptor() { return descriptor_; } |
274 | 403 |
275 void Build(const byte* start, const byte* end) { | 404 void Build(const byte* start, const byte* end) { |
276 TestBuildingGraph(main_zone(), &jsgraph, &env, start, end); | 405 TestBuildingGraph(main_zone(), &jsgraph, &env, start, end); |
277 } | 406 } |
278 | 407 |
279 byte AllocateLocal(LocalType type) { | 408 byte AllocateLocal(LocalType type) { |
280 int result = static_cast<int>(env.total_locals); | 409 int result = static_cast<int>(env.total_locals); |
281 env.AddLocals(type, 1); | 410 env.AddLocals(type, 1); |
282 byte b = static_cast<byte>(result); | 411 byte b = static_cast<byte>(result); |
283 CHECK_EQ(result, b); | 412 CHECK_EQ(result, b); |
284 return b; | 413 return b; |
285 } | 414 } |
286 | 415 |
287 Handle<Code> Compile(ModuleEnv* module) { | 416 Handle<Code> Compile(ModuleEnv* module) { |
288 descriptor_ = module->GetWasmCallDescriptor(this->zone(), env.sig); | 417 InitializeDescriptor(); |
289 CompilationInfo info("wasm compile", this->isolate(), this->zone()); | 418 CompilationInfo info("wasm compile", this->isolate(), this->zone()); |
290 Handle<Code> result = | 419 Handle<Code> result = |
291 Pipeline::GenerateCodeForTesting(&info, descriptor_, this->graph()); | 420 Pipeline::GenerateCodeForTesting(&info, descriptor_, this->graph()); |
292 #ifdef ENABLE_DISASSEMBLER | 421 #ifdef ENABLE_DISASSEMBLER |
293 if (!result.is_null() && FLAG_print_opt_code) { | 422 if (!result.is_null() && FLAG_print_opt_code) { |
294 OFStream os(stdout); | 423 OFStream os(stdout); |
295 result->Disassemble("wasm code", os); | 424 result->Disassemble("wasm code", os); |
296 } | 425 } |
297 #endif | 426 #endif |
298 | 427 |
(...skipping 17 matching lines...) Expand all Loading... | |
316 template <typename ReturnType> | 445 template <typename ReturnType> |
317 class WasmRunner { | 446 class WasmRunner { |
318 public: | 447 public: |
319 WasmRunner(MachineType p0 = MachineType::None(), | 448 WasmRunner(MachineType p0 = MachineType::None(), |
320 MachineType p1 = MachineType::None(), | 449 MachineType p1 = MachineType::None(), |
321 MachineType p2 = MachineType::None(), | 450 MachineType p2 = MachineType::None(), |
322 MachineType p3 = MachineType::None()) | 451 MachineType p3 = MachineType::None()) |
323 : signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, | 452 : signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, |
324 GetParameterCount(p0, p1, p2, p3), storage_), | 453 GetParameterCount(p0, p1, p2, p3), storage_), |
325 compiler_(&signature_), | 454 compiler_(&signature_), |
326 call_wrapper_(p0, p1, p2, p3), | |
327 compilation_done_(false) { | 455 compilation_done_(false) { |
328 int index = 0; | 456 int index = 0; |
329 MachineType ret = MachineTypeForC<ReturnType>(); | 457 MachineType ret = MachineTypeForC<ReturnType>(); |
330 if (ret != MachineType::None()) { | 458 if (ret != MachineType::None()) { |
331 storage_[index++] = WasmOpcodes::LocalTypeFor(ret); | 459 storage_[index++] = WasmOpcodes::LocalTypeFor(ret); |
332 } | 460 } |
333 if (p0 != MachineType::None()) | 461 if (p0 != MachineType::None()) |
334 storage_[index++] = WasmOpcodes::LocalTypeFor(p0); | 462 storage_[index++] = WasmOpcodes::LocalTypeFor(p0); |
335 if (p1 != MachineType::None()) | 463 if (p1 != MachineType::None()) |
336 storage_[index++] = WasmOpcodes::LocalTypeFor(p1); | 464 storage_[index++] = WasmOpcodes::LocalTypeFor(p1); |
337 if (p2 != MachineType::None()) | 465 if (p2 != MachineType::None()) |
338 storage_[index++] = WasmOpcodes::LocalTypeFor(p2); | 466 storage_[index++] = WasmOpcodes::LocalTypeFor(p2); |
339 if (p3 != MachineType::None()) | 467 if (p3 != MachineType::None()) |
340 storage_[index++] = WasmOpcodes::LocalTypeFor(p3); | 468 storage_[index++] = WasmOpcodes::LocalTypeFor(p3); |
469 | |
470 compiler_.InitializeDescriptor(); | |
471 wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3); | |
341 } | 472 } |
342 | 473 |
343 | 474 |
344 FunctionEnv* env() { return &compiler_.env; } | 475 FunctionEnv* env() { return &compiler_.env; } |
345 | 476 |
346 | 477 |
347 // Builds a graph from the given Wasm code, and generates the machine | 478 // Builds a graph from the given Wasm code, and generates the machine |
348 // code and call wrapper for that graph. This method must not be called | 479 // code and call wrapper for that graph. This method must not be called |
349 // more than once. | 480 // more than once. |
350 void Build(const byte* start, const byte* end) { | 481 void Build(const byte* start, const byte* end) { |
351 DCHECK(!compilation_done_); | 482 DCHECK(!compilation_done_); |
352 compilation_done_ = true; | 483 compilation_done_ = true; |
353 // Build the TF graph. | 484 // Build the TF graph. |
354 compiler_.Build(start, end); | 485 compiler_.Build(start, end); |
355 // Generate code. | 486 // Generate code. |
356 Handle<Code> code = compiler_.Compile(env()->module); | 487 Handle<Code> code = compiler_.Compile(env()->module); |
357 | 488 |
358 // Construct the call wrapper. | 489 wrapper_.SetInnerCode(code); |
359 Node* inputs[5]; | |
360 int input_count = 0; | |
361 inputs[input_count++] = call_wrapper_.HeapConstant(code); | |
362 for (size_t i = 0; i < signature_.parameter_count(); i++) { | |
363 inputs[input_count++] = call_wrapper_.Parameter(i); | |
364 } | |
365 | |
366 call_wrapper_.Return(call_wrapper_.AddNode( | |
367 call_wrapper_.common()->Call(compiler_.descriptor()), input_count, | |
368 inputs)); | |
369 } | 490 } |
370 | 491 |
371 ReturnType Call() { return call_wrapper_.Call(); } | 492 ReturnType Call() { return Call(nullptr, nullptr, nullptr, nullptr); } |
372 | 493 |
373 template <typename P0> | 494 template <typename P0> |
374 ReturnType Call(P0 p0) { | 495 ReturnType Call(P0 p0) { |
375 return call_wrapper_.Call(p0); | 496 return Call(p0, nullptr, nullptr, nullptr); |
376 } | 497 } |
377 | 498 |
378 template <typename P0, typename P1> | 499 template <typename P0, typename P1> |
379 ReturnType Call(P0 p0, P1 p1) { | 500 ReturnType Call(P0 p0, P1 p1) { |
380 return call_wrapper_.Call(p0, p1); | 501 return Call(p0, p1, nullptr, nullptr); |
381 } | 502 } |
382 | 503 |
383 template <typename P0, typename P1, typename P2> | 504 template <typename P0, typename P1, typename P2> |
384 ReturnType Call(P0 p0, P1 p1, P2 p2) { | 505 ReturnType Call(P0 p0, P1 p1, P2 p2) { |
385 return call_wrapper_.Call(p0, p1, p2); | 506 return Call(p0, p1, p2, nullptr); |
386 } | 507 } |
387 | 508 |
388 template <typename P0, typename P1, typename P2, typename P3> | 509 template <typename P0, typename P1, typename P2, typename P3> |
389 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) { | 510 ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) { |
390 return call_wrapper_.Call(p0, p1, p2, p3); | 511 CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(), |
512 wrapper_.GetWrapperCode(), wrapper_.signature()); | |
513 ReturnType return_value; | |
514 int32_t result = runner.Call<void*, void*, void*, void*, void*>( | |
515 &p0, &p1, &p2, &p3, &return_value); | |
516 CHECK_EQ(7654, result); | |
titzer
2016/02/18 08:18:49
Pull this constant out somewhere.
ahaas
2016/02/18 09:10:57
Done.
| |
517 return return_value; | |
391 } | 518 } |
392 | 519 |
393 byte AllocateLocal(LocalType type) { | 520 byte AllocateLocal(LocalType type) { |
394 int result = static_cast<int>(env()->total_locals); | 521 int result = static_cast<int>(env()->total_locals); |
395 env()->AddLocals(type, 1); | 522 env()->AddLocals(type, 1); |
396 byte b = static_cast<byte>(result); | 523 byte b = static_cast<byte>(result); |
397 CHECK_EQ(result, b); | 524 CHECK_EQ(result, b); |
398 return b; | 525 return b; |
399 } | 526 } |
400 | 527 |
401 private: | 528 private: |
402 LocalType storage_[5]; | 529 LocalType storage_[5]; |
403 FunctionSig signature_; | 530 FunctionSig signature_; |
404 WasmFunctionCompiler compiler_; | 531 WasmFunctionCompiler compiler_; |
405 BufferedRawMachineAssemblerTester<ReturnType> call_wrapper_; | 532 WasmFunctionWrapper<ReturnType> wrapper_; |
406 bool compilation_done_; | 533 bool compilation_done_; |
407 | 534 |
408 static size_t GetParameterCount(MachineType p0, MachineType p1, | 535 static size_t GetParameterCount(MachineType p0, MachineType p1, |
409 MachineType p2, MachineType p3) { | 536 MachineType p2, MachineType p3) { |
410 if (p0 == MachineType::None()) return 0; | 537 if (p0 == MachineType::None()) return 0; |
411 if (p1 == MachineType::None()) return 1; | 538 if (p1 == MachineType::None()) return 1; |
412 if (p2 == MachineType::None()) return 2; | 539 if (p2 == MachineType::None()) return 2; |
413 if (p3 == MachineType::None()) return 3; | 540 if (p3 == MachineType::None()) return 3; |
414 return 4; | 541 return 4; |
415 } | 542 } |
416 }; | 543 }; |
417 | 544 |
418 } // namespace | 545 } // namespace |
419 | 546 |
420 #endif | 547 #endif |
OLD | NEW |