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 |