Chromium Code Reviews| 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 |