Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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 "test/compiler-unittests/instruction-selector-unittest.h" | 5 #include "test/compiler-unittests/instruction-selector-unittest.h" |
| 6 | 6 |
| 7 #include "src/flags.h" | 7 #include "src/flags.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 332 m.NewNode(m.common()->Continuation(), call); | 332 m.NewNode(m.common()->Continuation(), call); |
| 333 m.Return(call); | 333 m.Return(call); |
| 334 | 334 |
| 335 m.Bind(&deopt); | 335 m.Bind(&deopt); |
| 336 m.NewNode(m.common()->LazyDeoptimization(), call); | 336 m.NewNode(m.common()->LazyDeoptimization(), call); |
| 337 | 337 |
| 338 Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1)); | 338 Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1)); |
| 339 Node* locals = m.NewNode(m.common()->StateValues(0)); | 339 Node* locals = m.NewNode(m.common()->StateValues(0)); |
| 340 Node* stack = m.NewNode(m.common()->StateValues(0)); | 340 Node* stack = m.NewNode(m.common()->StateValues(0)); |
| 341 | 341 |
| 342 Node* state_node = | 342 Node* state_node = m.NewNode(m.common()->FrameState(bailout_id), parameters, |
| 343 m.NewNode(m.common()->FrameState(bailout_id), parameters, locals, stack); | 343 locals, stack, m.UndefinedConstant()); |
| 344 m.Deoptimize(state_node); | 344 m.Deoptimize(state_node); |
| 345 | 345 |
| 346 Stream s = m.Build(kAllExceptNopInstructions); | 346 Stream s = m.Build(kAllExceptNopInstructions); |
| 347 | 347 |
| 348 // Skip until kArchCallJSFunction. | 348 // Skip until kArchCallJSFunction. |
| 349 size_t index = 0; | 349 size_t index = 0; |
| 350 for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction; | 350 for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction; |
| 351 index++) { | 351 index++) { |
| 352 } | 352 } |
| 353 // Now we should have three instructions: call, return and deoptimize. | 353 // Now we should have three instructions: call, return and deoptimize. |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 369 | 369 |
| 370 // Some arguments for the call node. | 370 // Some arguments for the call node. |
| 371 Node* function_node = m.Parameter(0); | 371 Node* function_node = m.Parameter(0); |
| 372 Node* receiver = m.Parameter(1); | 372 Node* receiver = m.Parameter(1); |
| 373 Node* context = m.Int32Constant(1); // Context is ignored. | 373 Node* context = m.Int32Constant(1); // Context is ignored. |
| 374 | 374 |
| 375 // Build frame state for the state before the call. | 375 // Build frame state for the state before the call. |
| 376 Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); | 376 Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); |
| 377 Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44)); | 377 Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44)); |
| 378 Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45)); | 378 Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45)); |
| 379 Node* frame_state_before = m.NewNode( | 379 Node* frame_state_before = |
| 380 m.common()->FrameState(bailout_id_before), parameters, locals, stack); | 380 m.NewNode(m.common()->FrameState(bailout_id_before), parameters, locals, |
| 381 stack, m.UndefinedConstant()); | |
| 381 | 382 |
| 382 StreamBuilder::Label deopt, cont; | 383 StreamBuilder::Label deopt, cont; |
| 383 // Build the call. | 384 // Build the call. |
| 384 Node* call = | 385 Node* call = |
| 385 m.CallFunctionStub0(function_node, receiver, context, frame_state_before, | 386 m.CallFunctionStub0(function_node, receiver, context, frame_state_before, |
| 386 &cont, &deopt, CALL_AS_METHOD); | 387 &cont, &deopt, CALL_AS_METHOD); |
| 387 | 388 |
| 388 // Create the continuation branch. | 389 // Create the continuation branch. |
| 389 m.Bind(&cont); | 390 m.Bind(&cont); |
| 390 m.NewNode(m.common()->Continuation(), call); | 391 m.NewNode(m.common()->Continuation(), call); |
| 391 m.Return(call); | 392 m.Return(call); |
| 392 | 393 |
| 393 // Create the lazy deoptimization block (with a different frame state). | 394 // Create the lazy deoptimization block (with a different frame state). |
| 394 m.Bind(&deopt); | 395 m.Bind(&deopt); |
| 395 m.NewNode(m.common()->LazyDeoptimization(), call); | 396 m.NewNode(m.common()->LazyDeoptimization(), call); |
| 396 | 397 |
| 397 Node* stack_after = | 398 Node* stack_after = |
| 398 m.NewNode(m.common()->StateValues(2), m.Int32Constant(55), call); | 399 m.NewNode(m.common()->StateValues(2), m.Int32Constant(55), call); |
| 399 | 400 |
| 400 Node* frame_state_after = m.NewNode(m.common()->FrameState(bailout_id_after), | 401 Node* frame_state_after = |
| 401 parameters, locals, stack_after); | 402 m.NewNode(m.common()->FrameState(bailout_id_after), parameters, locals, |
| 403 stack_after, m.UndefinedConstant()); | |
| 402 m.Deoptimize(frame_state_after); | 404 m.Deoptimize(frame_state_after); |
| 403 | 405 |
| 404 Stream s = m.Build(kAllExceptNopInstructions); | 406 Stream s = m.Build(kAllExceptNopInstructions); |
| 405 | 407 |
| 406 // Skip until kArchCallJSFunction. | 408 // Skip until kArchCallJSFunction. |
| 407 size_t index = 0; | 409 size_t index = 0; |
| 408 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; | 410 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; |
| 409 index++) { | 411 index++) { |
| 410 } | 412 } |
| 411 // Now we should have three instructions: call, return and deoptimize. | 413 // Now we should have three instructions: call, return and deoptimize. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 459 EXPECT_EQ(1, desc_after->locals_count()); | 461 EXPECT_EQ(1, desc_after->locals_count()); |
| 460 EXPECT_EQ(2, desc_after->stack_count()); | 462 EXPECT_EQ(2, desc_after->stack_count()); |
| 461 // Parameter value from the frame state. | 463 // Parameter value from the frame state. |
| 462 EXPECT_EQ(43, s.ToInt32(deopt_instr->InputAt(1))); | 464 EXPECT_EQ(43, s.ToInt32(deopt_instr->InputAt(1))); |
| 463 EXPECT_EQ(44, s.ToInt32(deopt_instr->InputAt(2))); | 465 EXPECT_EQ(44, s.ToInt32(deopt_instr->InputAt(2))); |
| 464 EXPECT_EQ(55, s.ToInt32(deopt_instr->InputAt(3))); | 466 EXPECT_EQ(55, s.ToInt32(deopt_instr->InputAt(3))); |
| 465 EXPECT_EQ(call->id(), s.ToVreg(deopt_instr->InputAt(4))); | 467 EXPECT_EQ(call->id(), s.ToVreg(deopt_instr->InputAt(4))); |
| 466 EXPECT_EQ(index, s.size()); | 468 EXPECT_EQ(index, s.size()); |
| 467 } | 469 } |
| 468 | 470 |
| 471 | |
| 472 TARGET_TEST_F(InstructionSelectorTest, | |
| 473 CallFunctionStubDeoptRecursiveFrameState) { | |
| 474 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged, | |
| 475 kMachAnyTagged); | |
| 476 | |
| 477 BailoutId bailout_id_before(42); | |
| 478 BailoutId bailout_id_after(54); | |
| 479 BailoutId bailout_id_parent(62); | |
| 480 | |
| 481 // Some arguments for the call node. | |
| 482 Node* function_node = m.Parameter(0); | |
| 483 Node* receiver = m.Parameter(1); | |
| 484 Node* context = m.Int32Constant(1); // Context is ignored. | |
| 485 | |
| 486 // Build frame state for the state before the call. | |
| 487 Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63)); | |
| 488 Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64)); | |
| 489 Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65)); | |
| 490 Node* frame_state_parent = | |
| 491 m.NewNode(m.common()->FrameState(bailout_id_parent), parameters, locals, | |
| 492 stack, m.UndefinedConstant()); | |
| 493 | |
| 494 Node* parameters2 = | |
| 495 m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); | |
| 496 Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44)); | |
| 497 Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45)); | |
| 498 Node* frame_state_before = | |
| 499 m.NewNode(m.common()->FrameState(bailout_id_before), parameters2, locals2, | |
| 500 stack2, frame_state_parent); | |
| 501 | |
| 502 StreamBuilder::Label deopt, cont; | |
| 503 // Build the call. | |
| 504 Node* call = | |
| 505 m.CallFunctionStub0(function_node, receiver, context, frame_state_before, | |
| 506 &cont, &deopt, CALL_AS_METHOD); | |
| 507 | |
| 508 // Create the continuation branch. | |
| 509 m.Bind(&cont); | |
| 510 m.NewNode(m.common()->Continuation(), call); | |
| 511 m.Return(call); | |
| 512 | |
| 513 // Create the lazy deoptimization block (with a different frame state). | |
| 514 m.Bind(&deopt); | |
| 515 m.NewNode(m.common()->LazyDeoptimization(), call); | |
| 516 | |
| 517 Node* parameters3 = | |
| 518 m.NewNode(m.common()->StateValues(1), m.Int32Constant(53)); | |
| 519 Node* locals3 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(54)); | |
| 520 Node* stack_after = | |
| 521 m.NewNode(m.common()->StateValues(2), m.Int32Constant(55), call); | |
| 522 | |
| 523 Node* frame_state_after = | |
| 524 m.NewNode(m.common()->FrameState(bailout_id_after), parameters3, locals3, | |
| 525 stack_after, m.UndefinedConstant()); | |
| 526 m.Deoptimize(frame_state_after); | |
| 527 | |
| 528 Stream s = m.Build(kAllExceptNopInstructions); | |
| 529 | |
| 530 // Skip until kArchCallJSFunction. | |
| 531 size_t index = 0; | |
| 532 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; | |
| 533 index++) { | |
| 534 } | |
| 535 // Now we should have three instructions: call, return and deoptimize. | |
| 536 ASSERT_EQ(index + 3, s.size()); | |
| 537 | |
| 538 // Check the call instruction | |
| 539 const Instruction* call_instr = s[index++]; | |
| 540 EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); | |
| 541 size_t num_operands = | |
| 542 1 + // Code object. | |
| 543 1 + // Frame state deopt id | |
| 544 3 + // One input for each value in frame state. | |
| 545 3 + // One input for each value in the parent frame state. | |
| 546 1 + // Function. | |
| 547 1 + // Context. | |
| 548 2; // Continuation and deoptimization block labels. | |
| 549 ASSERT_EQ(num_operands, call_instr->InputCount()); | |
| 550 | |
| 551 // Code object. | |
| 552 EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); | |
| 553 | |
| 554 // Deoptimization id. | |
| 555 int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); | |
| 556 FrameStateDescriptor* desc_before = s.GetDeoptimizationEntry(deopt_id_before); | |
| 557 EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); | |
| 558 EXPECT_EQ(1, desc_before->parameters_count()); | |
| 559 EXPECT_EQ(1, desc_before->locals_count()); | |
| 560 EXPECT_EQ(1, desc_before->stack_count()); | |
| 561 EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2))); | |
|
Jarin
2014/08/29 15:07:07
Hmm, could we put the parent values first here?
sigurds
2014/09/01 08:48:18
Done.
| |
| 562 EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(3))); | |
| 563 EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(4))); | |
| 564 // Values from parent environment should follow. | |
| 565 EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(5))); | |
| 566 EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(6))); | |
| 567 EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(7))); | |
| 568 | |
| 569 // Function. | |
| 570 EXPECT_EQ(function_node->id(), s.ToVreg(call_instr->InputAt(8))); | |
| 571 // Context. | |
| 572 EXPECT_EQ(context->id(), s.ToVreg(call_instr->InputAt(9))); | |
| 573 // Continuation. | |
| 574 EXPECT_EQ(cont.block()->id(), s.ToInt32(call_instr->InputAt(10))); | |
| 575 // Deoptimization. | |
| 576 EXPECT_EQ(deopt.block()->id(), s.ToInt32(call_instr->InputAt(11))); | |
| 577 | |
| 578 EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); | |
| 579 | |
| 580 // Check the deoptimize instruction. | |
| 581 const Instruction* deopt_instr = s[index++]; | |
| 582 EXPECT_EQ(kArchDeoptimize, deopt_instr->arch_opcode()); | |
| 583 ASSERT_EQ(5U, deopt_instr->InputCount()); | |
| 584 int32_t deopt_id_after = s.ToInt32(deopt_instr->InputAt(0)); | |
| 585 FrameStateDescriptor* desc_after = s.GetDeoptimizationEntry(deopt_id_after); | |
| 586 EXPECT_EQ(bailout_id_after, desc_after->bailout_id()); | |
| 587 EXPECT_EQ(1, desc_after->parameters_count()); | |
| 588 EXPECT_EQ(1, desc_after->locals_count()); | |
| 589 EXPECT_EQ(2, desc_after->stack_count()); | |
| 590 // Parameter value from the frame state. | |
| 591 EXPECT_EQ(53, s.ToInt32(deopt_instr->InputAt(1))); | |
| 592 EXPECT_EQ(54, s.ToInt32(deopt_instr->InputAt(2))); | |
| 593 EXPECT_EQ(55, s.ToInt32(deopt_instr->InputAt(3))); | |
| 594 EXPECT_EQ(call->id(), s.ToVreg(deopt_instr->InputAt(4))); | |
| 595 EXPECT_EQ(index, s.size()); | |
| 596 } | |
| 597 | |
| 469 } // namespace compiler | 598 } // namespace compiler |
| 470 } // namespace internal | 599 } // namespace internal |
| 471 } // namespace v8 | 600 } // namespace v8 |
| OLD | NEW |