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 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t index, | 223 OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t index, |
224 Register value, Register scratch0, Register scratch1, | 224 Register value, Register scratch0, Register scratch1, |
225 RecordWriteMode mode) | 225 RecordWriteMode mode) |
226 : OutOfLineCode(gen), | 226 : OutOfLineCode(gen), |
227 object_(object), | 227 object_(object), |
228 index_(no_reg), | 228 index_(no_reg), |
229 index_immediate_(index), | 229 index_immediate_(index), |
230 value_(value), | 230 value_(value), |
231 scratch0_(scratch0), | 231 scratch0_(scratch0), |
232 scratch1_(scratch1), | 232 scratch1_(scratch1), |
233 mode_(mode) {} | 233 mode_(mode), |
| 234 must_save_lr_(!gen->frame_access_state()->has_frame()) {} |
234 | 235 |
235 void Generate() final { | 236 void Generate() final { |
236 if (mode_ > RecordWriteMode::kValueIsPointer) { | 237 if (mode_ > RecordWriteMode::kValueIsPointer) { |
237 __ JumpIfSmi(value_, exit()); | 238 __ JumpIfSmi(value_, exit()); |
238 } | 239 } |
239 __ CheckPageFlag(value_, scratch0_, | 240 __ CheckPageFlag(value_, scratch0_, |
240 MemoryChunk::kPointersToHereAreInterestingMask, eq, | 241 MemoryChunk::kPointersToHereAreInterestingMask, eq, |
241 exit()); | 242 exit()); |
242 RememberedSetAction const remembered_set_action = | 243 RememberedSetAction const remembered_set_action = |
243 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET | 244 mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET |
244 : OMIT_REMEMBERED_SET; | 245 : OMIT_REMEMBERED_SET; |
245 SaveFPRegsMode const save_fp_mode = | 246 SaveFPRegsMode const save_fp_mode = |
246 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; | 247 frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs; |
247 if (!frame()->needs_frame()) { | 248 if (must_save_lr_) { |
248 // We need to save and restore lr if the frame was elided. | 249 // We need to save and restore lr if the frame was elided. |
249 __ Push(lr); | 250 __ Push(lr); |
250 } | 251 } |
251 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_, | 252 RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_, |
252 remembered_set_action, save_fp_mode); | 253 remembered_set_action, save_fp_mode); |
253 if (index_.is(no_reg)) { | 254 if (index_.is(no_reg)) { |
254 __ add(scratch1_, object_, Operand(index_immediate_)); | 255 __ add(scratch1_, object_, Operand(index_immediate_)); |
255 } else { | 256 } else { |
256 DCHECK_EQ(0, index_immediate_); | 257 DCHECK_EQ(0, index_immediate_); |
257 __ add(scratch1_, object_, Operand(index_)); | 258 __ add(scratch1_, object_, Operand(index_)); |
258 } | 259 } |
259 __ CallStub(&stub); | 260 __ CallStub(&stub); |
260 if (!frame()->needs_frame()) { | 261 if (must_save_lr_) { |
261 __ Pop(lr); | 262 __ Pop(lr); |
262 } | 263 } |
263 } | 264 } |
264 | 265 |
265 private: | 266 private: |
266 Register const object_; | 267 Register const object_; |
267 Register const index_; | 268 Register const index_; |
268 int32_t const index_immediate_; // Valid if index_.is(no_reg). | 269 int32_t const index_immediate_; // Valid if index_.is(no_reg). |
269 Register const value_; | 270 Register const value_; |
270 Register const scratch0_; | 271 Register const scratch0_; |
271 Register const scratch1_; | 272 Register const scratch1_; |
272 RecordWriteMode const mode_; | 273 RecordWriteMode const mode_; |
| 274 bool must_save_lr_; |
273 }; | 275 }; |
274 | 276 |
275 | 277 |
276 Condition FlagsConditionToCondition(FlagsCondition condition) { | 278 Condition FlagsConditionToCondition(FlagsCondition condition) { |
277 switch (condition) { | 279 switch (condition) { |
278 case kEqual: | 280 case kEqual: |
279 return eq; | 281 return eq; |
280 case kNotEqual: | 282 case kNotEqual: |
281 return ne; | 283 return ne; |
282 case kSignedLessThan: | 284 case kSignedLessThan: |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 if (instr->InputAt(1)->IsRegister()) { \ | 381 if (instr->InputAt(1)->IsRegister()) { \ |
380 __ cmp(offset, i.InputRegister(1)); \ | 382 __ cmp(offset, i.InputRegister(1)); \ |
381 } else { \ | 383 } else { \ |
382 __ cmp(offset, i.InputImmediate(1)); \ | 384 __ cmp(offset, i.InputImmediate(1)); \ |
383 } \ | 385 } \ |
384 auto value = i.InputRegister(2); \ | 386 auto value = i.InputRegister(2); \ |
385 __ asm_instr(value, i.InputOffset(3), lo); \ | 387 __ asm_instr(value, i.InputOffset(3), lo); \ |
386 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ | 388 DCHECK_EQ(LeaveCC, i.OutputSBit()); \ |
387 } while (0) | 389 } while (0) |
388 | 390 |
| 391 void CodeGenerator::AssembleDeconstructFrame() { |
| 392 __ LeaveFrame(StackFrame::MANUAL); |
| 393 } |
| 394 |
| 395 void CodeGenerator::AssembleSetupStackPointer() {} |
389 | 396 |
390 void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) { | 397 void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) { |
391 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); | 398 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); |
392 if (sp_slot_delta > 0) { | 399 if (sp_slot_delta > 0) { |
393 __ add(sp, sp, Operand(sp_slot_delta * kPointerSize)); | 400 __ add(sp, sp, Operand(sp_slot_delta * kPointerSize)); |
394 } | 401 } |
395 frame_access_state()->SetFrameAccessToDefault(); | 402 frame_access_state()->SetFrameAccessToDefault(); |
396 } | 403 } |
397 | 404 |
398 | 405 |
399 void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) { | 406 void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) { |
400 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); | 407 int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta); |
401 if (sp_slot_delta < 0) { | 408 if (sp_slot_delta < 0) { |
402 __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize)); | 409 __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize)); |
403 frame_access_state()->IncreaseSPDelta(-sp_slot_delta); | 410 frame_access_state()->IncreaseSPDelta(-sp_slot_delta); |
404 } | 411 } |
405 if (frame()->needs_frame()) { | 412 if (frame_access_state()->has_frame()) { |
406 if (FLAG_enable_embedded_constant_pool) { | 413 if (FLAG_enable_embedded_constant_pool) { |
407 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset)); | 414 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset)); |
408 } | 415 } |
409 __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); | 416 __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); |
410 __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 417 __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
411 } | 418 } |
412 frame_access_state()->SetFrameAccessToSP(); | 419 frame_access_state()->SetFrameAccessToSP(); |
413 } | 420 } |
414 | 421 |
415 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg, | 422 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg, |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
573 break; | 580 break; |
574 case kArchStackPointer: | 581 case kArchStackPointer: |
575 __ mov(i.OutputRegister(), sp); | 582 __ mov(i.OutputRegister(), sp); |
576 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 583 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
577 break; | 584 break; |
578 case kArchFramePointer: | 585 case kArchFramePointer: |
579 __ mov(i.OutputRegister(), fp); | 586 __ mov(i.OutputRegister(), fp); |
580 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 587 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
581 break; | 588 break; |
582 case kArchParentFramePointer: | 589 case kArchParentFramePointer: |
583 if (frame_access_state()->frame()->needs_frame()) { | 590 if (frame_access_state()->has_frame()) { |
584 __ ldr(i.OutputRegister(), MemOperand(fp, 0)); | 591 __ ldr(i.OutputRegister(), MemOperand(fp, 0)); |
585 } else { | 592 } else { |
586 __ mov(i.OutputRegister(), fp); | 593 __ mov(i.OutputRegister(), fp); |
587 } | 594 } |
588 break; | 595 break; |
589 case kArchTruncateDoubleToI: | 596 case kArchTruncateDoubleToI: |
590 __ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0)); | 597 __ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0)); |
591 DCHECK_EQ(LeaveCC, i.OutputSBit()); | 598 DCHECK_EQ(LeaveCC, i.OutputSBit()); |
592 break; | 599 break; |
593 case kArchStoreWithWriteBarrier: { | 600 case kArchStoreWithWriteBarrier: { |
(...skipping 658 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1252 // TODO(turbofan): We should be able to generate better code by sharing the | 1259 // TODO(turbofan): We should be able to generate better code by sharing the |
1253 // actual final call site and just bl'ing to it here, similar to what we do | 1260 // actual final call site and just bl'ing to it here, similar to what we do |
1254 // in the lithium backend. | 1261 // in the lithium backend. |
1255 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY); | 1262 __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY); |
1256 __ CheckConstPool(false, false); | 1263 __ CheckConstPool(false, false); |
1257 } | 1264 } |
1258 | 1265 |
1259 | 1266 |
1260 void CodeGenerator::AssemblePrologue() { | 1267 void CodeGenerator::AssemblePrologue() { |
1261 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); | 1268 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); |
1262 if (frame()->needs_frame()) { | 1269 if (frame_access_state()->has_frame()) { |
1263 if (descriptor->IsCFunctionCall()) { | 1270 if (descriptor->IsCFunctionCall()) { |
1264 if (FLAG_enable_embedded_constant_pool) { | 1271 if (FLAG_enable_embedded_constant_pool) { |
1265 __ Push(lr, fp, pp); | 1272 __ Push(lr, fp, pp); |
1266 // Adjust FP to point to saved FP. | 1273 // Adjust FP to point to saved FP. |
1267 __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset)); | 1274 __ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset)); |
1268 } else { | 1275 } else { |
1269 __ Push(lr, fp); | 1276 __ Push(lr, fp); |
1270 __ mov(fp, sp); | 1277 __ mov(fp, sp); |
1271 } | 1278 } |
1272 } else if (descriptor->IsJSFunctionCall()) { | 1279 } else if (descriptor->IsJSFunctionCall()) { |
1273 __ Prologue(this->info()->GeneratePreagedPrologue()); | 1280 __ Prologue(this->info()->GeneratePreagedPrologue()); |
1274 } else { | 1281 } else { |
1275 __ StubPrologue(info()->GetOutputStackFrameType()); | 1282 __ StubPrologue(info()->GetOutputStackFrameType()); |
1276 } | 1283 } |
1277 } else { | |
1278 frame()->SetElidedFrameSizeInSlots(0); | |
1279 } | 1284 } |
1280 frame_access_state()->SetFrameAccessToDefault(); | |
1281 | 1285 |
1282 int stack_shrink_slots = frame()->GetSpillSlotCount(); | 1286 int stack_shrink_slots = frame()->GetSpillSlotCount(); |
1283 if (info()->is_osr()) { | 1287 if (info()->is_osr()) { |
1284 // TurboFan OSR-compiled functions cannot be entered directly. | 1288 // TurboFan OSR-compiled functions cannot be entered directly. |
1285 __ Abort(kShouldNotDirectlyEnterOsrFunction); | 1289 __ Abort(kShouldNotDirectlyEnterOsrFunction); |
1286 | 1290 |
1287 // Unoptimized code jumps directly to this entrypoint while the unoptimized | 1291 // Unoptimized code jumps directly to this entrypoint while the unoptimized |
1288 // frame is still on the stack. Optimized code uses OSR values directly from | 1292 // frame is still on the stack. Optimized code uses OSR values directly from |
1289 // the unoptimized frame. Thus, all that needs to be done is to allocate the | 1293 // the unoptimized frame. Thus, all that needs to be done is to allocate the |
1290 // remaining stack slots. | 1294 // remaining stack slots. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1340 const RegList saves_fp = descriptor->CalleeSavedFPRegisters(); | 1344 const RegList saves_fp = descriptor->CalleeSavedFPRegisters(); |
1341 if (saves_fp != 0) { | 1345 if (saves_fp != 0) { |
1342 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32); | 1346 STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32); |
1343 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1; | 1347 uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1; |
1344 uint32_t first = base::bits::CountTrailingZeros32(saves_fp); | 1348 uint32_t first = base::bits::CountTrailingZeros32(saves_fp); |
1345 __ vldm(ia_w, sp, DwVfpRegister::from_code(first), | 1349 __ vldm(ia_w, sp, DwVfpRegister::from_code(first), |
1346 DwVfpRegister::from_code(last)); | 1350 DwVfpRegister::from_code(last)); |
1347 } | 1351 } |
1348 | 1352 |
1349 if (descriptor->IsCFunctionCall()) { | 1353 if (descriptor->IsCFunctionCall()) { |
1350 __ LeaveFrame(StackFrame::MANUAL); | 1354 AssembleDeconstructFrame(); |
1351 } else if (frame()->needs_frame()) { | 1355 } else if (frame_access_state()->has_frame()) { |
1352 // Canonicalize JSFunction return sites for now. | 1356 // Canonicalize JSFunction return sites for now. |
1353 if (return_label_.is_bound()) { | 1357 if (return_label_.is_bound()) { |
1354 __ b(&return_label_); | 1358 __ b(&return_label_); |
1355 return; | 1359 return; |
1356 } else { | 1360 } else { |
1357 __ bind(&return_label_); | 1361 __ bind(&return_label_); |
1358 __ LeaveFrame(StackFrame::MANUAL); | 1362 AssembleDeconstructFrame(); |
1359 } | 1363 } |
1360 } | 1364 } |
1361 __ Ret(pop_count); | 1365 __ Ret(pop_count); |
1362 } | 1366 } |
1363 | 1367 |
1364 | 1368 |
1365 void CodeGenerator::AssembleMove(InstructionOperand* source, | 1369 void CodeGenerator::AssembleMove(InstructionOperand* source, |
1366 InstructionOperand* destination) { | 1370 InstructionOperand* destination) { |
1367 ArmOperandConverter g(this, nullptr); | 1371 ArmOperandConverter g(this, nullptr); |
1368 // Dispatch on the source and destination operand kinds. Not all | 1372 // Dispatch on the source and destination operand kinds. Not all |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1567 padding_size -= v8::internal::Assembler::kInstrSize; | 1571 padding_size -= v8::internal::Assembler::kInstrSize; |
1568 } | 1572 } |
1569 } | 1573 } |
1570 } | 1574 } |
1571 | 1575 |
1572 #undef __ | 1576 #undef __ |
1573 | 1577 |
1574 } // namespace compiler | 1578 } // namespace compiler |
1575 } // namespace internal | 1579 } // namespace internal |
1576 } // namespace v8 | 1580 } // namespace v8 |
OLD | NEW |