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/compiler/code-generator-impl.h" | 8 #include "src/compiler/code-generator-impl.h" |
9 #include "src/compiler/gap-resolver.h" | 9 #include "src/compiler/gap-resolver.h" |
10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 return MemOperand(r0); | 142 return MemOperand(r0); |
143 } | 143 } |
144 | 144 |
145 MemOperand InputOffset(size_t first_index = 0) { | 145 MemOperand InputOffset(size_t first_index = 0) { |
146 return InputOffset(&first_index); | 146 return InputOffset(&first_index); |
147 } | 147 } |
148 | 148 |
149 MemOperand ToMemOperand(InstructionOperand* op) const { | 149 MemOperand ToMemOperand(InstructionOperand* op) const { |
150 DCHECK(op != NULL); | 150 DCHECK(op != NULL); |
151 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot()); | 151 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot()); |
152 FrameOffset offset = | 152 FrameOffset offset = frame_access_state()->GetFrameOffset( |
153 linkage()->GetFrameOffset(AllocatedOperand::cast(op)->index(), frame()); | 153 AllocatedOperand::cast(op)->index()); |
154 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset()); | 154 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset()); |
155 } | 155 } |
156 }; | 156 }; |
157 | 157 |
158 | 158 |
159 namespace { | 159 namespace { |
160 | 160 |
161 class OutOfLineLoadFloat32 final : public OutOfLineCode { | 161 class OutOfLineLoadFloat32 final : public OutOfLineCode { |
162 public: | 162 public: |
163 OutOfLineLoadFloat32(CodeGenerator* gen, SwVfpRegister result) | 163 OutOfLineLoadFloat32(CodeGenerator* gen, SwVfpRegister result) |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 __ asm_instr(value, i.InputOffset(3), lo); \ | 352 __ asm_instr(value, i.InputOffset(3), lo); \ |
353 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ | 353 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ |
354 } while (0) | 354 } while (0) |
355 | 355 |
356 | 356 |
357 void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) { | 357 void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) { |
358 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); | 358 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); |
359 if (sp_slot_delta > 0) { | 359 if (sp_slot_delta > 0) { |
360 __ add(sp, sp, Operand(sp_slot_delta * kPointerSize)); | 360 __ add(sp, sp, Operand(sp_slot_delta * kPointerSize)); |
361 } | 361 } |
362 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); | 362 if (frame()->needs_frame()) { |
363 int spill_slots = frame()->GetSpillSlotCount(); | |
364 bool has_frame = descriptor->IsJSFunctionCall() || spill_slots > 0; | |
365 if (has_frame) { | |
366 if (FLAG_enable_embedded_constant_pool) { | 363 if (FLAG_enable_embedded_constant_pool) { |
367 __ ldm(ia_w, sp, pp.bit() | fp.bit() | lr.bit()); | 364 __ ldm(ia_w, sp, pp.bit() | fp.bit() | lr.bit()); |
368 } else { | 365 } else { |
369 __ ldm(ia_w, sp, fp.bit() | lr.bit()); | 366 __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
370 } | 367 } |
371 } | 368 } |
| 369 frame_access_state()->SetFrameAccessToDefault(); |
372 } | 370 } |
373 | 371 |
374 | 372 |
375 void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) { | 373 void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) { |
376 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); | 374 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); |
377 if (sp_slot_delta < 0) { | 375 if (sp_slot_delta < 0) { |
378 __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize)); | 376 __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize)); |
| 377 frame_access_state()->IncreaseSPDelta(-sp_slot_delta); |
379 } | 378 } |
| 379 frame_access_state()->SetFrameAccessToSP(); |
380 } | 380 } |
381 | 381 |
382 | 382 |
383 // Assembles an instruction after register allocation, producing machine code. | 383 // Assembles an instruction after register allocation, producing machine code. |
384 void CodeGenerator::AssembleArchInstruction(Instruction* instr) { | 384 void CodeGenerator::AssembleArchInstruction(Instruction* instr) { |
385 ArmOperandConverter i(this, instr); | 385 ArmOperandConverter i(this, instr); |
386 | 386 |
387 masm()->MaybeCheckConstPool(); | 387 masm()->MaybeCheckConstPool(); |
388 | 388 |
389 switch (ArchOpcodeField::decode(instr->opcode())) { | 389 switch (ArchOpcodeField::decode(instr->opcode())) { |
390 case kArchCallCodeObject: { | 390 case kArchCallCodeObject: { |
391 EnsureSpaceForLazyDeopt(); | 391 EnsureSpaceForLazyDeopt(); |
392 if (instr->InputAt(0)->IsImmediate()) { | 392 if (instr->InputAt(0)->IsImmediate()) { |
393 __ Call(Handle<Code>::cast(i.InputHeapObject(0)), | 393 __ Call(Handle<Code>::cast(i.InputHeapObject(0)), |
394 RelocInfo::CODE_TARGET); | 394 RelocInfo::CODE_TARGET); |
395 } else { | 395 } else { |
396 __ add(ip, i.InputRegister(0), | 396 __ add(ip, i.InputRegister(0), |
397 Operand(Code::kHeaderSize - kHeapObjectTag)); | 397 Operand(Code::kHeaderSize - kHeapObjectTag)); |
398 __ Call(ip); | 398 __ Call(ip); |
399 } | 399 } |
400 RecordCallPosition(instr); | 400 RecordCallPosition(instr); |
401 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 401 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
| 402 frame_access_state()->ClearSPDelta(); |
402 break; | 403 break; |
403 } | 404 } |
404 case kArchTailCallCodeObject: { | 405 case kArchTailCallCodeObject: { |
405 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); | 406 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); |
406 AssembleDeconstructActivationRecord(stack_param_delta); | 407 AssembleDeconstructActivationRecord(stack_param_delta); |
407 if (instr->InputAt(0)->IsImmediate()) { | 408 if (instr->InputAt(0)->IsImmediate()) { |
408 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)), | 409 __ Jump(Handle<Code>::cast(i.InputHeapObject(0)), |
409 RelocInfo::CODE_TARGET); | 410 RelocInfo::CODE_TARGET); |
410 } else { | 411 } else { |
411 __ add(ip, i.InputRegister(0), | 412 __ add(ip, i.InputRegister(0), |
412 Operand(Code::kHeaderSize - kHeapObjectTag)); | 413 Operand(Code::kHeaderSize - kHeapObjectTag)); |
413 __ Jump(ip); | 414 __ Jump(ip); |
414 } | 415 } |
415 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 416 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
| 417 frame_access_state()->ClearSPDelta(); |
416 break; | 418 break; |
417 } | 419 } |
418 case kArchCallJSFunction: { | 420 case kArchCallJSFunction: { |
419 EnsureSpaceForLazyDeopt(); | 421 EnsureSpaceForLazyDeopt(); |
420 Register func = i.InputRegister(0); | 422 Register func = i.InputRegister(0); |
421 if (FLAG_debug_code) { | 423 if (FLAG_debug_code) { |
422 // Check the function's context matches the context argument. | 424 // Check the function's context matches the context argument. |
423 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); | 425 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); |
424 __ cmp(cp, kScratchReg); | 426 __ cmp(cp, kScratchReg); |
425 __ Assert(eq, kWrongFunctionContext); | 427 __ Assert(eq, kWrongFunctionContext); |
426 } | 428 } |
427 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); | 429 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); |
428 __ Call(ip); | 430 __ Call(ip); |
429 RecordCallPosition(instr); | 431 RecordCallPosition(instr); |
430 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 432 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
| 433 frame_access_state()->ClearSPDelta(); |
431 break; | 434 break; |
432 } | 435 } |
433 case kArchTailCallJSFunction: { | 436 case kArchTailCallJSFunction: { |
434 Register func = i.InputRegister(0); | 437 Register func = i.InputRegister(0); |
435 if (FLAG_debug_code) { | 438 if (FLAG_debug_code) { |
436 // Check the function's context matches the context argument. | 439 // Check the function's context matches the context argument. |
437 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); | 440 __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset)); |
438 __ cmp(cp, kScratchReg); | 441 __ cmp(cp, kScratchReg); |
439 __ Assert(eq, kWrongFunctionContext); | 442 __ Assert(eq, kWrongFunctionContext); |
440 } | 443 } |
441 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); | 444 int stack_param_delta = i.InputInt32(instr->InputCount() - 1); |
442 AssembleDeconstructActivationRecord(stack_param_delta); | 445 AssembleDeconstructActivationRecord(stack_param_delta); |
443 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); | 446 __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset)); |
444 __ Jump(ip); | 447 __ Jump(ip); |
445 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 448 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
| 449 frame_access_state()->ClearSPDelta(); |
446 break; | 450 break; |
447 } | 451 } |
448 case kArchLazyBailout: { | 452 case kArchLazyBailout: { |
449 EnsureSpaceForLazyDeopt(); | 453 EnsureSpaceForLazyDeopt(); |
450 RecordCallPosition(instr); | 454 RecordCallPosition(instr); |
451 break; | 455 break; |
452 } | 456 } |
453 case kArchPrepareCallCFunction: { | 457 case kArchPrepareCallCFunction: { |
454 int const num_parameters = MiscField::decode(instr->opcode()); | 458 int const num_parameters = MiscField::decode(instr->opcode()); |
455 __ PrepareCallCFunction(num_parameters, kScratchReg); | 459 __ PrepareCallCFunction(num_parameters, kScratchReg); |
| 460 // Frame alignment requires using FP-relative frame addressing. |
| 461 frame_access_state()->SetFrameAccessToFP(); |
456 break; | 462 break; |
457 } | 463 } |
458 case kArchPrepareTailCall: | 464 case kArchPrepareTailCall: |
459 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1)); | 465 AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1)); |
460 break; | 466 break; |
461 case kArchCallCFunction: { | 467 case kArchCallCFunction: { |
462 int const num_parameters = MiscField::decode(instr->opcode()); | 468 int const num_parameters = MiscField::decode(instr->opcode()); |
463 if (instr->InputAt(0)->IsImmediate()) { | 469 if (instr->InputAt(0)->IsImmediate()) { |
464 ExternalReference ref = i.InputExternalReference(0); | 470 ExternalReference ref = i.InputExternalReference(0); |
465 __ CallCFunction(ref, num_parameters); | 471 __ CallCFunction(ref, num_parameters); |
466 } else { | 472 } else { |
467 Register func = i.InputRegister(0); | 473 Register func = i.InputRegister(0); |
468 __ CallCFunction(func, num_parameters); | 474 __ CallCFunction(func, num_parameters); |
469 } | 475 } |
| 476 frame_access_state()->SetFrameAccessToDefault(); |
| 477 frame_access_state()->ClearSPDelta(); |
470 break; | 478 break; |
471 } | 479 } |
472 case kArchJmp: | 480 case kArchJmp: |
473 AssembleArchJump(i.InputRpo(0)); | 481 AssembleArchJump(i.InputRpo(0)); |
474 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 482 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
475 break; | 483 break; |
476 case kArchLookupSwitch: | 484 case kArchLookupSwitch: |
477 AssembleArchLookupSwitch(instr); | 485 AssembleArchLookupSwitch(instr); |
478 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 486 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
479 break; | 487 break; |
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
914 case kArmVstrF64: { | 922 case kArmVstrF64: { |
915 size_t index = 0; | 923 size_t index = 0; |
916 MemOperand operand = i.InputOffset(&index); | 924 MemOperand operand = i.InputOffset(&index); |
917 __ vstr(i.InputFloat64Register(index), operand); | 925 __ vstr(i.InputFloat64Register(index), operand); |
918 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 926 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
919 break; | 927 break; |
920 } | 928 } |
921 case kArmPush: | 929 case kArmPush: |
922 if (instr->InputAt(0)->IsDoubleRegister()) { | 930 if (instr->InputAt(0)->IsDoubleRegister()) { |
923 __ vpush(i.InputDoubleRegister(0)); | 931 __ vpush(i.InputDoubleRegister(0)); |
| 932 frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize); |
924 } else { | 933 } else { |
925 __ push(i.InputRegister(0)); | 934 __ push(i.InputRegister(0)); |
| 935 frame_access_state()->IncreaseSPDelta(1); |
926 } | 936 } |
927 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 937 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
928 break; | 938 break; |
929 case kArmPoke: { | 939 case kArmPoke: { |
930 int const slot = MiscField::decode(instr->opcode()); | 940 int const slot = MiscField::decode(instr->opcode()); |
931 __ str(i.InputRegister(0), MemOperand(sp, slot * kPointerSize)); | 941 __ str(i.InputRegister(0), MemOperand(sp, slot * kPointerSize)); |
932 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 942 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
933 break; | 943 break; |
934 } | 944 } |
935 case kCheckedLoadInt8: | 945 case kCheckedLoadInt8: |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1037 void CodeGenerator::AssembleDeoptimizerCall( | 1047 void CodeGenerator::AssembleDeoptimizerCall( |
1038 int deoptimization_id, Deoptimizer::BailoutType bailout_type) { | 1048 int deoptimization_id, Deoptimizer::BailoutType bailout_type) { |
1039 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( | 1049 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( |
1040 isolate(), deoptimization_id, bailout_type); | 1050 isolate(), deoptimization_id, bailout_type); |
1041 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY); | 1051 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY); |
1042 } | 1052 } |
1043 | 1053 |
1044 | 1054 |
1045 void CodeGenerator::AssemblePrologue() { | 1055 void CodeGenerator::AssemblePrologue() { |
1046 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); | 1056 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); |
1047 if (descriptor->kind() == CallDescriptor::kCallAddress) { | 1057 if (descriptor->IsCFunctionCall()) { |
1048 if (FLAG_enable_embedded_constant_pool) { | 1058 if (FLAG_enable_embedded_constant_pool) { |
1049 __ Push(lr, fp, pp); | 1059 __ Push(lr, fp, pp); |
1050 // Adjust FP to point to saved FP. | 1060 // Adjust FP to point to saved FP. |
1051 __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset)); | 1061 __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset)); |
1052 } else { | 1062 } else { |
1053 __ Push(lr, fp); | 1063 __ Push(lr, fp); |
1054 __ mov(fp, sp); | 1064 __ mov(fp, sp); |
1055 } | 1065 } |
1056 } else if (descriptor->IsJSFunctionCall()) { | 1066 } else if (descriptor->IsJSFunctionCall()) { |
1057 CompilationInfo* info = this->info(); | 1067 CompilationInfo* info = this->info(); |
1058 __ Prologue(info->IsCodePreAgingActive()); | 1068 __ Prologue(info->IsCodePreAgingActive()); |
1059 } else if (needs_frame_) { | 1069 } else if (frame()->needs_frame()) { |
1060 __ StubPrologue(); | 1070 __ StubPrologue(); |
1061 } else { | 1071 } else { |
1062 frame()->SetElidedFrameSizeInSlots(0); | 1072 frame()->SetElidedFrameSizeInSlots(0); |
1063 } | 1073 } |
| 1074 frame_access_state()->SetFrameAccessToDefault(); |
1064 | 1075 |
1065 int stack_shrink_slots = frame()->GetSpillSlotCount(); | 1076 int stack_shrink_slots = frame()->GetSpillSlotCount(); |
1066 if (info()->is_osr()) { | 1077 if (info()->is_osr()) { |
1067 // TurboFan OSR-compiled functions cannot be entered directly. | 1078 // TurboFan OSR-compiled functions cannot be entered directly. |
1068 __ Abort(kShouldNotDirectlyEnterOsrFunction); | 1079 __ Abort(kShouldNotDirectlyEnterOsrFunction); |
1069 | 1080 |
1070 // Unoptimized code jumps directly to this entrypoint while the unoptimized | 1081 // Unoptimized code jumps directly to this entrypoint while the unoptimized |
1071 // frame is still on the stack. Optimized code uses OSR values directly from | 1082 // frame is still on the stack. Optimized code uses OSR values directly from |
1072 // the unoptimized frame. Thus, all that needs to be done is to allocate the | 1083 // the unoptimized frame. Thus, all that needs to be done is to allocate the |
1073 // remaining stack slots. | 1084 // remaining stack slots. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1124 // Restore FP registers. | 1135 // Restore FP registers. |
1125 const RegList saves_fp = descriptor->CalleeSavedFPRegisters(); | 1136 const RegList saves_fp = descriptor->CalleeSavedFPRegisters(); |
1126 if (saves_fp != 0) { | 1137 if (saves_fp != 0) { |
1127 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32); | 1138 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32); |
1128 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1; | 1139 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1; |
1129 uint32_t first = base::bits::CountTrailingZeros32(saves_fp); | 1140 uint32_t first = base::bits::CountTrailingZeros32(saves_fp); |
1130 __ vldm(ia_w, sp, DwVfpRegister::from_code(first), | 1141 __ vldm(ia_w, sp, DwVfpRegister::from_code(first), |
1131 DwVfpRegister::from_code(last)); | 1142 DwVfpRegister::from_code(last)); |
1132 } | 1143 } |
1133 | 1144 |
1134 if (descriptor->kind() == CallDescriptor::kCallAddress) { | 1145 if (descriptor->IsCFunctionCall()) { |
1135 __ LeaveFrame(StackFrame::MANUAL); | 1146 __ LeaveFrame(StackFrame::MANUAL); |
1136 } else if (descriptor->IsJSFunctionCall() || needs_frame_) { | 1147 } else if (frame()->needs_frame()) { |
1137 // Canonicalize JSFunction return sites for now. | 1148 // Canonicalize JSFunction return sites for now. |
1138 if (return_label_.is_bound()) { | 1149 if (return_label_.is_bound()) { |
1139 __ b(&return_label_); | 1150 __ b(&return_label_); |
1140 return; | 1151 return; |
1141 } else { | 1152 } else { |
1142 __ bind(&return_label_); | 1153 __ bind(&return_label_); |
1143 __ LeaveFrame(StackFrame::MANUAL); | 1154 __ LeaveFrame(StackFrame::MANUAL); |
1144 } | 1155 } |
1145 } | 1156 } |
1146 __ Ret(pop_count); | 1157 __ Ret(pop_count); |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1352 padding_size -= v8::internal::Assembler::kInstrSize; | 1363 padding_size -= v8::internal::Assembler::kInstrSize; |
1353 } | 1364 } |
1354 } | 1365 } |
1355 } | 1366 } |
1356 | 1367 |
1357 #undef __ | 1368 #undef __ |
1358 | 1369 |
1359 } // namespace compiler | 1370 } // namespace compiler |
1360 } // namespace internal | 1371 } // namespace internal |
1361 } // namespace v8 | 1372 } // namespace v8 |
OLD | NEW |