Upgrade V8 to version 4.9.385.28
https://chromium.googlesource.com/v8/v8/+/4.9.385.28
FPIIM-449
Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/compiler/arm/code-generator-arm.cc b/src/compiler/arm/code-generator-arm.cc
index cfa4de9..9b074b0 100644
--- a/src/compiler/arm/code-generator-arm.cc
+++ b/src/compiler/arm/code-generator-arm.cc
@@ -5,11 +5,11 @@
#include "src/compiler/code-generator.h"
#include "src/arm/macro-assembler-arm.h"
+#include "src/ast/scopes.h"
#include "src/compiler/code-generator-impl.h"
#include "src/compiler/gap-resolver.h"
#include "src/compiler/node-matchers.h"
-#include "src/compiler/node-properties-inl.h"
-#include "src/scopes.h"
+#include "src/compiler/osr.h"
namespace v8 {
namespace internal {
@@ -22,16 +22,16 @@
// Adds Arm-specific methods to convert InstructionOperands.
-class ArmOperandConverter FINAL : public InstructionOperandConverter {
+class ArmOperandConverter final : public InstructionOperandConverter {
public:
ArmOperandConverter(CodeGenerator* gen, Instruction* instr)
: InstructionOperandConverter(gen, instr) {}
- SwVfpRegister OutputFloat32Register(int index = 0) {
+ SwVfpRegister OutputFloat32Register(size_t index = 0) {
return ToFloat32Register(instr_->OutputAt(index));
}
- SwVfpRegister InputFloat32Register(int index) {
+ SwVfpRegister InputFloat32Register(size_t index) {
return ToFloat32Register(instr_->InputAt(index));
}
@@ -39,11 +39,11 @@
return ToFloat64Register(op).low();
}
- LowDwVfpRegister OutputFloat64Register(int index = 0) {
+ LowDwVfpRegister OutputFloat64Register(size_t index = 0) {
return ToFloat64Register(instr_->OutputAt(index));
}
- LowDwVfpRegister InputFloat64Register(int index) {
+ LowDwVfpRegister InputFloat64Register(size_t index) {
return ToFloat64Register(instr_->InputAt(index));
}
@@ -63,7 +63,7 @@
return LeaveCC;
}
- Operand InputImmediate(int index) {
+ Operand InputImmediate(size_t index) {
Constant constant = ToConstant(instr_->InputAt(index));
switch (constant.type()) {
case Constant::kInt32:
@@ -84,8 +84,8 @@
return Operand::Zero();
}
- Operand InputOperand2(int first_index) {
- const int index = first_index;
+ Operand InputOperand2(size_t first_index) {
+ const size_t index = first_index;
switch (AddressingModeField::decode(instr_->opcode())) {
case kMode_None:
case kMode_Offset_RI:
@@ -116,8 +116,8 @@
return Operand::Zero();
}
- MemOperand InputOffset(int* first_index) {
- const int index = *first_index;
+ MemOperand InputOffset(size_t* first_index) {
+ const size_t index = *first_index;
switch (AddressingModeField::decode(instr_->opcode())) {
case kMode_None:
case kMode_Operand2_I:
@@ -142,17 +142,15 @@
return MemOperand(r0);
}
- MemOperand InputOffset(int first_index = 0) {
+ MemOperand InputOffset(size_t first_index = 0) {
return InputOffset(&first_index);
}
MemOperand ToMemOperand(InstructionOperand* op) const {
- DCHECK(op != NULL);
- DCHECK(!op->IsRegister());
- DCHECK(!op->IsDoubleRegister());
+ DCHECK_NOT_NULL(op);
DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
- // The linkage computes where all spill slots are located.
- FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
+ FrameOffset offset = frame_access_state()->GetFrameOffset(
+ AllocatedOperand::cast(op)->index());
return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
}
};
@@ -160,12 +158,12 @@
namespace {
-class OutOfLineLoadFloat32 FINAL : public OutOfLineCode {
+class OutOfLineLoadFloat32 final : public OutOfLineCode {
public:
OutOfLineLoadFloat32(CodeGenerator* gen, SwVfpRegister result)
: OutOfLineCode(gen), result_(result) {}
- void Generate() FINAL {
+ void Generate() final {
__ vmov(result_, std::numeric_limits<float>::quiet_NaN());
}
@@ -174,12 +172,12 @@
};
-class OutOfLineLoadFloat64 FINAL : public OutOfLineCode {
+class OutOfLineLoadFloat64 final : public OutOfLineCode {
public:
OutOfLineLoadFloat64(CodeGenerator* gen, DwVfpRegister result)
: OutOfLineCode(gen), result_(result) {}
- void Generate() FINAL {
+ void Generate() final {
__ vmov(result_, std::numeric_limits<double>::quiet_NaN(), kScratchReg);
}
@@ -188,17 +186,109 @@
};
-class OutOfLineLoadInteger FINAL : public OutOfLineCode {
+class OutOfLineLoadInteger final : public OutOfLineCode {
public:
OutOfLineLoadInteger(CodeGenerator* gen, Register result)
: OutOfLineCode(gen), result_(result) {}
- void Generate() FINAL { __ mov(result_, Operand::Zero()); }
+ void Generate() final { __ mov(result_, Operand::Zero()); }
private:
Register const result_;
};
+
+class OutOfLineRecordWrite final : public OutOfLineCode {
+ public:
+ OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register index,
+ Register value, Register scratch0, Register scratch1,
+ RecordWriteMode mode)
+ : OutOfLineCode(gen),
+ object_(object),
+ index_(index),
+ value_(value),
+ scratch0_(scratch0),
+ scratch1_(scratch1),
+ mode_(mode) {}
+
+ void Generate() final {
+ if (mode_ > RecordWriteMode::kValueIsPointer) {
+ __ JumpIfSmi(value_, exit());
+ }
+ if (mode_ > RecordWriteMode::kValueIsMap) {
+ __ CheckPageFlag(value_, scratch0_,
+ MemoryChunk::kPointersToHereAreInterestingMask, eq,
+ exit());
+ }
+ SaveFPRegsMode const save_fp_mode =
+ frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
+ // TODO(turbofan): Once we get frame elision working, we need to save
+ // and restore lr properly here if the frame was elided.
+ RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
+ EMIT_REMEMBERED_SET, save_fp_mode);
+ __ add(scratch1_, object_, index_);
+ __ CallStub(&stub);
+ }
+
+ private:
+ Register const object_;
+ Register const index_;
+ Register const value_;
+ Register const scratch0_;
+ Register const scratch1_;
+ RecordWriteMode const mode_;
+};
+
+
+Condition FlagsConditionToCondition(FlagsCondition condition) {
+ switch (condition) {
+ case kEqual:
+ return eq;
+ case kNotEqual:
+ return ne;
+ case kSignedLessThan:
+ return lt;
+ case kSignedGreaterThanOrEqual:
+ return ge;
+ case kSignedLessThanOrEqual:
+ return le;
+ case kSignedGreaterThan:
+ return gt;
+ case kUnsignedLessThan:
+ return lo;
+ case kUnsignedGreaterThanOrEqual:
+ return hs;
+ case kUnsignedLessThanOrEqual:
+ return ls;
+ case kUnsignedGreaterThan:
+ return hi;
+ case kFloatLessThanOrUnordered:
+ return lt;
+ case kFloatGreaterThanOrEqual:
+ return ge;
+ case kFloatLessThanOrEqual:
+ return ls;
+ case kFloatGreaterThanOrUnordered:
+ return hi;
+ case kFloatLessThan:
+ return lo;
+ case kFloatGreaterThanOrEqualOrUnordered:
+ return hs;
+ case kFloatLessThanOrEqualOrUnordered:
+ return le;
+ case kFloatGreaterThan:
+ return gt;
+ case kOverflow:
+ return vs;
+ case kNotOverflow:
+ return vc;
+ default:
+ break;
+ }
+ UNREACHABLE();
+ return kNoCondition;
+}
+
} // namespace
@@ -264,10 +354,38 @@
} while (0)
+void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
+ int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
+ if (sp_slot_delta > 0) {
+ __ add(sp, sp, Operand(sp_slot_delta * kPointerSize));
+ }
+ frame_access_state()->SetFrameAccessToDefault();
+}
+
+
+void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
+ int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
+ if (sp_slot_delta < 0) {
+ __ sub(sp, sp, Operand(-sp_slot_delta * kPointerSize));
+ frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
+ }
+ if (frame()->needs_frame()) {
+ if (FLAG_enable_embedded_constant_pool) {
+ __ ldr(cp, MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
+ }
+ __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
+ __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+ }
+ frame_access_state()->SetFrameAccessToSP();
+}
+
+
// Assembles an instruction after register allocation, producing machine code.
void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
ArmOperandConverter i(this, instr);
+ masm()->MaybeCheckConstPool();
+
switch (ArchOpcodeField::decode(instr->opcode())) {
case kArchCallCodeObject: {
EnsureSpaceForLazyDeopt();
@@ -279,8 +397,24 @@
Operand(Code::kHeaderSize - kHeapObjectTag));
__ Call(ip);
}
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
DCHECK_EQ(LeaveCC, i.OutputSBit());
+ frame_access_state()->ClearSPDelta();
+ break;
+ }
+ case kArchTailCallCodeObject: {
+ int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
+ AssembleDeconstructActivationRecord(stack_param_delta);
+ if (instr->InputAt(0)->IsImmediate()) {
+ __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
+ RelocInfo::CODE_TARGET);
+ } else {
+ __ add(ip, i.InputRegister(0),
+ Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Jump(ip);
+ }
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ frame_access_state()->ClearSPDelta();
break;
}
case kArchCallJSFunction: {
@@ -294,18 +428,80 @@
}
__ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
__ Call(ip);
- AddSafepointAndDeopt(instr);
+ RecordCallPosition(instr);
DCHECK_EQ(LeaveCC, i.OutputSBit());
+ frame_access_state()->ClearSPDelta();
+ break;
+ }
+ case kArchTailCallJSFunction: {
+ Register func = i.InputRegister(0);
+ if (FLAG_debug_code) {
+ // Check the function's context matches the context argument.
+ __ ldr(kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset));
+ __ cmp(cp, kScratchReg);
+ __ Assert(eq, kWrongFunctionContext);
+ }
+ int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
+ AssembleDeconstructActivationRecord(stack_param_delta);
+ __ ldr(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
+ __ Jump(ip);
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ frame_access_state()->ClearSPDelta();
+ break;
+ }
+ case kArchLazyBailout: {
+ EnsureSpaceForLazyDeopt();
+ RecordCallPosition(instr);
+ break;
+ }
+ case kArchPrepareCallCFunction: {
+ int const num_parameters = MiscField::decode(instr->opcode());
+ __ PrepareCallCFunction(num_parameters, kScratchReg);
+ // Frame alignment requires using FP-relative frame addressing.
+ frame_access_state()->SetFrameAccessToFP();
+ break;
+ }
+ case kArchPrepareTailCall:
+ AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
+ break;
+ case kArchCallCFunction: {
+ int const num_parameters = MiscField::decode(instr->opcode());
+ if (instr->InputAt(0)->IsImmediate()) {
+ ExternalReference ref = i.InputExternalReference(0);
+ __ CallCFunction(ref, num_parameters);
+ } else {
+ Register func = i.InputRegister(0);
+ __ CallCFunction(func, num_parameters);
+ }
+ frame_access_state()->SetFrameAccessToDefault();
+ frame_access_state()->ClearSPDelta();
break;
}
case kArchJmp:
AssembleArchJump(i.InputRpo(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
+ case kArchLookupSwitch:
+ AssembleArchLookupSwitch(instr);
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArchTableSwitch:
+ AssembleArchTableSwitch(instr);
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
case kArchNop:
+ case kArchThrowTerminator:
// don't emit code for nops.
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
+ case kArchDeoptimize: {
+ int deopt_state_id =
+ BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
+ Deoptimizer::BailoutType bailout_type =
+ Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
+ AssembleDeoptimizerCall(deopt_state_id, bailout_type);
+ break;
+ }
case kArchRet:
AssembleReturn();
DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -314,10 +510,31 @@
__ mov(i.OutputRegister(), sp);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
+ case kArchFramePointer:
+ __ mov(i.OutputRegister(), fp);
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
case kArchTruncateDoubleToI:
__ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
+ case kArchStoreWithWriteBarrier: {
+ RecordWriteMode mode =
+ static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
+ Register object = i.InputRegister(0);
+ Register index = i.InputRegister(1);
+ Register value = i.InputRegister(2);
+ Register scratch0 = i.TempRegister(0);
+ Register scratch1 = i.TempRegister(1);
+ auto ool = new (zone()) OutOfLineRecordWrite(this, object, index, value,
+ scratch0, scratch1, mode);
+ __ str(value, MemOperand(object, index));
+ __ CheckPageFlag(object, scratch0,
+ MemoryChunk::kPointersFromHereAreInterestingMask, ne,
+ ool->entry());
+ __ bind(ool->exit());
+ break;
+ }
case kArmAdd:
__ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
i.OutputSBit());
@@ -441,6 +658,10 @@
i.InputInt32(2));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
+ case kArmClz:
+ __ clz(i.OutputRegister(), i.InputRegister(0));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
case kArmCmp:
__ cmp(i.InputRegister(0), i.InputOperand2(1));
DCHECK_EQ(SetCC, i.OutputSBit());
@@ -457,9 +678,67 @@
__ teq(i.InputRegister(0), i.InputOperand2(1));
DCHECK_EQ(SetCC, i.OutputSBit());
break;
+ case kArmVcmpF32:
+ if (instr->InputAt(1)->IsDoubleRegister()) {
+ __ VFPCompareAndSetFlags(i.InputFloat32Register(0),
+ i.InputFloat32Register(1));
+ } else {
+ DCHECK(instr->InputAt(1)->IsImmediate());
+ // 0.0 is the only immediate supported by vcmp instructions.
+ DCHECK(i.InputFloat32(1) == 0.0f);
+ __ VFPCompareAndSetFlags(i.InputFloat32Register(0), i.InputFloat32(1));
+ }
+ DCHECK_EQ(SetCC, i.OutputSBit());
+ break;
+ case kArmVaddF32:
+ __ vadd(i.OutputFloat32Register(), i.InputFloat32Register(0),
+ i.InputFloat32Register(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmVsubF32:
+ __ vsub(i.OutputFloat32Register(), i.InputFloat32Register(0),
+ i.InputFloat32Register(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmVmulF32:
+ __ vmul(i.OutputFloat32Register(), i.InputFloat32Register(0),
+ i.InputFloat32Register(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmVmlaF32:
+ __ vmla(i.OutputFloat32Register(), i.InputFloat32Register(1),
+ i.InputFloat32Register(2));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmVmlsF32:
+ __ vmls(i.OutputFloat32Register(), i.InputFloat32Register(1),
+ i.InputFloat32Register(2));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmVdivF32:
+ __ vdiv(i.OutputFloat32Register(), i.InputFloat32Register(0),
+ i.InputFloat32Register(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmVsqrtF32:
+ __ vsqrt(i.OutputFloat32Register(), i.InputFloat32Register(0));
+ break;
+ case kArmVabsF32:
+ __ vabs(i.OutputFloat32Register(), i.InputFloat32Register(0));
+ break;
+ case kArmVnegF32:
+ __ vneg(i.OutputFloat32Register(), i.InputFloat32Register(0));
+ break;
case kArmVcmpF64:
- __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
- i.InputFloat64Register(1));
+ if (instr->InputAt(1)->IsDoubleRegister()) {
+ __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
+ i.InputFloat64Register(1));
+ } else {
+ DCHECK(instr->InputAt(1)->IsImmediate());
+ // 0.0 is the only immediate supported by vcmp instructions.
+ DCHECK(i.InputDouble(1) == 0.0);
+ __ VFPCompareAndSetFlags(i.InputFloat64Register(0), i.InputDouble(1));
+ }
DCHECK_EQ(SetCC, i.OutputSBit());
break;
case kArmVaddF64:
@@ -509,21 +788,39 @@
case kArmVsqrtF64:
__ vsqrt(i.OutputFloat64Register(), i.InputFloat64Register(0));
break;
- case kArmVfloorF64:
- __ vrintm(i.OutputFloat64Register(), i.InputFloat64Register(0));
- break;
- case kArmVceilF64:
- __ vrintp(i.OutputFloat64Register(), i.InputFloat64Register(0));
- break;
- case kArmVroundTruncateF64:
- __ vrintz(i.OutputFloat64Register(), i.InputFloat64Register(0));
- break;
- case kArmVroundTiesAwayF64:
- __ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ case kArmVabsF64:
+ __ vabs(i.OutputFloat64Register(), i.InputFloat64Register(0));
break;
case kArmVnegF64:
__ vneg(i.OutputFloat64Register(), i.InputFloat64Register(0));
break;
+ case kArmVrintmF32:
+ __ vrintm(i.OutputFloat32Register(), i.InputFloat32Register(0));
+ break;
+ case kArmVrintmF64:
+ __ vrintm(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ break;
+ case kArmVrintpF32:
+ __ vrintp(i.OutputFloat32Register(), i.InputFloat32Register(0));
+ break;
+ case kArmVrintpF64:
+ __ vrintp(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ break;
+ case kArmVrintzF32:
+ __ vrintz(i.OutputFloat32Register(), i.InputFloat32Register(0));
+ break;
+ case kArmVrintzF64:
+ __ vrintz(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ break;
+ case kArmVrintaF64:
+ __ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ break;
+ case kArmVrintnF32:
+ __ vrintn(i.OutputFloat32Register(), i.InputFloat32Register(0));
+ break;
+ case kArmVrintnF64:
+ __ vrintn(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ break;
case kArmVcvtF32F64: {
__ vcvt_f32_f64(i.OutputFloat32Register(), i.InputFloat64Register(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -562,6 +859,27 @@
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
+ case kArmVmovLowU32F64:
+ __ VmovLow(i.OutputRegister(), i.InputFloat64Register(0));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmVmovLowF64U32:
+ __ VmovLow(i.OutputFloat64Register(), i.InputRegister(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmVmovHighU32F64:
+ __ VmovHigh(i.OutputRegister(), i.InputFloat64Register(0));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmVmovHighF64U32:
+ __ VmovHigh(i.OutputFloat64Register(), i.InputRegister(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmVmovF64U32U32:
+ __ vmov(i.OutputFloat64Register(), i.InputRegister(0),
+ i.InputRegister(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
case kArmLdrb:
__ ldrb(i.OutputRegister(), i.InputOffset());
DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -571,7 +889,7 @@
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmStrb: {
- int index = 0;
+ size_t index = 0;
MemOperand operand = i.InputOffset(&index);
__ strb(i.InputRegister(index), operand);
DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -584,7 +902,7 @@
__ ldrsh(i.OutputRegister(), i.InputOffset());
break;
case kArmStrh: {
- int index = 0;
+ size_t index = 0;
MemOperand operand = i.InputOffset(&index);
__ strh(i.InputRegister(index), operand);
DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -594,7 +912,7 @@
__ ldr(i.OutputRegister(), i.InputOffset());
break;
case kArmStr: {
- int index = 0;
+ size_t index = 0;
MemOperand operand = i.InputOffset(&index);
__ str(i.InputRegister(index), operand);
DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -606,7 +924,7 @@
break;
}
case kArmVstrF32: {
- int index = 0;
+ size_t index = 0;
MemOperand operand = i.InputOffset(&index);
__ vstr(i.InputFloat32Register(index), operand);
DCHECK_EQ(LeaveCC, i.OutputSBit());
@@ -617,26 +935,25 @@
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVstrF64: {
- int index = 0;
+ size_t index = 0;
MemOperand operand = i.InputOffset(&index);
__ vstr(i.InputFloat64Register(index), operand);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmPush:
- __ Push(i.InputRegister(0));
+ if (instr->InputAt(0)->IsDoubleRegister()) {
+ __ vpush(i.InputDoubleRegister(0));
+ frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
+ } else {
+ __ push(i.InputRegister(0));
+ frame_access_state()->IncreaseSPDelta(1);
+ }
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
- case kArmStoreWriteBarrier: {
- Register object = i.InputRegister(0);
- Register index = i.InputRegister(1);
- Register value = i.InputRegister(2);
- __ add(index, object, index);
- __ str(value, MemOperand(index));
- SaveFPRegsMode mode =
- frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
- LinkRegisterStatus lr_status = kLRHasNotBeenSaved;
- __ RecordWrite(object, index, value, lr_status, mode);
+ case kArmPoke: {
+ int const slot = MiscField::decode(instr->opcode());
+ __ str(i.InputRegister(0), MemOperand(sp, slot * kPointerSize));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
@@ -676,8 +993,12 @@
case kCheckedStoreFloat64:
ASSEMBLE_CHECKED_STORE_FLOAT(64);
break;
+ case kCheckedLoadWord64:
+ case kCheckedStoreWord64:
+ UNREACHABLE(); // currently unsupported checked int64 load/store.
+ break;
}
-}
+} // NOLINT(readability/fn_size)
// Assembles branches after an instruction.
@@ -685,70 +1006,13 @@
ArmOperandConverter i(this, instr);
Label* tlabel = branch->true_label;
Label* flabel = branch->false_label;
- switch (branch->condition) {
- case kUnorderedEqual:
- // The "eq" condition will not catch the unordered case.
- // The jump/fall through to false label will be used if the comparison
- // was unordered.
- case kEqual:
- __ b(eq, tlabel);
- break;
- case kUnorderedNotEqual:
- // Unordered or not equal can be tested with "ne" condtion.
- // See ARMv7 manual A8.3 - Conditional execution.
- case kNotEqual:
- __ b(ne, tlabel);
- break;
- case kSignedLessThan:
- __ b(lt, tlabel);
- break;
- case kSignedGreaterThanOrEqual:
- __ b(ge, tlabel);
- break;
- case kSignedLessThanOrEqual:
- __ b(le, tlabel);
- break;
- case kSignedGreaterThan:
- __ b(gt, tlabel);
- break;
- case kUnorderedLessThan:
- // The "lo" condition will not catch the unordered case.
- // The jump/fall through to false label will be used if the comparison
- // was unordered.
- case kUnsignedLessThan:
- __ b(lo, tlabel);
- break;
- case kUnorderedGreaterThanOrEqual:
- // Unordered, greater than or equal can be tested with "hs" condtion.
- // See ARMv7 manual A8.3 - Conditional execution.
- case kUnsignedGreaterThanOrEqual:
- __ b(hs, tlabel);
- break;
- case kUnorderedLessThanOrEqual:
- // The "ls" condition will not catch the unordered case.
- // The jump/fall through to false label will be used if the comparison
- // was unordered.
- case kUnsignedLessThanOrEqual:
- __ b(ls, tlabel);
- break;
- case kUnorderedGreaterThan:
- // Unordered or greater than can be tested with "hi" condtion.
- // See ARMv7 manual A8.3 - Conditional execution.
- case kUnsignedGreaterThan:
- __ b(hi, tlabel);
- break;
- case kOverflow:
- __ b(vs, tlabel);
- break;
- case kNotOverflow:
- __ b(vc, tlabel);
- break;
- }
+ Condition cc = FlagsConditionToCondition(branch->condition);
+ __ b(cc, tlabel);
if (!branch->fallthru) __ b(flabel); // no fallthru to flabel.
}
-void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+void CodeGenerator::AssembleArchJump(RpoNumber target) {
if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
}
@@ -757,169 +1021,160 @@
void CodeGenerator::AssembleArchBoolean(Instruction* instr,
FlagsCondition condition) {
ArmOperandConverter i(this, instr);
- Label done;
// Materialize a full 32-bit 1 or 0 value. The result register is always the
// last output of the instruction.
- Label check;
- DCHECK_NE(0, instr->OutputCount());
+ DCHECK_NE(0u, instr->OutputCount());
Register reg = i.OutputRegister(instr->OutputCount() - 1);
- Condition cc = kNoCondition;
- switch (condition) {
- case kUnorderedEqual:
- __ b(vc, &check);
- __ mov(reg, Operand(0));
- __ b(&done);
- // Fall through.
- case kEqual:
- cc = eq;
- break;
- case kUnorderedNotEqual:
- __ b(vc, &check);
- __ mov(reg, Operand(1));
- __ b(&done);
- // Fall through.
- case kNotEqual:
- cc = ne;
- break;
- case kSignedLessThan:
- cc = lt;
- break;
- case kSignedGreaterThanOrEqual:
- cc = ge;
- break;
- case kSignedLessThanOrEqual:
- cc = le;
- break;
- case kSignedGreaterThan:
- cc = gt;
- break;
- case kUnorderedLessThan:
- __ b(vc, &check);
- __ mov(reg, Operand(0));
- __ b(&done);
- // Fall through.
- case kUnsignedLessThan:
- cc = lo;
- break;
- case kUnorderedGreaterThanOrEqual:
- __ b(vc, &check);
- __ mov(reg, Operand(1));
- __ b(&done);
- // Fall through.
- case kUnsignedGreaterThanOrEqual:
- cc = hs;
- break;
- case kUnorderedLessThanOrEqual:
- __ b(vc, &check);
- __ mov(reg, Operand(0));
- __ b(&done);
- // Fall through.
- case kUnsignedLessThanOrEqual:
- cc = ls;
- break;
- case kUnorderedGreaterThan:
- __ b(vc, &check);
- __ mov(reg, Operand(1));
- __ b(&done);
- // Fall through.
- case kUnsignedGreaterThan:
- cc = hi;
- break;
- case kOverflow:
- cc = vs;
- break;
- case kNotOverflow:
- cc = vc;
- break;
- }
- __ bind(&check);
+ Condition cc = FlagsConditionToCondition(condition);
__ mov(reg, Operand(0));
__ mov(reg, Operand(1), LeaveCC, cc);
- __ bind(&done);
}
-void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
+ ArmOperandConverter i(this, instr);
+ Register input = i.InputRegister(0);
+ for (size_t index = 2; index < instr->InputCount(); index += 2) {
+ __ cmp(input, Operand(i.InputInt32(index + 0)));
+ __ b(eq, GetLabel(i.InputRpo(index + 1)));
+ }
+ AssembleArchJump(i.InputRpo(1));
+}
+
+
+void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
+ ArmOperandConverter i(this, instr);
+ Register input = i.InputRegister(0);
+ size_t const case_count = instr->InputCount() - 2;
+ // Ensure to emit the constant pool first if necessary.
+ __ CheckConstPool(true, true);
+ __ cmp(input, Operand(case_count));
+ __ BlockConstPoolFor(case_count + 2);
+ __ add(pc, pc, Operand(input, LSL, 2), LeaveCC, lo);
+ __ b(GetLabel(i.InputRpo(1)));
+ for (size_t index = 0; index < case_count; ++index) {
+ __ b(GetLabel(i.InputRpo(index + 2)));
+ }
+}
+
+
+void CodeGenerator::AssembleDeoptimizerCall(
+ int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
- isolate(), deoptimization_id, Deoptimizer::LAZY);
+ isolate(), deoptimization_id, bailout_type);
__ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
}
void CodeGenerator::AssemblePrologue() {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
- if (descriptor->kind() == CallDescriptor::kCallAddress) {
- bool saved_pp;
- if (FLAG_enable_ool_constant_pool) {
+ if (descriptor->IsCFunctionCall()) {
+ if (FLAG_enable_embedded_constant_pool) {
__ Push(lr, fp, pp);
// Adjust FP to point to saved FP.
__ sub(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
- saved_pp = true;
} else {
__ Push(lr, fp);
__ mov(fp, sp);
- saved_pp = false;
- }
- const RegList saves = descriptor->CalleeSavedRegisters();
- if (saves != 0 || saved_pp) {
- // Save callee-saved registers.
- int register_save_area_size = saved_pp ? kPointerSize : 0;
- for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
- if (!((1 << i) & saves)) continue;
- register_save_area_size += kPointerSize;
- }
- frame()->SetRegisterSaveAreaSize(register_save_area_size);
- __ stm(db_w, sp, saves);
}
} else if (descriptor->IsJSFunctionCall()) {
- CompilationInfo* info = this->info();
- __ Prologue(info->IsCodePreAgingActive());
- frame()->SetRegisterSaveAreaSize(
- StandardFrameConstants::kFixedFrameSizeFromFp);
- } else {
+ __ Prologue(this->info()->GeneratePreagedPrologue());
+ } else if (frame()->needs_frame()) {
__ StubPrologue();
- frame()->SetRegisterSaveAreaSize(
- StandardFrameConstants::kFixedFrameSizeFromFp);
+ } else {
+ frame()->SetElidedFrameSizeInSlots(0);
}
- int stack_slots = frame()->GetSpillSlotCount();
- if (stack_slots > 0) {
- __ sub(sp, sp, Operand(stack_slots * kPointerSize));
+ frame_access_state()->SetFrameAccessToDefault();
+
+ int stack_shrink_slots = frame()->GetSpillSlotCount();
+ if (info()->is_osr()) {
+ // TurboFan OSR-compiled functions cannot be entered directly.
+ __ Abort(kShouldNotDirectlyEnterOsrFunction);
+
+ // Unoptimized code jumps directly to this entrypoint while the unoptimized
+ // frame is still on the stack. Optimized code uses OSR values directly from
+ // the unoptimized frame. Thus, all that needs to be done is to allocate the
+ // remaining stack slots.
+ if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
+ osr_pc_offset_ = __ pc_offset();
+ // TODO(titzer): cannot address target function == local #-1
+ __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+ stack_shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
+ }
+
+ const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
+ if (saves_fp != 0) {
+ stack_shrink_slots += frame()->AlignSavedCalleeRegisterSlots();
+ }
+ if (stack_shrink_slots > 0) {
+ __ sub(sp, sp, Operand(stack_shrink_slots * kPointerSize));
+ }
+
+ if (saves_fp != 0) {
+ // Save callee-saved FP registers.
+ STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
+ uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
+ uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
+ DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
+ __ vstm(db_w, sp, DwVfpRegister::from_code(first),
+ DwVfpRegister::from_code(last));
+ frame()->AllocateSavedCalleeRegisterSlots((last - first + 1) *
+ (kDoubleSize / kPointerSize));
+ }
+ const RegList saves = FLAG_enable_embedded_constant_pool
+ ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
+ : descriptor->CalleeSavedRegisters();
+ if (saves != 0) {
+ // Save callee-saved registers.
+ __ stm(db_w, sp, saves);
+ frame()->AllocateSavedCalleeRegisterSlots(
+ base::bits::CountPopulation32(saves));
}
}
void CodeGenerator::AssembleReturn() {
CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
- if (descriptor->kind() == CallDescriptor::kCallAddress) {
- if (frame()->GetRegisterSaveAreaSize() > 0) {
- // Remove this frame's spill slots first.
- int stack_slots = frame()->GetSpillSlotCount();
- if (stack_slots > 0) {
- __ add(sp, sp, Operand(stack_slots * kPointerSize));
- }
- // Restore registers.
- const RegList saves = descriptor->CalleeSavedRegisters();
- if (saves != 0) {
- __ ldm(ia_w, sp, saves);
- }
- }
- __ LeaveFrame(StackFrame::MANUAL);
- __ Ret();
- } else {
- __ LeaveFrame(StackFrame::MANUAL);
- int pop_count = descriptor->IsJSFunctionCall()
- ? static_cast<int>(descriptor->JSParameterCount())
- : 0;
- __ Drop(pop_count);
- __ Ret();
+ int pop_count = static_cast<int>(descriptor->StackParameterCount());
+
+ // Restore registers.
+ const RegList saves = FLAG_enable_embedded_constant_pool
+ ? (descriptor->CalleeSavedRegisters() & ~pp.bit())
+ : descriptor->CalleeSavedRegisters();
+ if (saves != 0) {
+ __ ldm(ia_w, sp, saves);
}
+
+ // Restore FP registers.
+ const RegList saves_fp = descriptor->CalleeSavedFPRegisters();
+ if (saves_fp != 0) {
+ STATIC_ASSERT(DwVfpRegister::kMaxNumRegisters == 32);
+ uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
+ uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
+ __ vldm(ia_w, sp, DwVfpRegister::from_code(first),
+ DwVfpRegister::from_code(last));
+ }
+
+ if (descriptor->IsCFunctionCall()) {
+ __ LeaveFrame(StackFrame::MANUAL);
+ } else if (frame()->needs_frame()) {
+ // Canonicalize JSFunction return sites for now.
+ if (return_label_.is_bound()) {
+ __ b(&return_label_);
+ return;
+ } else {
+ __ bind(&return_label_);
+ __ LeaveFrame(StackFrame::MANUAL);
+ }
+ }
+ __ Ret(pop_count);
}
void CodeGenerator::AssembleMove(InstructionOperand* source,
InstructionOperand* destination) {
- ArmOperandConverter g(this, NULL);
+ ArmOperandConverter g(this, nullptr);
// Dispatch on the source and destination operand kinds. Not all
// combinations are possible.
if (source->IsRegister()) {
@@ -963,9 +1218,19 @@
case Constant::kExternalReference:
__ mov(dst, Operand(src.ToExternalReference()));
break;
- case Constant::kHeapObject:
- __ Move(dst, src.ToHeapObject());
+ case Constant::kHeapObject: {
+ Handle<HeapObject> src_object = src.ToHeapObject();
+ Heap::RootListIndex index;
+ int offset;
+ if (IsMaterializableFromFrame(src_object, &offset)) {
+ __ ldr(dst, MemOperand(fp, offset));
+ } else if (IsMaterializableFromRoot(src_object, &index)) {
+ __ LoadRoot(dst, index);
+ } else {
+ __ Move(dst, src_object);
+ }
break;
+ }
case Constant::kRpoNumber:
UNREACHABLE(); // TODO(dcarney): loading RPO constants on arm.
break;
@@ -1017,7 +1282,7 @@
void CodeGenerator::AssembleSwap(InstructionOperand* source,
InstructionOperand* destination) {
- ArmOperandConverter g(this, NULL);
+ ArmOperandConverter g(this, nullptr);
// Dispatch on the source and destination operand kinds. Not all
// combinations are possible.
if (source->IsRegister()) {
@@ -1082,29 +1347,36 @@
}
+void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
+ // On 32-bit ARM we emit the jump tables inline.
+ UNREACHABLE();
+}
+
+
void CodeGenerator::AddNopForSmiCodeInlining() {
// On 32-bit ARM we do not insert nops for inlined Smi code.
}
void CodeGenerator::EnsureSpaceForLazyDeopt() {
+ if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
+ return;
+ }
+
int space_needed = Deoptimizer::patch_size();
- if (!info()->IsStub()) {
- // Ensure that we have enough space after the previous lazy-bailout
- // instruction for patching the code here.
- int current_pc = masm()->pc_offset();
- if (current_pc < last_lazy_deopt_pc_ + space_needed) {
- // Block literal pool emission for duration of padding.
- v8::internal::Assembler::BlockConstPoolScope block_const_pool(masm());
- int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
- DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
- while (padding_size > 0) {
- __ nop();
- padding_size -= v8::internal::Assembler::kInstrSize;
- }
+ // Ensure that we have enough space after the previous lazy-bailout
+ // instruction for patching the code here.
+ int current_pc = masm()->pc_offset();
+ if (current_pc < last_lazy_deopt_pc_ + space_needed) {
+ // Block literal pool emission for duration of padding.
+ v8::internal::Assembler::BlockConstPoolScope block_const_pool(masm());
+ int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
+ DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
+ while (padding_size > 0) {
+ __ nop();
+ padding_size -= v8::internal::Assembler::kInstrSize;
}
}
- MarkLazyDeoptSite();
}
#undef __