| 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::SetupStackPointer() {} |
| 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. | |
| 1353 if (return_label_.is_bound()) { | 1356 if (return_label_.is_bound()) { |
| 1354 __ b(&return_label_); | 1357 __ b(&return_label_); |
| 1355 return; | 1358 return; |
| 1356 } else { | 1359 } else { |
| 1357 __ bind(&return_label_); | 1360 __ bind(&return_label_); |
| 1358 __ LeaveFrame(StackFrame::MANUAL); | 1361 AssembleDeconstructFrame(); |
| 1359 } | 1362 } |
| 1360 } | 1363 } |
| 1361 __ Ret(pop_count); | 1364 __ Ret(pop_count); |
| 1362 } | 1365 } |
| 1363 | 1366 |
| 1364 | 1367 |
| 1365 void CodeGenerator::AssembleMove(InstructionOperand* source, | 1368 void CodeGenerator::AssembleMove(InstructionOperand* source, |
| 1366 InstructionOperand* destination) { | 1369 InstructionOperand* destination) { |
| 1367 ArmOperandConverter g(this, nullptr); | 1370 ArmOperandConverter g(this, nullptr); |
| 1368 // Dispatch on the source and destination operand kinds. Not all | 1371 // 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; | 1570 padding_size -= v8::internal::Assembler::kInstrSize; |
| 1568 } | 1571 } |
| 1569 } | 1572 } |
| 1570 } | 1573 } |
| 1571 | 1574 |
| 1572 #undef __ | 1575 #undef __ |
| 1573 | 1576 |
| 1574 } // namespace compiler | 1577 } // namespace compiler |
| 1575 } // namespace internal | 1578 } // namespace internal |
| 1576 } // namespace v8 | 1579 } // namespace v8 |
| OLD | NEW |