| 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 79 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   90     int virtual_register = *i; |   90     int virtual_register = *i; | 
|   91     if (sequence.IsDouble(virtual_register)) { |   91     if (sequence.IsDouble(virtual_register)) { | 
|   92       EXPECT_FALSE(sequence.IsReference(virtual_register)); |   92       EXPECT_FALSE(sequence.IsReference(virtual_register)); | 
|   93       s.doubles_.insert(virtual_register); |   93       s.doubles_.insert(virtual_register); | 
|   94     } |   94     } | 
|   95     if (sequence.IsReference(virtual_register)) { |   95     if (sequence.IsReference(virtual_register)) { | 
|   96       EXPECT_FALSE(sequence.IsDouble(virtual_register)); |   96       EXPECT_FALSE(sequence.IsDouble(virtual_register)); | 
|   97       s.references_.insert(virtual_register); |   97       s.references_.insert(virtual_register); | 
|   98     } |   98     } | 
|   99   } |   99   } | 
|  100   for (int i = 0; i < sequence.GetDeoptimizationEntryCount(); i++) { |  100   for (int i = 0; i < sequence.GetFrameStateDescriptorCount(); i++) { | 
|  101     s.deoptimization_entries_.push_back(sequence.GetDeoptimizationEntry(i)); |  101     s.deoptimization_entries_.push_back(sequence.GetFrameStateDescriptor( | 
 |  102         InstructionSequence::StateId::FromInt(i))); | 
|  102   } |  103   } | 
|  103   return s; |  104   return s; | 
|  104 } |  105 } | 
|  105  |  106  | 
|  106  |  107  | 
|  107 // ----------------------------------------------------------------------------- |  108 // ----------------------------------------------------------------------------- | 
|  108 // Return. |  109 // Return. | 
|  109  |  110  | 
|  110  |  111  | 
|  111 TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) { |  112 TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) { | 
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  316  |  317  | 
|  317 // ----------------------------------------------------------------------------- |  318 // ----------------------------------------------------------------------------- | 
|  318 // Calls with deoptimization. |  319 // Calls with deoptimization. | 
|  319 TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { |  320 TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { | 
|  320   StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged); |  321   StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged); | 
|  321  |  322  | 
|  322   BailoutId bailout_id(42); |  323   BailoutId bailout_id(42); | 
|  323  |  324  | 
|  324   Node* function_node = m.Parameter(0); |  325   Node* function_node = m.Parameter(0); | 
|  325   Node* receiver = m.Parameter(1); |  326   Node* receiver = m.Parameter(1); | 
|  326   StreamBuilder::Label deopt, cont; |  | 
|  327  |  | 
|  328   // TODO(jarin) Add frame state. |  | 
|  329   Node* call = m.CallJS0(function_node, receiver, &cont, &deopt); |  | 
|  330  |  | 
|  331   m.Bind(&cont); |  | 
|  332   m.NewNode(m.common()->Continuation(), call); |  | 
|  333   m.Return(call); |  | 
|  334  |  | 
|  335   m.Bind(&deopt); |  | 
|  336   m.NewNode(m.common()->LazyDeoptimization(), call); |  | 
|  337  |  327  | 
|  338   Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1)); |  328   Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1)); | 
|  339   Node* locals = m.NewNode(m.common()->StateValues(0)); |  329   Node* locals = m.NewNode(m.common()->StateValues(0)); | 
|  340   Node* stack = m.NewNode(m.common()->StateValues(0)); |  330   Node* stack = m.NewNode(m.common()->StateValues(0)); | 
 |  331   Node* context_dummy = m.Int32Constant(0); | 
|  341  |  332  | 
|  342   Node* state_node = |  333   Node* state_node = m.NewNode(m.common()->FrameState(bailout_id, PUSH_OUTPUT), | 
|  343       m.NewNode(m.common()->FrameState(bailout_id), parameters, locals, stack); |  334                                parameters, locals, stack, context_dummy); | 
|  344   m.Deoptimize(state_node); |  335   Node* call = m.CallJS0(function_node, receiver, state_node); | 
 |  336   m.Return(call); | 
|  345  |  337  | 
|  346   Stream s = m.Build(kAllExceptNopInstructions); |  338   Stream s = m.Build(kAllExceptNopInstructions); | 
|  347  |  339  | 
|  348   // Skip until kArchCallJSFunction. |  340   // Skip until kArchCallJSFunction. | 
|  349   size_t index = 0; |  341   size_t index = 0; | 
|  350   for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction; |  342   for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction; | 
|  351        index++) { |  343        index++) { | 
|  352   } |  344   } | 
|  353   // Now we should have three instructions: call, return and deoptimize. |  345   // Now we should have two instructions: call and return. | 
|  354   ASSERT_EQ(index + 3, s.size()); |  346   ASSERT_EQ(index + 2, s.size()); | 
|  355  |  347  | 
|  356   EXPECT_EQ(kArchCallJSFunction, s[index++]->arch_opcode()); |  348   EXPECT_EQ(kArchCallJSFunction, s[index++]->arch_opcode()); | 
|  357   EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); |  349   EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); | 
|  358   EXPECT_EQ(kArchDeoptimize, s[index++]->arch_opcode()); |  350  | 
|  359   EXPECT_EQ(index, s.size()); |  351   // TODO(jarin) Check deoptimization table. | 
|  360 } |  352 } | 
|  361  |  353  | 
|  362  |  354  | 
|  363 TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { |  355 TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { | 
|  364   StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged, |  356   StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged, | 
|  365                   kMachAnyTagged); |  357                   kMachAnyTagged); | 
|  366  |  358  | 
|  367   BailoutId bailout_id_before(42); |  359   BailoutId bailout_id_before(42); | 
|  368   BailoutId bailout_id_after(54); |  | 
|  369  |  360  | 
|  370   // Some arguments for the call node. |  361   // Some arguments for the call node. | 
|  371   Node* function_node = m.Parameter(0); |  362   Node* function_node = m.Parameter(0); | 
|  372   Node* receiver = m.Parameter(1); |  363   Node* receiver = m.Parameter(1); | 
|  373   Node* context = m.Int32Constant(1);  // Context is ignored. |  364   Node* context = m.Int32Constant(1);  // Context is ignored. | 
|  374  |  365  | 
|  375   // Build frame state for the state before the call. |  366   // Build frame state for the state before the call. | 
|  376   Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); |  367   Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); | 
|  377   Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44)); |  368   Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44)); | 
|  378   Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45)); |  369   Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45)); | 
|  379   Node* frame_state_before = m.NewNode( |  370   Node* context_sentinel = m.Int32Constant(0); | 
|  380       m.common()->FrameState(bailout_id_before), parameters, locals, stack); |  371   Node* frame_state_before = | 
 |  372       m.NewNode(m.common()->FrameState(bailout_id_before, PUSH_OUTPUT), | 
 |  373                 parameters, locals, stack, context_sentinel); | 
|  381  |  374  | 
|  382   StreamBuilder::Label deopt, cont; |  | 
|  383   // Build the call. |  375   // Build the call. | 
|  384   Node* call = |  376   Node* call = m.CallFunctionStub0(function_node, receiver, context, | 
|  385       m.CallFunctionStub0(function_node, receiver, context, frame_state_before, |  377                                    frame_state_before, CALL_AS_METHOD); | 
|  386                           &cont, &deopt, CALL_AS_METHOD); |  | 
|  387  |  378  | 
|  388   // Create the continuation branch. |  | 
|  389   m.Bind(&cont); |  | 
|  390   m.NewNode(m.common()->Continuation(), call); |  | 
|  391   m.Return(call); |  379   m.Return(call); | 
|  392  |  380  | 
|  393   // Create the lazy deoptimization block (with a different frame state). |  | 
|  394   m.Bind(&deopt); |  | 
|  395   m.NewNode(m.common()->LazyDeoptimization(), call); |  | 
|  396  |  | 
|  397   Node* stack_after = |  | 
|  398       m.NewNode(m.common()->StateValues(2), m.Int32Constant(55), call); |  | 
|  399  |  | 
|  400   Node* frame_state_after = m.NewNode(m.common()->FrameState(bailout_id_after), |  | 
|  401                                       parameters, locals, stack_after); |  | 
|  402   m.Deoptimize(frame_state_after); |  | 
|  403  |  | 
|  404   Stream s = m.Build(kAllExceptNopInstructions); |  381   Stream s = m.Build(kAllExceptNopInstructions); | 
|  405  |  382  | 
|  406   // Skip until kArchCallJSFunction. |  383   // Skip until kArchCallJSFunction. | 
|  407   size_t index = 0; |  384   size_t index = 0; | 
|  408   for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; |  385   for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; | 
|  409        index++) { |  386        index++) { | 
|  410   } |  387   } | 
|  411   // Now we should have three instructions: call, return and deoptimize. |  388   // Now we should have two instructions: call, return. | 
|  412   ASSERT_EQ(index + 3, s.size()); |  389   ASSERT_EQ(index + 2, s.size()); | 
|  413  |  390  | 
|  414   // Check the call instruction |  391   // Check the call instruction | 
|  415   const Instruction* call_instr = s[index++]; |  392   const Instruction* call_instr = s[index++]; | 
|  416   EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); |  393   EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); | 
|  417   size_t num_operands = |  394   size_t num_operands = | 
|  418       1 +  // Code object. |  395       1 +  // Code object. | 
|  419       1 + |  396       1 + | 
|  420       3 +  // Frame state deopt id + one input for each value in frame state. |  397       4 +  // Frame state deopt id + one input for each value in frame state. | 
|  421       1 +  // Function. |  398       1 +  // Function. | 
|  422       1 +  // Context. |  399       1;   // Context. | 
|  423       2;   // Continuation and deoptimization block labels. |  | 
|  424   ASSERT_EQ(num_operands, call_instr->InputCount()); |  400   ASSERT_EQ(num_operands, call_instr->InputCount()); | 
|  425  |  401  | 
|  426   // Code object. |  402   // Code object. | 
|  427   EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); |  403   EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); | 
|  428  |  404  | 
|  429   // Deoptimization id. |  405   // Deoptimization id. | 
|  430   int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); |  406   int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); | 
|  431   FrameStateDescriptor* desc_before = s.GetDeoptimizationEntry(deopt_id_before); |  407   FrameStateDescriptor* desc_before = | 
 |  408       s.GetFrameStateDescriptor(deopt_id_before); | 
|  432   EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); |  409   EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); | 
 |  410   EXPECT_EQ(PUSH_OUTPUT, desc_before->state_combine()); | 
|  433   EXPECT_EQ(1, desc_before->parameters_count()); |  411   EXPECT_EQ(1, desc_before->parameters_count()); | 
|  434   EXPECT_EQ(1, desc_before->locals_count()); |  412   EXPECT_EQ(1, desc_before->locals_count()); | 
|  435   EXPECT_EQ(1, desc_before->stack_count()); |  413   EXPECT_EQ(1, desc_before->stack_count()); | 
|  436   EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2))); |  414   EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2))); | 
|  437   EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(3))); |  415   EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3))); | 
|  438   EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(4))); |  416   EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(4))); | 
 |  417   EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(5))); | 
|  439  |  418  | 
|  440   // Function. |  419   // Function. | 
|  441   EXPECT_EQ(function_node->id(), s.ToVreg(call_instr->InputAt(5))); |  420   EXPECT_EQ(function_node->id(), s.ToVreg(call_instr->InputAt(6))); | 
|  442   // Context. |  421   // Context. | 
|  443   EXPECT_EQ(context->id(), s.ToVreg(call_instr->InputAt(6))); |  422   EXPECT_EQ(context->id(), s.ToVreg(call_instr->InputAt(7))); | 
|  444   // Continuation. |  | 
|  445   EXPECT_EQ(cont.block()->id(), s.ToInt32(call_instr->InputAt(7))); |  | 
|  446   // Deoptimization. |  | 
|  447   EXPECT_EQ(deopt.block()->id(), s.ToInt32(call_instr->InputAt(8))); |  | 
|  448  |  423  | 
|  449   EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); |  424   EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); | 
|  450  |  425  | 
|  451   // Check the deoptimize instruction. |  | 
|  452   const Instruction* deopt_instr = s[index++]; |  | 
|  453   EXPECT_EQ(kArchDeoptimize, deopt_instr->arch_opcode()); |  | 
|  454   ASSERT_EQ(5U, deopt_instr->InputCount()); |  | 
|  455   int32_t deopt_id_after = s.ToInt32(deopt_instr->InputAt(0)); |  | 
|  456   FrameStateDescriptor* desc_after = s.GetDeoptimizationEntry(deopt_id_after); |  | 
|  457   EXPECT_EQ(bailout_id_after, desc_after->bailout_id()); |  | 
|  458   EXPECT_EQ(1, desc_after->parameters_count()); |  | 
|  459   EXPECT_EQ(1, desc_after->locals_count()); |  | 
|  460   EXPECT_EQ(2, desc_after->stack_count()); |  | 
|  461   // Parameter value from the frame state. |  | 
|  462   EXPECT_EQ(43, s.ToInt32(deopt_instr->InputAt(1))); |  | 
|  463   EXPECT_EQ(44, s.ToInt32(deopt_instr->InputAt(2))); |  | 
|  464   EXPECT_EQ(55, s.ToInt32(deopt_instr->InputAt(3))); |  | 
|  465   EXPECT_EQ(call->id(), s.ToVreg(deopt_instr->InputAt(4))); |  | 
|  466   EXPECT_EQ(index, s.size()); |  426   EXPECT_EQ(index, s.size()); | 
|  467 } |  427 } | 
|  468  |  428  | 
|  469 }  // namespace compiler |  429 }  // namespace compiler | 
|  470 }  // namespace internal |  430 }  // namespace internal | 
|  471 }  // namespace v8 |  431 }  // namespace v8 | 
| OLD | NEW |