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 "src/compiler/code-generator.h" | 5 #include "src/compiler/code-generator.h" |
6 | 6 |
7 #include "src/arm/macro-assembler-arm.h" | 7 #include "src/arm/macro-assembler-arm.h" |
8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
9 #include "src/compiler/code-generator-impl.h" | 9 #include "src/compiler/code-generator-impl.h" |
10 #include "src/compiler/gap-resolver.h" | 10 #include "src/compiler/gap-resolver.h" |
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 0, 1); \ | 408 0, 1); \ |
409 /* Move the result in the double result register. */ \ | 409 /* Move the result in the double result register. */ \ |
410 __ MovFromFloatResult(i.OutputDoubleRegister()); \ | 410 __ MovFromFloatResult(i.OutputDoubleRegister()); \ |
411 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ | 411 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ |
412 } while (0) | 412 } while (0) |
413 | 413 |
414 void CodeGenerator::AssembleDeconstructFrame() { | 414 void CodeGenerator::AssembleDeconstructFrame() { |
415 __ LeaveFrame(StackFrame::MANUAL); | 415 __ LeaveFrame(StackFrame::MANUAL); |
416 } | 416 } |
417 | 417 |
418 void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) { | 418 void CodeGenerator::AssemblePrepareTailCall() { |
419 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); | |
420 if (sp_slot_delta > 0) { | |
421 __ add(sp, sp, Operand(sp_slot_delta * kPointerSize)); | |
422 } | |
423 frame_access_state()->SetFrameAccessToDefault(); | |
424 } | |
425 | |
426 | |
427 void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) { | |
428 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); | |
429 if (sp_slot_delta < 0) { | |
430 __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize)); | |
431 frame_access_state()->IncreaseSPDelta(-sp_slot_delta); | |
432 } | |
433 if (frame_access_state()->has_frame()) { | 419 if (frame_access_state()->has_frame()) { |
434 if (FLAG_enable_embedded_constant_pool) { | 420 if (FLAG_enable_embedded_constant_pool) { |
435 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset)); | 421 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset)); |
436 } | 422 } |
437 __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); | 423 __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); |
438 __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 424 __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
439 } | 425 } |
440 frame_access_state()->SetFrameAccessToSP(); | 426 frame_access_state()->SetFrameAccessToSP(); |
441 } | 427 } |
442 | 428 |
(...skipping 15 matching lines...) Expand all Loading... |
458 __ ldr(caller_args_count_reg, | 444 __ ldr(caller_args_count_reg, |
459 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 445 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
460 __ SmiUntag(caller_args_count_reg); | 446 __ SmiUntag(caller_args_count_reg); |
461 | 447 |
462 ParameterCount callee_args_count(args_reg); | 448 ParameterCount callee_args_count(args_reg); |
463 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2, | 449 __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2, |
464 scratch3); | 450 scratch3); |
465 __ bind(&done); | 451 __ bind(&done); |
466 } | 452 } |
467 | 453 |
| 454 namespace { |
| 455 |
| 456 void FlushPendingPushRegisters(MacroAssembler* masm, |
| 457 FrameAccessState* frame_access_state, |
| 458 ZoneVector<Register>* pending_pushes) { |
| 459 switch (pending_pushes->size()) { |
| 460 case 0: |
| 461 break; |
| 462 case 1: |
| 463 masm->push((*pending_pushes)[0]); |
| 464 break; |
| 465 case 2: |
| 466 masm->Push((*pending_pushes)[0], (*pending_pushes)[1]); |
| 467 break; |
| 468 case 3: |
| 469 masm->Push((*pending_pushes)[0], (*pending_pushes)[1], |
| 470 (*pending_pushes)[2]); |
| 471 break; |
| 472 default: |
| 473 UNREACHABLE(); |
| 474 break; |
| 475 } |
| 476 frame_access_state->IncreaseSPDelta(pending_pushes->size()); |
| 477 pending_pushes->resize(0); |
| 478 } |
| 479 |
| 480 void AddPendingPushRegister(MacroAssembler* masm, |
| 481 FrameAccessState* frame_access_state, |
| 482 ZoneVector<Register>* pending_pushes, |
| 483 Register reg) { |
| 484 pending_pushes->push_back(reg); |
| 485 if (pending_pushes->size() == 3 || reg.is(ip)) { |
| 486 FlushPendingPushRegisters(masm, frame_access_state, pending_pushes); |
| 487 } |
| 488 } |
| 489 |
| 490 void AdjustStackPointerForTailCall( |
| 491 MacroAssembler* masm, FrameAccessState* state, int new_slot_above_sp, |
| 492 ZoneVector<Register>* pending_pushes = nullptr, |
| 493 bool allow_shrinkage = true) { |
| 494 int current_sp_offset = state->GetSPToFPSlotCount() + |
| 495 StandardFrameConstants::kFixedSlotCountAboveFp; |
| 496 int stack_slot_delta = new_slot_above_sp - current_sp_offset; |
| 497 if (stack_slot_delta > 0) { |
| 498 if (pending_pushes != nullptr) { |
| 499 FlushPendingPushRegisters(masm, state, pending_pushes); |
| 500 } |
| 501 masm->sub(sp, sp, Operand(stack_slot_delta * kPointerSize)); |
| 502 state->IncreaseSPDelta(stack_slot_delta); |
| 503 } else if (allow_shrinkage && stack_slot_delta < 0) { |
| 504 if (pending_pushes != nullptr) { |
| 505 FlushPendingPushRegisters(masm, state, pending_pushes); |
| 506 } |
| 507 masm->add(sp, sp, Operand(-stack_slot_delta * kPointerSize)); |
| 508 state->IncreaseSPDelta(stack_slot_delta); |
| 509 } |
| 510 } |
| 511 |
| 512 } // namespace |
| 513 |
| 514 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr, |
| 515 int first_unused_stack_slot) { |
| 516 CodeGenerator::PushTypeFlags flags(kImmediatePush | kScalarPush); |
| 517 ZoneVector<MoveOperands*> pushes(zone()); |
| 518 GetPushCompatibleMoves(instr, flags, &pushes); |
| 519 |
| 520 if (!pushes.empty() && |
| 521 (LocationOperand::cast(pushes.back()->destination()).index() + 1 == |
| 522 first_unused_stack_slot)) { |
| 523 ArmOperandConverter g(this, instr); |
| 524 ZoneVector<Register> pending_pushes(zone()); |
| 525 for (auto move : pushes) { |
| 526 LocationOperand destination_location( |
| 527 LocationOperand::cast(move->destination())); |
| 528 InstructionOperand source(move->source()); |
| 529 AdjustStackPointerForTailCall( |
| 530 masm(), frame_access_state(), |
| 531 destination_location.index() - pending_pushes.size(), |
| 532 &pending_pushes); |
| 533 if (source.IsStackSlot()) { |
| 534 LocationOperand source_location(LocationOperand::cast(source)); |
| 535 __ ldr(ip, g.SlotToMemOperand(source_location.index())); |
| 536 AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes, |
| 537 ip); |
| 538 } else if (source.IsRegister()) { |
| 539 LocationOperand source_location(LocationOperand::cast(source)); |
| 540 AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes, |
| 541 source_location.GetRegister()); |
| 542 } else if (source.IsImmediate()) { |
| 543 AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes, |
| 544 ip); |
| 545 } else { |
| 546 // Pushes of non-scalar data types is not supported. |
| 547 UNIMPLEMENTED(); |
| 548 } |
| 549 move->Eliminate(); |
| 550 } |
| 551 FlushPendingPushRegisters(masm(), frame_access_state(), &pending_pushes); |
| 552 } |
| 553 AdjustStackPointerForTailCall(masm(), frame_access_state(), |
| 554 first_unused_stack_slot, nullptr, false); |
| 555 } |
| 556 |
| 557 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr, |
| 558 int first_unused_stack_slot) { |
| 559 AdjustStackPointerForTailCall(masm(), frame_access_state(), |
| 560 first_unused_stack_slot); |
| 561 } |
| 562 |
468 // Assembles an instruction after register allocation, producing machine code. | 563 // Assembles an instruction after register allocation, producing machine code. |
469 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( | 564 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( |
470 Instruction* instr) { | 565 Instruction* instr) { |
471 ArmOperandConverter i(this, instr); | 566 ArmOperandConverter i(this, instr); |
472 | 567 |
473 __ MaybeCheckConstPool(); | 568 __ MaybeCheckConstPool(); |
474 InstructionCode opcode = instr->opcode(); | 569 InstructionCode opcode = instr->opcode(); |
475 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode); | 570 ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode); |
476 switch (arch_opcode) { | 571 switch (arch_opcode) { |
477 case kArchCallCodeObject: { | 572 case kArchCallCodeObject: { |
478 EnsureSpaceForLazyDeopt(); | 573 EnsureSpaceForLazyDeopt(); |
479 if (instr->InputAt(0)->IsImmediate()) { | 574 if (instr->InputAt(0)->IsImmediate()) { |
480 __ Call(Handle<Code>::cast(i.InputHeapObject(0)), | 575 __ Call(Handle<Code>::cast(i.InputHeapObject(0)), |
481 RelocInfo::CODE_TARGET); | 576 RelocInfo::CODE_TARGET); |
482 } else { | 577 } else { |
483 __ add(ip, i.InputRegister(0), | 578 __ add(ip, i.InputRegister(0), |
484 Operand(Code::kHeaderSize - kHeapObjectTag)); | 579 Operand(Code::kHeaderSize - kHeapObjectTag)); |
485 __ Call(ip); | 580 __ Call(ip); |
486 } | 581 } |
487 RecordCallPosition(instr); | 582 RecordCallPosition(instr); |
488 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 583 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
489 frame_access_state()->ClearSPDelta(); | 584 frame_access_state()->ClearSPDelta(); |
490 break; | 585 break; |
491 } | 586 } |
492 case kArchTailCallCodeObjectFromJSFunction: | 587 case kArchTailCallCodeObjectFromJSFunction: |
493 case kArchTailCallCodeObject: { | 588 case kArchTailCallCodeObject: { |
494 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); | |
495 AssembleDeconstructActivationRecord(stack_param_delta); | |
496 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) { | 589 if (arch_opcode == kArchTailCallCodeObjectFromJSFunction) { |
497 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, | 590 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, |
498 i.TempRegister(0), i.TempRegister(1), | 591 i.TempRegister(0), i.TempRegister(1), |
499 i.TempRegister(2)); | 592 i.TempRegister(2)); |
500 } | 593 } |
501 if (instr->InputAt(0)->IsImmediate()) { | 594 if (instr->InputAt(0)->IsImmediate()) { |
502 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)), | 595 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)), |
503 RelocInfo::CODE_TARGET); | 596 RelocInfo::CODE_TARGET); |
504 } else { | 597 } else { |
505 __ add(ip, i.InputRegister(0), | 598 __ add(ip, i.InputRegister(0), |
506 Operand(Code::kHeaderSize - kHeapObjectTag)); | 599 Operand(Code::kHeaderSize - kHeapObjectTag)); |
507 __ Jump(ip); | 600 __ Jump(ip); |
508 } | 601 } |
509 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 602 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
510 frame_access_state()->ClearSPDelta(); | 603 frame_access_state()->ClearSPDelta(); |
| 604 frame_access_state()->SetFrameAccessToDefault(); |
511 break; | 605 break; |
512 } | 606 } |
513 case kArchTailCallAddress: { | 607 case kArchTailCallAddress: { |
514 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); | |
515 AssembleDeconstructActivationRecord(stack_param_delta); | |
516 CHECK(!instr->InputAt(0)->IsImmediate()); | 608 CHECK(!instr->InputAt(0)->IsImmediate()); |
517 __ Jump(i.InputRegister(0)); | 609 __ Jump(i.InputRegister(0)); |
518 frame_access_state()->ClearSPDelta(); | 610 frame_access_state()->ClearSPDelta(); |
| 611 frame_access_state()->SetFrameAccessToDefault(); |
519 break; | 612 break; |
520 } | 613 } |
521 case kArchCallJSFunction: { | 614 case kArchCallJSFunction: { |
522 EnsureSpaceForLazyDeopt(); | 615 EnsureSpaceForLazyDeopt(); |
523 Register func = i.InputRegister(0); | 616 Register func = i.InputRegister(0); |
524 if (FLAG_debug_code) { | 617 if (FLAG_debug_code) { |
525 // Check the function's context matches the context argument. | 618 // Check the function's context matches the context argument. |
526 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); | 619 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); |
527 __ cmp(cp, kScratchReg); | 620 __ cmp(cp, kScratchReg); |
528 __ Assert(eq, kWrongFunctionContext); | 621 __ Assert(eq, kWrongFunctionContext); |
529 } | 622 } |
530 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); | 623 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); |
531 __ Call(ip); | 624 __ Call(ip); |
532 RecordCallPosition(instr); | 625 RecordCallPosition(instr); |
533 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 626 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
534 frame_access_state()->ClearSPDelta(); | 627 frame_access_state()->ClearSPDelta(); |
535 break; | 628 break; |
536 } | 629 } |
537 case kArchTailCallJSFunctionFromJSFunction: | 630 case kArchTailCallJSFunctionFromJSFunction: |
538 case kArchTailCallJSFunction: { | 631 case kArchTailCallJSFunction: { |
539 Register func = i.InputRegister(0); | 632 Register func = i.InputRegister(0); |
540 if (FLAG_debug_code) { | 633 if (FLAG_debug_code) { |
541 // Check the function's context matches the context argument. | 634 // Check the function's context matches the context argument. |
542 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); | 635 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); |
543 __ cmp(cp, kScratchReg); | 636 __ cmp(cp, kScratchReg); |
544 __ Assert(eq, kWrongFunctionContext); | 637 __ Assert(eq, kWrongFunctionContext); |
545 } | 638 } |
546 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); | |
547 AssembleDeconstructActivationRecord(stack_param_delta); | |
548 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) { | 639 if (arch_opcode == kArchTailCallJSFunctionFromJSFunction) { |
549 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, | 640 AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister, |
550 i.TempRegister(0), i.TempRegister(1), | 641 i.TempRegister(0), i.TempRegister(1), |
551 i.TempRegister(2)); | 642 i.TempRegister(2)); |
552 } | 643 } |
553 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); | 644 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); |
554 __ Jump(ip); | 645 __ Jump(ip); |
555 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 646 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
556 frame_access_state()->ClearSPDelta(); | 647 frame_access_state()->ClearSPDelta(); |
| 648 frame_access_state()->SetFrameAccessToDefault(); |
557 break; | 649 break; |
558 } | 650 } |
559 case kArchPrepareCallCFunction: { | 651 case kArchPrepareCallCFunction: { |
560 int const num_parameters = MiscField::decode(instr->opcode()); | 652 int const num_parameters = MiscField::decode(instr->opcode()); |
561 __ PrepareCallCFunction(num_parameters, kScratchReg); | 653 __ PrepareCallCFunction(num_parameters, kScratchReg); |
562 // Frame alignment requires using FP-relative frame addressing. | 654 // Frame alignment requires using FP-relative frame addressing. |
563 frame_access_state()->SetFrameAccessToFP(); | 655 frame_access_state()->SetFrameAccessToFP(); |
564 break; | 656 break; |
565 } | 657 } |
566 case kArchPrepareTailCall: | 658 case kArchPrepareTailCall: |
567 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1)); | 659 AssemblePrepareTailCall(); |
568 break; | 660 break; |
569 case kArchCallCFunction: { | 661 case kArchCallCFunction: { |
570 int const num_parameters = MiscField::decode(instr->opcode()); | 662 int const num_parameters = MiscField::decode(instr->opcode()); |
571 if (instr->InputAt(0)->IsImmediate()) { | 663 if (instr->InputAt(0)->IsImmediate()) { |
572 ExternalReference ref = i.InputExternalReference(0); | 664 ExternalReference ref = i.InputExternalReference(0); |
573 __ CallCFunction(ref, num_parameters); | 665 __ CallCFunction(ref, num_parameters); |
574 } else { | 666 } else { |
575 Register func = i.InputRegister(0); | 667 Register func = i.InputRegister(0); |
576 __ CallCFunction(func, num_parameters); | 668 __ CallCFunction(func, num_parameters); |
577 } | 669 } |
(...skipping 1247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1825 padding_size -= v8::internal::Assembler::kInstrSize; | 1917 padding_size -= v8::internal::Assembler::kInstrSize; |
1826 } | 1918 } |
1827 } | 1919 } |
1828 } | 1920 } |
1829 | 1921 |
1830 #undef __ | 1922 #undef __ |
1831 | 1923 |
1832 } // namespace compiler | 1924 } // namespace compiler |
1833 } // namespace internal | 1925 } // namespace internal |
1834 } // namespace v8 | 1926 } // namespace v8 |
OLD | NEW |