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 3// found in the LICENSE file. 4 5#include "test/unittests/compiler/instruction-selector-unittest.h" 6 7#include "src/code-factory.h" 8#include "src/compiler/graph.h" 9#include "src/compiler/schedule.h" 10#include "src/flags.h" 11#include "test/unittests/compiler/compiler-test-utils.h" 12 13namespace v8 { 14namespace internal { 15namespace compiler { 16 17 18InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {} 19 20 21InstructionSelectorTest::~InstructionSelectorTest() {} 22 23 24InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( 25 InstructionSelector::Features features, 26 InstructionSelectorTest::StreamBuilderMode mode, 27 InstructionSelector::SourcePositionMode source_position_mode) { 28 Schedule* schedule = Export(); 29 if (FLAG_trace_turbo) { 30 OFStream out(stdout); 31 out << "=== Schedule before instruction selection ===" << std::endl 32 << *schedule; 33 } 34 size_t const node_count = graph()->NodeCount(); 35 EXPECT_NE(0u, node_count); 36 Linkage linkage(call_descriptor()); 37 InstructionBlocks* instruction_blocks = 38 InstructionSequence::InstructionBlocksFor(test_->zone(), schedule); 39 InstructionSequence sequence(test_->isolate(), test_->zone(), 40 instruction_blocks); 41 SourcePositionTable source_position_table(graph()); 42 InstructionSelector selector(test_->zone(), node_count, &linkage, &sequence, 43 schedule, &source_position_table, nullptr, 44 source_position_mode, features); 45 selector.SelectInstructions(); 46 if (FLAG_trace_turbo) { 47 OFStream out(stdout); 48 PrintableInstructionSequence printable = {RegisterConfiguration::Turbofan(), 49 &sequence}; 50 out << "=== Code sequence after instruction selection ===" << std::endl 51 << printable; 52 } 53 Stream s; 54 s.virtual_registers_ = selector.GetVirtualRegistersForTesting(); 55 // Map virtual registers. 56 for (Instruction* const instr : sequence) { 57 if (instr->opcode() < 0) continue; 58 if (mode == kTargetInstructions) { 59 switch (instr->arch_opcode()) { 60#define CASE(Name) \ 61 case k##Name: \ 62 break; 63 TARGET_ARCH_OPCODE_LIST(CASE) 64#undef CASE 65 default: 66 continue; 67 } 68 } 69 if (mode == kAllExceptNopInstructions && instr->arch_opcode() == kArchNop) { 70 continue; 71 } 72 for (size_t i = 0; i < instr->OutputCount(); ++i) { 73 InstructionOperand* output = instr->OutputAt(i); 74 EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind()); 75 if (output->IsConstant()) { 76 int vreg = ConstantOperand::cast(output)->virtual_register(); 77 s.constants_.insert(std::make_pair(vreg, sequence.GetConstant(vreg))); 78 } 79 } 80 for (size_t i = 0; i < instr->InputCount(); ++i) { 81 InstructionOperand* input = instr->InputAt(i); 82 EXPECT_NE(InstructionOperand::CONSTANT, input->kind()); 83 if (input->IsImmediate()) { 84 auto imm = ImmediateOperand::cast(input); 85 if (imm->type() == ImmediateOperand::INDEXED) { 86 int index = imm->indexed_value(); 87 s.immediates_.insert( 88 std::make_pair(index, sequence.GetImmediate(imm))); 89 } 90 } 91 } 92 s.instructions_.push_back(instr); 93 } 94 for (auto i : s.virtual_registers_) { 95 int const virtual_register = i.second; 96 if (sequence.IsFP(virtual_register)) { 97 EXPECT_FALSE(sequence.IsReference(virtual_register)); 98 s.doubles_.insert(virtual_register); 99 } 100 if (sequence.IsReference(virtual_register)) { 101 EXPECT_FALSE(sequence.IsFP(virtual_register)); 102 s.references_.insert(virtual_register); 103 } 104 } 105 for (int i = 0; i < sequence.GetFrameStateDescriptorCount(); i++) { 106 s.deoptimization_entries_.push_back(sequence.GetFrameStateDescriptor( 107 InstructionSequence::StateId::FromInt(i))); 108 } 109 return s; 110} 111 112 113int InstructionSelectorTest::Stream::ToVreg(const Node* node) const { 114 VirtualRegisters::const_iterator i = virtual_registers_.find(node->id()); 115 CHECK(i != virtual_registers_.end()); 116 return i->second; 117} 118 119 120bool InstructionSelectorTest::Stream::IsFixed(const InstructionOperand* operand, 121 Register reg) const { 122 if (!operand->IsUnallocated()) return false; 123 const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand); 124 if (!unallocated->HasFixedRegisterPolicy()) return false; 125 return unallocated->fixed_register_index() == reg.code(); 126} 127 128 129bool InstructionSelectorTest::Stream::IsSameAsFirst( 130 const InstructionOperand* operand) const { 131 if (!operand->IsUnallocated()) return false; 132 const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand); 133 return unallocated->HasSameAsInputPolicy(); 134} 135 136 137bool InstructionSelectorTest::Stream::IsUsedAtStart( 138 const InstructionOperand* operand) const { 139 if (!operand->IsUnallocated()) return false; 140 const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand); 141 return unallocated->IsUsedAtStart(); 142} 143 144 145const FrameStateFunctionInfo* 146InstructionSelectorTest::StreamBuilder::GetFrameStateFunctionInfo( 147 int parameter_count, int local_count) { 148 return common()->CreateFrameStateFunctionInfo( 149 FrameStateType::kJavaScriptFunction, parameter_count, local_count, 150 Handle<SharedFunctionInfo>()); 151} 152 153 154// ----------------------------------------------------------------------------- 155// Return. 156 157 158TARGET_TEST_F(InstructionSelectorTest, ReturnFloat32Constant) { 159 const float kValue = 4.2f; 160 StreamBuilder m(this, MachineType::Float32()); 161 m.Return(m.Float32Constant(kValue)); 162 Stream s = m.Build(kAllInstructions); 163 ASSERT_EQ(3U, s.size()); 164 EXPECT_EQ(kArchNop, s[0]->arch_opcode()); 165 ASSERT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind()); 166 EXPECT_FLOAT_EQ(kValue, s.ToFloat32(s[0]->OutputAt(0))); 167 EXPECT_EQ(kArchRet, s[1]->arch_opcode()); 168 EXPECT_EQ(1U, s[1]->InputCount()); 169} 170 171 172TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) { 173 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); 174 m.Return(m.Parameter(0)); 175 Stream s = m.Build(kAllInstructions); 176 ASSERT_EQ(3U, s.size()); 177 EXPECT_EQ(kArchNop, s[0]->arch_opcode()); 178 ASSERT_EQ(1U, s[0]->OutputCount()); 179 EXPECT_EQ(kArchRet, s[1]->arch_opcode()); 180 EXPECT_EQ(1U, s[1]->InputCount()); 181} 182 183 184TARGET_TEST_F(InstructionSelectorTest, ReturnZero) { 185 StreamBuilder m(this, MachineType::Int32()); 186 m.Return(m.Int32Constant(0)); 187 Stream s = m.Build(kAllInstructions); 188 ASSERT_EQ(3U, s.size()); 189 EXPECT_EQ(kArchNop, s[0]->arch_opcode()); 190 ASSERT_EQ(1U, s[0]->OutputCount()); 191 EXPECT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind()); 192 EXPECT_EQ(0, s.ToInt32(s[0]->OutputAt(0))); 193 EXPECT_EQ(kArchRet, s[1]->arch_opcode()); 194 EXPECT_EQ(1U, s[1]->InputCount()); 195} 196 197 198// ----------------------------------------------------------------------------- 199// Conversions. 200 201TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToWord32WithParameter) { 202 StreamBuilder m(this, MachineType::Int32(), MachineType::Float64()); 203 m.Return(m.TruncateFloat64ToWord32(m.Parameter(0))); 204 Stream s = m.Build(kAllInstructions); 205 ASSERT_EQ(4U, s.size()); 206 EXPECT_EQ(kArchNop, s[0]->arch_opcode()); 207 EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode()); 208 EXPECT_EQ(1U, s[1]->InputCount()); 209 EXPECT_EQ(1U, s[1]->OutputCount()); 210 EXPECT_EQ(kArchRet, s[2]->arch_opcode()); 211} 212 213 214// ----------------------------------------------------------------------------- 215// Parameters. 216 217 218TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) { 219 StreamBuilder m(this, MachineType::Float64(), MachineType::Float64()); 220 Node* param = m.Parameter(0); 221 m.Return(param); 222 Stream s = m.Build(kAllInstructions); 223 EXPECT_TRUE(s.IsDouble(param)); 224} 225 226 227TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) { 228 StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged()); 229 Node* param = m.Parameter(0); 230 m.Return(param); 231 Stream s = m.Build(kAllInstructions); 232 EXPECT_TRUE(s.IsReference(param)); 233} 234 235 236// ----------------------------------------------------------------------------- 237// FinishRegion. 238 239 240TARGET_TEST_F(InstructionSelectorTest, FinishRegion) { 241 StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged()); 242 Node* param = m.Parameter(0); 243 Node* finish = 244 m.AddNode(m.common()->FinishRegion(), param, m.graph()->start()); 245 m.Return(finish); 246 Stream s = m.Build(kAllInstructions); 247 ASSERT_EQ(4U, s.size()); 248 EXPECT_EQ(kArchNop, s[0]->arch_opcode()); 249 ASSERT_EQ(1U, s[0]->OutputCount()); 250 ASSERT_TRUE(s[0]->Output()->IsUnallocated()); 251 EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->Output())); 252 EXPECT_EQ(kArchNop, s[1]->arch_opcode()); 253 ASSERT_EQ(1U, s[1]->InputCount()); 254 ASSERT_TRUE(s[1]->InputAt(0)->IsUnallocated()); 255 EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[1]->InputAt(0))); 256 ASSERT_EQ(1U, s[1]->OutputCount()); 257 ASSERT_TRUE(s[1]->Output()->IsUnallocated()); 258 EXPECT_TRUE(UnallocatedOperand::cast(s[1]->Output())->HasSameAsInputPolicy()); 259 EXPECT_EQ(s.ToVreg(finish), s.ToVreg(s[1]->Output())); 260 EXPECT_TRUE(s.IsReference(finish)); 261} 262 263 264// ----------------------------------------------------------------------------- 265// Phi. 266 267 268typedef InstructionSelectorTestWithParam<MachineType> 269 InstructionSelectorPhiTest; 270 271 272TARGET_TEST_P(InstructionSelectorPhiTest, Doubleness) { 273 const MachineType type = GetParam(); 274 StreamBuilder m(this, type, type, type); 275 Node* param0 = m.Parameter(0); 276 Node* param1 = m.Parameter(1); 277 RawMachineLabel a, b, c; 278 m.Branch(m.Int32Constant(0), &a, &b); 279 m.Bind(&a); 280 m.Goto(&c); 281 m.Bind(&b); 282 m.Goto(&c); 283 m.Bind(&c); 284 Node* phi = m.Phi(type.representation(), param0, param1); 285 m.Return(phi); 286 Stream s = m.Build(kAllInstructions); 287 EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param0)); 288 EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param1)); 289} 290 291 292TARGET_TEST_P(InstructionSelectorPhiTest, Referenceness) { 293 const MachineType type = GetParam(); 294 StreamBuilder m(this, type, type, type); 295 Node* param0 = m.Parameter(0); 296 Node* param1 = m.Parameter(1); 297 RawMachineLabel a, b, c; 298 m.Branch(m.Int32Constant(1), &a, &b); 299 m.Bind(&a); 300 m.Goto(&c); 301 m.Bind(&b); 302 m.Goto(&c); 303 m.Bind(&c); 304 Node* phi = m.Phi(type.representation(), param0, param1); 305 m.Return(phi); 306 Stream s = m.Build(kAllInstructions); 307 EXPECT_EQ(s.IsReference(phi), s.IsReference(param0)); 308 EXPECT_EQ(s.IsReference(phi), s.IsReference(param1)); 309} 310 311 312INSTANTIATE_TEST_CASE_P( 313 InstructionSelectorTest, InstructionSelectorPhiTest, 314 ::testing::Values(MachineType::Float64(), MachineType::Int8(), 315 MachineType::Uint8(), MachineType::Int16(), 316 MachineType::Uint16(), MachineType::Int32(), 317 MachineType::Uint32(), MachineType::Int64(), 318 MachineType::Uint64(), MachineType::Pointer(), 319 MachineType::AnyTagged())); 320 321 322// ----------------------------------------------------------------------------- 323// ValueEffect. 324 325 326TARGET_TEST_F(InstructionSelectorTest, ValueEffect) { 327 StreamBuilder m1(this, MachineType::Int32(), MachineType::Pointer()); 328 Node* p1 = m1.Parameter(0); 329 m1.Return(m1.Load(MachineType::Int32(), p1, m1.Int32Constant(0))); 330 Stream s1 = m1.Build(kAllInstructions); 331 StreamBuilder m2(this, MachineType::Int32(), MachineType::Pointer()); 332 Node* p2 = m2.Parameter(0); 333 m2.Return(m2.AddNode( 334 m2.machine()->Load(MachineType::Int32()), p2, m2.Int32Constant(0), 335 m2.AddNode(m2.common()->BeginRegion(RegionObservability::kObservable), 336 m2.graph()->start()))); 337 Stream s2 = m2.Build(kAllInstructions); 338 EXPECT_LE(3U, s1.size()); 339 ASSERT_EQ(s1.size(), s2.size()); 340 TRACED_FORRANGE(size_t, i, 0, s1.size() - 1) { 341 const Instruction* i1 = s1[i]; 342 const Instruction* i2 = s2[i]; 343 EXPECT_EQ(i1->arch_opcode(), i2->arch_opcode()); 344 EXPECT_EQ(i1->InputCount(), i2->InputCount()); 345 EXPECT_EQ(i1->OutputCount(), i2->OutputCount()); 346 } 347} 348 349 350// ----------------------------------------------------------------------------- 351// Calls with deoptimization. 352 353 354TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { 355 StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged(), 356 MachineType::AnyTagged(), MachineType::AnyTagged()); 357 358 BailoutId bailout_id(42); 359 360 Node* function_node = m.Parameter(0); 361 Node* receiver = m.Parameter(1); 362 Node* context = m.Parameter(2); 363 364 ZoneVector<MachineType> int32_type(1, MachineType::Int32(), zone()); 365 ZoneVector<MachineType> empty_types(zone()); 366 367 CallDescriptor* descriptor = Linkage::GetJSCallDescriptor( 368 zone(), false, 1, CallDescriptor::kNeedsFrameState); 369 370 // Build frame state for the state before the call. 371 Node* parameters = 372 m.AddNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(1)); 373 Node* locals = m.AddNode(m.common()->TypedStateValues(&empty_types)); 374 Node* stack = m.AddNode(m.common()->TypedStateValues(&empty_types)); 375 Node* context_sentinel = m.Int32Constant(0); 376 Node* state_node = m.AddNode( 377 m.common()->FrameState(bailout_id, OutputFrameStateCombine::Push(), 378 m.GetFrameStateFunctionInfo(1, 0)), 379 parameters, locals, stack, context_sentinel, function_node, 380 m.UndefinedConstant()); 381 382 // Build the call. 383 Node* args[] = {receiver, m.UndefinedConstant(), m.Int32Constant(1), context}; 384 Node* call = 385 m.CallNWithFrameState(descriptor, function_node, args, state_node); 386 m.Return(call); 387 388 Stream s = m.Build(kAllExceptNopInstructions); 389 390 // Skip until kArchCallJSFunction. 391 size_t index = 0; 392 for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction; 393 index++) { 394 } 395 // Now we should have two instructions: call and return. 396 ASSERT_EQ(index + 2, s.size()); 397 398 EXPECT_EQ(kArchCallJSFunction, s[index++]->arch_opcode()); 399 EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); 400 401 // TODO(jarin) Check deoptimization table. 402} 403 404 405TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeopt) { 406 StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged(), 407 MachineType::AnyTagged(), MachineType::AnyTagged()); 408 409 BailoutId bailout_id_before(42); 410 411 // Some arguments for the call node. 412 Node* function_node = m.Parameter(0); 413 Node* receiver = m.Parameter(1); 414 Node* context = m.Int32Constant(1); // Context is ignored. 415 416 ZoneVector<MachineType> int32_type(1, MachineType::Int32(), zone()); 417 ZoneVector<MachineType> float64_type(1, MachineType::Float64(), zone()); 418 ZoneVector<MachineType> tagged_type(1, MachineType::AnyTagged(), zone()); 419 420 Callable callable = CodeFactory::ToObject(isolate()); 421 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( 422 isolate(), zone(), callable.descriptor(), 1, 423 CallDescriptor::kNeedsFrameState, Operator::kNoProperties); 424 425 // Build frame state for the state before the call. 426 Node* parameters = 427 m.AddNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43)); 428 Node* locals = m.AddNode(m.common()->TypedStateValues(&float64_type), 429 m.Float64Constant(0.5)); 430 Node* stack = m.AddNode(m.common()->TypedStateValues(&tagged_type), 431 m.UndefinedConstant()); 432 Node* context_sentinel = m.Int32Constant(0); 433 Node* state_node = m.AddNode( 434 m.common()->FrameState(bailout_id_before, OutputFrameStateCombine::Push(), 435 m.GetFrameStateFunctionInfo(1, 1)), 436 parameters, locals, stack, context_sentinel, function_node, 437 m.UndefinedConstant()); 438 439 // Build the call. 440 Node* args[] = {function_node, receiver, context}; 441 Node* stub_code = m.HeapConstant(callable.code()); 442 Node* call = m.CallNWithFrameState(descriptor, stub_code, args, state_node); 443 m.Return(call); 444 445 Stream s = m.Build(kAllExceptNopInstructions); 446 447 // Skip until kArchCallJSFunction. 448 size_t index = 0; 449 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; 450 index++) { 451 } 452 // Now we should have two instructions: call, return. 453 ASSERT_EQ(index + 2, s.size()); 454 455 // Check the call instruction 456 const Instruction* call_instr = s[index++]; 457 EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); 458 size_t num_operands = 459 1 + // Code object. 460 1 + 461 5 + // Frame state deopt id + one input for each value in frame state. 462 1 + // Function. 463 1; // Context. 464 ASSERT_EQ(num_operands, call_instr->InputCount()); 465 466 // Code object. 467 EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); 468 469 // Deoptimization id. 470 int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); 471 FrameStateDescriptor* desc_before = 472 s.GetFrameStateDescriptor(deopt_id_before); 473 EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); 474 EXPECT_EQ(OutputFrameStateCombine::kPushOutput, 475 desc_before->state_combine().kind()); 476 EXPECT_EQ(1u, desc_before->parameters_count()); 477 EXPECT_EQ(1u, desc_before->locals_count()); 478 EXPECT_EQ(1u, desc_before->stack_count()); 479 EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(3))); 480 EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(4))); // This should be a context. 481 // We inserted 0 here. 482 EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(5))); 483 EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(6))->IsUndefined(isolate())); 484 EXPECT_EQ(MachineType::AnyTagged(), 485 desc_before->GetType(0)); // function is always 486 // tagged/any. 487 EXPECT_EQ(MachineType::Int32(), desc_before->GetType(1)); 488 EXPECT_EQ(MachineType::AnyTagged(), 489 desc_before->GetType(2)); // context is always 490 // tagged/any. 491 EXPECT_EQ(MachineType::Float64(), desc_before->GetType(3)); 492 EXPECT_EQ(MachineType::AnyTagged(), desc_before->GetType(4)); 493 494 // Function. 495 EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(7))); 496 // Context. 497 EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(8))); 498 499 EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); 500 501 EXPECT_EQ(index, s.size()); 502} 503 504 505TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeoptRecursiveFrameState) { 506 StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged(), 507 MachineType::AnyTagged(), MachineType::AnyTagged()); 508 509 BailoutId bailout_id_before(42); 510 BailoutId bailout_id_parent(62); 511 512 // Some arguments for the call node. 513 Node* function_node = m.Parameter(0); 514 Node* receiver = m.Parameter(1); 515 Node* context = m.Int32Constant(66); 516 Node* context2 = m.Int32Constant(46); 517 518 ZoneVector<MachineType> int32_type(1, MachineType::Int32(), zone()); 519 ZoneVector<MachineType> int32x2_type(2, MachineType::Int32(), zone()); 520 ZoneVector<MachineType> float64_type(1, MachineType::Float64(), zone()); 521 522 Callable callable = CodeFactory::ToObject(isolate()); 523 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( 524 isolate(), zone(), callable.descriptor(), 1, 525 CallDescriptor::kNeedsFrameState, Operator::kNoProperties); 526 527 // Build frame state for the state before the call. 528 Node* parameters = 529 m.AddNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(63)); 530 Node* locals = 531 m.AddNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(64)); 532 Node* stack = 533 m.AddNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(65)); 534 Node* frame_state_parent = m.AddNode( 535 m.common()->FrameState(bailout_id_parent, 536 OutputFrameStateCombine::Ignore(), 537 m.GetFrameStateFunctionInfo(1, 1)), 538 parameters, locals, stack, context, function_node, m.UndefinedConstant()); 539 540 Node* parameters2 = 541 m.AddNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43)); 542 Node* locals2 = m.AddNode(m.common()->TypedStateValues(&float64_type), 543 m.Float64Constant(0.25)); 544 Node* stack2 = m.AddNode(m.common()->TypedStateValues(&int32x2_type), 545 m.Int32Constant(44), m.Int32Constant(45)); 546 Node* state_node = m.AddNode( 547 m.common()->FrameState(bailout_id_before, OutputFrameStateCombine::Push(), 548 m.GetFrameStateFunctionInfo(1, 1)), 549 parameters2, locals2, stack2, context2, function_node, 550 frame_state_parent); 551 552 // Build the call. 553 Node* args[] = {function_node, receiver, context2}; 554 Node* stub_code = m.HeapConstant(callable.code()); 555 Node* call = m.CallNWithFrameState(descriptor, stub_code, args, state_node); 556 m.Return(call); 557 558 Stream s = m.Build(kAllExceptNopInstructions); 559 560 // Skip until kArchCallJSFunction. 561 size_t index = 0; 562 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject; 563 index++) { 564 } 565 // Now we should have three instructions: call, return. 566 EXPECT_EQ(index + 2, s.size()); 567 568 // Check the call instruction 569 const Instruction* call_instr = s[index++]; 570 EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode()); 571 size_t num_operands = 572 1 + // Code object. 573 1 + // Frame state deopt id 574 6 + // One input for each value in frame state + context. 575 5 + // One input for each value in the parent frame state + context. 576 1 + // Function. 577 1; // Context. 578 EXPECT_EQ(num_operands, call_instr->InputCount()); 579 // Code object. 580 EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate()); 581 582 // Deoptimization id. 583 int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1)); 584 FrameStateDescriptor* desc_before = 585 s.GetFrameStateDescriptor(deopt_id_before); 586 FrameStateDescriptor* desc_before_outer = desc_before->outer_state(); 587 EXPECT_EQ(bailout_id_before, desc_before->bailout_id()); 588 EXPECT_EQ(1u, desc_before_outer->parameters_count()); 589 EXPECT_EQ(1u, desc_before_outer->locals_count()); 590 EXPECT_EQ(1u, desc_before_outer->stack_count()); 591 // Values from parent environment. 592 EXPECT_EQ(MachineType::AnyTagged(), desc_before->GetType(0)); 593 EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(3))); 594 EXPECT_EQ(MachineType::Int32(), desc_before_outer->GetType(1)); 595 // Context: 596 EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(4))); 597 EXPECT_EQ(MachineType::AnyTagged(), desc_before_outer->GetType(2)); 598 EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(5))); 599 EXPECT_EQ(MachineType::Int32(), desc_before_outer->GetType(3)); 600 EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(6))); 601 EXPECT_EQ(MachineType::Int32(), desc_before_outer->GetType(4)); 602 // Values from the nested frame. 603 EXPECT_EQ(1u, desc_before->parameters_count()); 604 EXPECT_EQ(1u, desc_before->locals_count()); 605 EXPECT_EQ(2u, desc_before->stack_count()); 606 EXPECT_EQ(MachineType::AnyTagged(), desc_before->GetType(0)); 607 EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(8))); 608 EXPECT_EQ(MachineType::Int32(), desc_before->GetType(1)); 609 EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(9))); 610 EXPECT_EQ(MachineType::AnyTagged(), desc_before->GetType(2)); 611 EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(10))); 612 EXPECT_EQ(MachineType::Float64(), desc_before->GetType(3)); 613 EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(11))); 614 EXPECT_EQ(MachineType::Int32(), desc_before->GetType(4)); 615 EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(12))); 616 EXPECT_EQ(MachineType::Int32(), desc_before->GetType(5)); 617 618 // Function. 619 EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(13))); 620 // Context. 621 EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(14))); 622 // Continuation. 623 624 EXPECT_EQ(kArchRet, s[index++]->arch_opcode()); 625 EXPECT_EQ(index, s.size()); 626} 627 628} // namespace compiler 629} // namespace internal 630} // namespace v8 631