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