| 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/arm64/frames-arm64.h" | 7 #include "src/arm64/frames-arm64.h" |
| 8 #include "src/arm64/macro-assembler-arm64.h" | 8 #include "src/arm64/macro-assembler-arm64.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 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 } | 200 } |
| 201 UNREACHABLE(); | 201 UNREACHABLE(); |
| 202 return Operand(-1); | 202 return Operand(-1); |
| 203 } | 203 } |
| 204 | 204 |
| 205 MemOperand ToMemOperand(InstructionOperand* op, MacroAssembler* masm) const { | 205 MemOperand ToMemOperand(InstructionOperand* op, MacroAssembler* masm) const { |
| 206 DCHECK(op != NULL); | 206 DCHECK(op != NULL); |
| 207 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot()); | 207 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot()); |
| 208 FrameOffset offset = | 208 FrameOffset offset = |
| 209 linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame()); | 209 linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame()); |
| 210 if (offset.from_frame_pointer()) { |
| 211 int from_sp = |
| 212 offset.offset() + (frame()->GetSpToFpSlotCount() * kPointerSize); |
| 213 // Convert FP-offsets to SP-offsets if it results in better code. |
| 214 if (Assembler::IsImmLSUnscaled(from_sp) || |
| 215 Assembler::IsImmLSScaled(from_sp, LSDoubleWord)) { |
| 216 offset = FrameOffset::FromStackPointer(from_sp); |
| 217 } |
| 218 } |
| 210 return MemOperand(offset.from_stack_pointer() ? masm->StackPointer() : fp, | 219 return MemOperand(offset.from_stack_pointer() ? masm->StackPointer() : fp, |
| 211 offset.offset()); | 220 offset.offset()); |
| 212 } | 221 } |
| 213 }; | 222 }; |
| 214 | 223 |
| 215 | 224 |
| 216 namespace { | 225 namespace { |
| 217 | 226 |
| 218 class OutOfLineLoadNaN32 final : public OutOfLineCode { | 227 class OutOfLineLoadNaN32 final : public OutOfLineCode { |
| 219 public: | 228 public: |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 case kArchCallCodeObject: { | 433 case kArchCallCodeObject: { |
| 425 EnsureSpaceForLazyDeopt(); | 434 EnsureSpaceForLazyDeopt(); |
| 426 if (instr->InputAt(0)->IsImmediate()) { | 435 if (instr->InputAt(0)->IsImmediate()) { |
| 427 __ Call(Handle<Code>::cast(i.InputHeapObject(0)), | 436 __ Call(Handle<Code>::cast(i.InputHeapObject(0)), |
| 428 RelocInfo::CODE_TARGET); | 437 RelocInfo::CODE_TARGET); |
| 429 } else { | 438 } else { |
| 430 Register target = i.InputRegister(0); | 439 Register target = i.InputRegister(0); |
| 431 __ Add(target, target, Code::kHeaderSize - kHeapObjectTag); | 440 __ Add(target, target, Code::kHeaderSize - kHeapObjectTag); |
| 432 __ Call(target); | 441 __ Call(target); |
| 433 } | 442 } |
| 443 frame()->ClearOutgoingParameterSlots(); |
| 434 RecordCallPosition(instr); | 444 RecordCallPosition(instr); |
| 435 break; | 445 break; |
| 436 } | 446 } |
| 437 case kArchTailCallCodeObject: { | 447 case kArchTailCallCodeObject: { |
| 438 AssembleDeconstructActivationRecord(); | 448 AssembleDeconstructActivationRecord(); |
| 439 if (instr->InputAt(0)->IsImmediate()) { | 449 if (instr->InputAt(0)->IsImmediate()) { |
| 440 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)), | 450 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)), |
| 441 RelocInfo::CODE_TARGET); | 451 RelocInfo::CODE_TARGET); |
| 442 } else { | 452 } else { |
| 443 Register target = i.InputRegister(0); | 453 Register target = i.InputRegister(0); |
| 444 __ Add(target, target, Code::kHeaderSize - kHeapObjectTag); | 454 __ Add(target, target, Code::kHeaderSize - kHeapObjectTag); |
| 445 __ Jump(target); | 455 __ Jump(target); |
| 446 } | 456 } |
| 457 frame()->ClearOutgoingParameterSlots(); |
| 447 break; | 458 break; |
| 448 } | 459 } |
| 449 case kArchCallJSFunction: { | 460 case kArchCallJSFunction: { |
| 450 EnsureSpaceForLazyDeopt(); | 461 EnsureSpaceForLazyDeopt(); |
| 451 Register func = i.InputRegister(0); | 462 Register func = i.InputRegister(0); |
| 452 if (FLAG_debug_code) { | 463 if (FLAG_debug_code) { |
| 453 // Check the function's context matches the context argument. | 464 // Check the function's context matches the context argument. |
| 454 UseScratchRegisterScope scope(masm()); | 465 UseScratchRegisterScope scope(masm()); |
| 455 Register temp = scope.AcquireX(); | 466 Register temp = scope.AcquireX(); |
| 456 __ Ldr(temp, FieldMemOperand(func, JSFunction::kContextOffset)); | 467 __ Ldr(temp, FieldMemOperand(func, JSFunction::kContextOffset)); |
| 457 __ cmp(cp, temp); | 468 __ cmp(cp, temp); |
| 458 __ Assert(eq, kWrongFunctionContext); | 469 __ Assert(eq, kWrongFunctionContext); |
| 459 } | 470 } |
| 460 __ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); | 471 __ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); |
| 461 __ Call(x10); | 472 __ Call(x10); |
| 473 frame()->ClearOutgoingParameterSlots(); |
| 462 RecordCallPosition(instr); | 474 RecordCallPosition(instr); |
| 463 break; | 475 break; |
| 464 } | 476 } |
| 465 case kArchTailCallJSFunction: { | 477 case kArchTailCallJSFunction: { |
| 466 Register func = i.InputRegister(0); | 478 Register func = i.InputRegister(0); |
| 467 if (FLAG_debug_code) { | 479 if (FLAG_debug_code) { |
| 468 // Check the function's context matches the context argument. | 480 // Check the function's context matches the context argument. |
| 469 UseScratchRegisterScope scope(masm()); | 481 UseScratchRegisterScope scope(masm()); |
| 470 Register temp = scope.AcquireX(); | 482 Register temp = scope.AcquireX(); |
| 471 __ Ldr(temp, FieldMemOperand(func, JSFunction::kContextOffset)); | 483 __ Ldr(temp, FieldMemOperand(func, JSFunction::kContextOffset)); |
| 472 __ cmp(cp, temp); | 484 __ cmp(cp, temp); |
| 473 __ Assert(eq, kWrongFunctionContext); | 485 __ Assert(eq, kWrongFunctionContext); |
| 474 } | 486 } |
| 475 AssembleDeconstructActivationRecord(); | 487 AssembleDeconstructActivationRecord(); |
| 476 __ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); | 488 __ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); |
| 477 __ Jump(x10); | 489 __ Jump(x10); |
| 490 frame()->ClearOutgoingParameterSlots(); |
| 478 break; | 491 break; |
| 479 } | 492 } |
| 480 case kArchLazyBailout: { | 493 case kArchLazyBailout: { |
| 481 EnsureSpaceForLazyDeopt(); | 494 EnsureSpaceForLazyDeopt(); |
| 482 RecordCallPosition(instr); | 495 RecordCallPosition(instr); |
| 483 break; | 496 break; |
| 484 } | 497 } |
| 485 case kArchPrepareCallCFunction: | 498 case kArchPrepareCallCFunction: |
| 486 // We don't need kArchPrepareCallCFunction on arm64 as the instruction | 499 // We don't need kArchPrepareCallCFunction on arm64 as the instruction |
| 487 // selector already perform a Claim to reserve space on the stack and | 500 // selector already perform a Claim to reserve space on the stack and |
| 488 // guarantee correct alignment of stack pointer. | 501 // guarantee correct alignment of stack pointer. |
| 489 UNREACHABLE(); | 502 UNREACHABLE(); |
| 490 break; | 503 break; |
| 491 case kArchCallCFunction: { | 504 case kArchCallCFunction: { |
| 492 int const num_parameters = MiscField::decode(instr->opcode()); | 505 int const num_parameters = MiscField::decode(instr->opcode()); |
| 493 if (instr->InputAt(0)->IsImmediate()) { | 506 if (instr->InputAt(0)->IsImmediate()) { |
| 494 ExternalReference ref = i.InputExternalReference(0); | 507 ExternalReference ref = i.InputExternalReference(0); |
| 495 __ CallCFunction(ref, num_parameters, 0); | 508 __ CallCFunction(ref, num_parameters, 0); |
| 496 } else { | 509 } else { |
| 497 Register func = i.InputRegister(0); | 510 Register func = i.InputRegister(0); |
| 498 __ CallCFunction(func, num_parameters, 0); | 511 __ CallCFunction(func, num_parameters, 0); |
| 499 } | 512 } |
| 513 // CallCFunction only supports register arguments so we never need to call |
| 514 // frame()->ClearOutgoingParameterSlots() here. |
| 515 DCHECK(frame()->GetOutgoingParameterSlotCount() == 0); |
| 500 break; | 516 break; |
| 501 } | 517 } |
| 502 case kArchJmp: | 518 case kArchJmp: |
| 503 AssembleArchJump(i.InputRpo(0)); | 519 AssembleArchJump(i.InputRpo(0)); |
| 504 break; | 520 break; |
| 505 case kArchTableSwitch: | 521 case kArchTableSwitch: |
| 506 AssembleArchTableSwitch(instr); | 522 AssembleArchTableSwitch(instr); |
| 507 break; | 523 break; |
| 508 case kArchLookupSwitch: | 524 case kArchLookupSwitch: |
| 509 AssembleArchLookupSwitch(instr); | 525 AssembleArchLookupSwitch(instr); |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 753 __ Bfi(i.OutputRegister(), i.InputRegister(1), i.InputInt6(2), | 769 __ Bfi(i.OutputRegister(), i.InputRegister(1), i.InputInt6(2), |
| 754 i.InputInt6(3)); | 770 i.InputInt6(3)); |
| 755 break; | 771 break; |
| 756 case kArm64TestAndBranch32: | 772 case kArm64TestAndBranch32: |
| 757 case kArm64TestAndBranch: | 773 case kArm64TestAndBranch: |
| 758 // Pseudo instructions turned into tbz/tbnz in AssembleArchBranch. | 774 // Pseudo instructions turned into tbz/tbnz in AssembleArchBranch. |
| 759 break; | 775 break; |
| 760 case kArm64CompareAndBranch32: | 776 case kArm64CompareAndBranch32: |
| 761 // Pseudo instruction turned into cbz/cbnz in AssembleArchBranch. | 777 // Pseudo instruction turned into cbz/cbnz in AssembleArchBranch. |
| 762 break; | 778 break; |
| 763 case kArm64Claim: { | 779 case kArm64ClaimForCallArguments: { |
| 764 __ Claim(i.InputInt32(0)); | 780 __ Claim(i.InputInt32(0)); |
| 781 frame()->AllocateOutgoingParameterSlots(i.InputInt32(0)); |
| 765 break; | 782 break; |
| 766 } | 783 } |
| 767 case kArm64Poke: { | 784 case kArm64Poke: { |
| 768 Operand operand(i.InputInt32(1) * kPointerSize); | 785 Operand operand(i.InputInt32(1) * kPointerSize); |
| 769 __ Poke(i.InputRegister(0), operand); | 786 __ Poke(i.InputRegister(0), operand); |
| 770 break; | 787 break; |
| 771 } | 788 } |
| 772 case kArm64PokePair: { | 789 case kArm64PokePair: { |
| 773 int slot = i.InputInt32(2) - 1; | 790 int slot = i.InputInt32(2) - 1; |
| 774 __ PokePair(i.InputRegister(1), i.InputRegister(0), slot * kPointerSize); | 791 __ PokePair(i.InputRegister(1), i.InputRegister(0), slot * kPointerSize); |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1162 | 1179 |
| 1163 | 1180 |
| 1164 void CodeGenerator::AssembleDeoptimizerCall( | 1181 void CodeGenerator::AssembleDeoptimizerCall( |
| 1165 int deoptimization_id, Deoptimizer::BailoutType bailout_type) { | 1182 int deoptimization_id, Deoptimizer::BailoutType bailout_type) { |
| 1166 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( | 1183 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( |
| 1167 isolate(), deoptimization_id, bailout_type); | 1184 isolate(), deoptimization_id, bailout_type); |
| 1168 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY); | 1185 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY); |
| 1169 } | 1186 } |
| 1170 | 1187 |
| 1171 | 1188 |
| 1172 // TODO(dcarney): increase stack slots in frame once before first use. | |
| 1173 static int AlignedStackSlots(int stack_slots) { | |
| 1174 if (stack_slots & 1) stack_slots++; | |
| 1175 return stack_slots; | |
| 1176 } | |
| 1177 | |
| 1178 | |
| 1179 void CodeGenerator::AssemblePrologue() { | 1189 void CodeGenerator::AssemblePrologue() { |
| 1180 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); | 1190 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); |
| 1181 if (descriptor->kind() == CallDescriptor::kCallAddress) { | 1191 if (descriptor->kind() == CallDescriptor::kCallAddress) { |
| 1182 __ SetStackPointer(csp); | 1192 __ SetStackPointer(csp); |
| 1183 __ Push(lr, fp); | 1193 __ Push(lr, fp); |
| 1184 __ Mov(fp, csp); | 1194 __ Mov(fp, csp); |
| 1185 } else if (descriptor->IsJSFunctionCall()) { | 1195 } else if (descriptor->IsJSFunctionCall()) { |
| 1186 CompilationInfo* info = this->info(); | 1196 CompilationInfo* info = this->info(); |
| 1187 __ SetStackPointer(jssp); | 1197 __ SetStackPointer(jssp); |
| 1188 __ Prologue(info->IsCodePreAgingActive()); | 1198 __ Prologue(info->IsCodePreAgingActive()); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1202 // frame is still on the stack. Optimized code uses OSR values directly from | 1212 // frame is still on the stack. Optimized code uses OSR values directly from |
| 1203 // the unoptimized frame. Thus, all that needs to be done is to allocate the | 1213 // the unoptimized frame. Thus, all that needs to be done is to allocate the |
| 1204 // remaining stack slots. | 1214 // remaining stack slots. |
| 1205 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); | 1215 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); |
| 1206 osr_pc_offset_ = __ pc_offset(); | 1216 osr_pc_offset_ = __ pc_offset(); |
| 1207 // TODO(titzer): cannot address target function == local #-1 | 1217 // TODO(titzer): cannot address target function == local #-1 |
| 1208 __ ldr(x1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 1218 __ ldr(x1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 1209 stack_shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots(); | 1219 stack_shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots(); |
| 1210 } | 1220 } |
| 1211 | 1221 |
| 1212 if (stack_shrink_slots > 0) { | 1222 if (csp.Is(masm()->StackPointer())) { |
| 1213 Register sp = __ StackPointer(); | 1223 // The system stack pointer requires 16-byte alignment at function call |
| 1214 if (!sp.Is(csp)) { | 1224 // boundaries. |
| 1215 __ Sub(sp, sp, stack_shrink_slots * kPointerSize); | 1225 stack_shrink_slots += frame()->AlignSavedCalleeRegisterSlots(); |
| 1216 } | |
| 1217 __ Sub(csp, csp, AlignedStackSlots(stack_shrink_slots) * kPointerSize); | |
| 1218 } | 1226 } |
| 1227 __ Claim(stack_shrink_slots); |
| 1219 | 1228 |
| 1220 // Save FP registers. | 1229 // Save FP registers. |
| 1221 CPURegList saves_fp = CPURegList(CPURegister::kFPRegister, kDRegSizeInBits, | 1230 CPURegList saves_fp = CPURegList(CPURegister::kFPRegister, kDRegSizeInBits, |
| 1222 descriptor->CalleeSavedFPRegisters()); | 1231 descriptor->CalleeSavedFPRegisters()); |
| 1223 int saved_count = saves_fp.Count(); | 1232 int saved_count = saves_fp.Count(); |
| 1224 if (saved_count != 0) { | 1233 if (saved_count != 0) { |
| 1225 DCHECK(saves_fp.list() == CPURegList::GetCalleeSavedFP().list()); | 1234 DCHECK(saves_fp.list() == CPURegList::GetCalleeSavedFP().list()); |
| 1226 __ PushCPURegList(saves_fp); | 1235 __ PushCPURegList(saves_fp); |
| 1227 frame()->AllocateSavedCalleeRegisterSlots(saved_count * | 1236 frame()->AllocateSavedCalleeRegisterSlots(saved_count * |
| 1228 (kDoubleSize / kPointerSize)); | 1237 (kDoubleSize / kPointerSize)); |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1460 padding_size -= kInstructionSize; | 1469 padding_size -= kInstructionSize; |
| 1461 } | 1470 } |
| 1462 } | 1471 } |
| 1463 } | 1472 } |
| 1464 | 1473 |
| 1465 #undef __ | 1474 #undef __ |
| 1466 | 1475 |
| 1467 } // namespace compiler | 1476 } // namespace compiler |
| 1468 } // namespace internal | 1477 } // namespace internal |
| 1469 } // namespace v8 | 1478 } // namespace v8 |
| OLD | NEW |