|
|
@ -91,17 +91,8 @@ void LCodeGen::FinishCode(Handle<Code> code) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::Abort(const char* format, ...) { |
|
|
|
if (FLAG_trace_bailout) { |
|
|
|
SmartArrayPointer<char> name( |
|
|
|
info()->shared_info()->DebugName()->ToCString()); |
|
|
|
PrintF("Aborting LCodeGen in @\"%s\": ", *name); |
|
|
|
va_list arguments; |
|
|
|
va_start(arguments, format); |
|
|
|
OS::VPrint(format, arguments); |
|
|
|
va_end(arguments); |
|
|
|
PrintF("\n"); |
|
|
|
} |
|
|
|
void LCodeGen::Abort(const char* reason) { |
|
|
|
info()->set_bailout_reason(reason); |
|
|
|
status_ = ABORTED; |
|
|
|
} |
|
|
|
|
|
|
@ -127,6 +118,8 @@ void LCodeGen::Comment(const char* format, ...) { |
|
|
|
bool LCodeGen::GeneratePrologue() { |
|
|
|
ASSERT(is_generating()); |
|
|
|
|
|
|
|
ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
|
if (strlen(FLAG_stop_at) > 0 && |
|
|
|
info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
|
|
@ -322,7 +315,8 @@ Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) { |
|
|
|
return ToRegister(op->index()); |
|
|
|
} else if (op->IsConstantOperand()) { |
|
|
|
LConstantOperand* const_op = LConstantOperand::cast(op); |
|
|
|
Handle<Object> literal = chunk_->LookupLiteral(const_op); |
|
|
|
HConstant* constant = chunk_->LookupConstant(const_op); |
|
|
|
Handle<Object> literal = constant->handle(); |
|
|
|
Representation r = chunk_->LookupLiteralRepresentation(const_op); |
|
|
|
if (r.IsInteger32()) { |
|
|
|
ASSERT(literal->IsNumber()); |
|
|
@ -360,7 +354,8 @@ DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op, |
|
|
|
return ToDoubleRegister(op->index()); |
|
|
|
} else if (op->IsConstantOperand()) { |
|
|
|
LConstantOperand* const_op = LConstantOperand::cast(op); |
|
|
|
Handle<Object> literal = chunk_->LookupLiteral(const_op); |
|
|
|
HConstant* constant = chunk_->LookupConstant(const_op); |
|
|
|
Handle<Object> literal = constant->handle(); |
|
|
|
Representation r = chunk_->LookupLiteralRepresentation(const_op); |
|
|
|
if (r.IsInteger32()) { |
|
|
|
ASSERT(literal->IsNumber()); |
|
|
@ -386,9 +381,9 @@ DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op, |
|
|
|
|
|
|
|
|
|
|
|
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { |
|
|
|
Handle<Object> literal = chunk_->LookupLiteral(op); |
|
|
|
HConstant* constant = chunk_->LookupConstant(op); |
|
|
|
ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged()); |
|
|
|
return literal; |
|
|
|
return constant->handle(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -398,33 +393,33 @@ bool LCodeGen::IsInteger32(LConstantOperand* op) const { |
|
|
|
|
|
|
|
|
|
|
|
int LCodeGen::ToInteger32(LConstantOperand* op) const { |
|
|
|
Handle<Object> value = chunk_->LookupLiteral(op); |
|
|
|
HConstant* constant = chunk_->LookupConstant(op); |
|
|
|
ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32()); |
|
|
|
ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) == |
|
|
|
value->Number()); |
|
|
|
return static_cast<int32_t>(value->Number()); |
|
|
|
ASSERT(constant->HasInteger32Value()); |
|
|
|
return constant->Integer32Value(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double LCodeGen::ToDouble(LConstantOperand* op) const { |
|
|
|
Handle<Object> value = chunk_->LookupLiteral(op); |
|
|
|
return value->Number(); |
|
|
|
HConstant* constant = chunk_->LookupConstant(op); |
|
|
|
ASSERT(constant->HasDoubleValue()); |
|
|
|
return constant->DoubleValue(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Operand LCodeGen::ToOperand(LOperand* op) { |
|
|
|
if (op->IsConstantOperand()) { |
|
|
|
LConstantOperand* const_op = LConstantOperand::cast(op); |
|
|
|
Handle<Object> literal = chunk_->LookupLiteral(const_op); |
|
|
|
HConstant* constant = chunk()->LookupConstant(const_op); |
|
|
|
Representation r = chunk_->LookupLiteralRepresentation(const_op); |
|
|
|
if (r.IsInteger32()) { |
|
|
|
ASSERT(literal->IsNumber()); |
|
|
|
return Operand(static_cast<int32_t>(literal->Number())); |
|
|
|
ASSERT(constant->HasInteger32Value()); |
|
|
|
return Operand(constant->Integer32Value()); |
|
|
|
} else if (r.IsDouble()) { |
|
|
|
Abort("ToOperand Unsupported double immediate."); |
|
|
|
} |
|
|
|
ASSERT(r.IsTagged()); |
|
|
|
return Operand(literal); |
|
|
|
return Operand(constant->handle()); |
|
|
|
} else if (op->IsRegister()) { |
|
|
|
return Operand(ToRegister(op)); |
|
|
|
} else if (op->IsDoubleRegister()) { |
|
|
@ -478,7 +473,10 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, |
|
|
|
int height = translation_size - environment->parameter_count(); |
|
|
|
|
|
|
|
WriteTranslation(environment->outer(), translation); |
|
|
|
int closure_id = DefineDeoptimizationLiteral(environment->closure()); |
|
|
|
int closure_id = *info()->closure() != *environment->closure() |
|
|
|
? DefineDeoptimizationLiteral(environment->closure()) |
|
|
|
: Translation::kSelfLiteralId; |
|
|
|
|
|
|
|
switch (environment->frame_type()) { |
|
|
|
case JS_FUNCTION: |
|
|
|
translation->BeginJSFrame(environment->ast_id(), closure_id, height); |
|
|
@ -486,11 +484,19 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, |
|
|
|
case JS_CONSTRUCT: |
|
|
|
translation->BeginConstructStubFrame(closure_id, translation_size); |
|
|
|
break; |
|
|
|
case JS_GETTER: |
|
|
|
ASSERT(translation_size == 1); |
|
|
|
ASSERT(height == 0); |
|
|
|
translation->BeginGetterStubFrame(closure_id); |
|
|
|
break; |
|
|
|
case JS_SETTER: |
|
|
|
ASSERT(translation_size == 2); |
|
|
|
ASSERT(height == 0); |
|
|
|
translation->BeginSetterStubFrame(closure_id); |
|
|
|
break; |
|
|
|
case ARGUMENTS_ADAPTOR: |
|
|
|
translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); |
|
|
|
break; |
|
|
|
default: |
|
|
|
UNREACHABLE(); |
|
|
|
} |
|
|
|
for (int i = 0; i < translation_size; ++i) { |
|
|
|
LOperand* value = environment->values()->at(i); |
|
|
@ -502,7 +508,8 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, |
|
|
|
translation->MarkDuplicate(); |
|
|
|
AddToTranslation(translation, |
|
|
|
environment->spilled_registers()[value->index()], |
|
|
|
environment->HasTaggedValueAt(i)); |
|
|
|
environment->HasTaggedValueAt(i), |
|
|
|
environment->HasUint32ValueAt(i)); |
|
|
|
} else if ( |
|
|
|
value->IsDoubleRegister() && |
|
|
|
environment->spilled_double_registers()[value->index()] != NULL) { |
|
|
@ -510,18 +517,23 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, |
|
|
|
AddToTranslation( |
|
|
|
translation, |
|
|
|
environment->spilled_double_registers()[value->index()], |
|
|
|
false, |
|
|
|
false); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
AddToTranslation(translation, value, environment->HasTaggedValueAt(i)); |
|
|
|
AddToTranslation(translation, |
|
|
|
value, |
|
|
|
environment->HasTaggedValueAt(i), |
|
|
|
environment->HasUint32ValueAt(i)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::AddToTranslation(Translation* translation, |
|
|
|
LOperand* op, |
|
|
|
bool is_tagged) { |
|
|
|
bool is_tagged, |
|
|
|
bool is_uint32) { |
|
|
|
if (op == NULL) { |
|
|
|
// TODO(twuerthinger): Introduce marker operands to indicate that this value
|
|
|
|
// is not present and must be reconstructed from the deoptimizer. Currently
|
|
|
@ -530,6 +542,8 @@ void LCodeGen::AddToTranslation(Translation* translation, |
|
|
|
} else if (op->IsStackSlot()) { |
|
|
|
if (is_tagged) { |
|
|
|
translation->StoreStackSlot(op->index()); |
|
|
|
} else if (is_uint32) { |
|
|
|
translation->StoreUint32StackSlot(op->index()); |
|
|
|
} else { |
|
|
|
translation->StoreInt32StackSlot(op->index()); |
|
|
|
} |
|
|
@ -543,6 +557,8 @@ void LCodeGen::AddToTranslation(Translation* translation, |
|
|
|
Register reg = ToRegister(op); |
|
|
|
if (is_tagged) { |
|
|
|
translation->StoreRegister(reg); |
|
|
|
} else if (is_uint32) { |
|
|
|
translation->StoreUint32Register(reg); |
|
|
|
} else { |
|
|
|
translation->StoreInt32Register(reg); |
|
|
|
} |
|
|
@ -550,8 +566,8 @@ void LCodeGen::AddToTranslation(Translation* translation, |
|
|
|
DoubleRegister reg = ToDoubleRegister(op); |
|
|
|
translation->StoreDoubleRegister(reg); |
|
|
|
} else if (op->IsConstantOperand()) { |
|
|
|
Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op)); |
|
|
|
int src_index = DefineDeoptimizationLiteral(literal); |
|
|
|
HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op)); |
|
|
|
int src_index = DefineDeoptimizationLiteral(constant->handle()); |
|
|
|
translation->StoreLiteral(src_index); |
|
|
|
} else { |
|
|
|
UNREACHABLE(); |
|
|
@ -698,13 +714,13 @@ void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { |
|
|
|
} |
|
|
|
data->SetLiteralArray(*literals); |
|
|
|
|
|
|
|
data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id())); |
|
|
|
data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt())); |
|
|
|
data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_)); |
|
|
|
|
|
|
|
// Populate the deoptimization entries.
|
|
|
|
for (int i = 0; i < length; i++) { |
|
|
|
LEnvironment* env = deoptimizations_[i]; |
|
|
|
data->SetAstId(i, Smi::FromInt(env->ast_id())); |
|
|
|
data->SetAstId(i, env->ast_id()); |
|
|
|
data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); |
|
|
|
data->SetArgumentsStackHeight(i, |
|
|
|
Smi::FromInt(env->arguments_stack_height())); |
|
|
@ -1528,6 +1544,13 @@ void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) { |
|
|
|
Register result = ToRegister(instr->result()); |
|
|
|
Register map = ToRegister(instr->InputAt(0)); |
|
|
|
__ EnumLength(result, map); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoElementsKind(LElementsKind* instr) { |
|
|
|
Register result = ToRegister(instr->result()); |
|
|
|
Register input = ToRegister(instr->InputAt(0)); |
|
|
@ -1574,11 +1597,10 @@ void LCodeGen::DoDateField(LDateField* instr) { |
|
|
|
ASSERT(!scratch.is(scratch0())); |
|
|
|
ASSERT(!scratch.is(object)); |
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
|
__ AbortIfSmi(object); |
|
|
|
__ tst(object, Operand(kSmiTagMask)); |
|
|
|
DeoptimizeIf(eq, instr->environment()); |
|
|
|
__ CompareObjectType(object, scratch, scratch, JS_DATE_TYPE); |
|
|
|
__ Assert(eq, "Trying to get date field from non-date."); |
|
|
|
#endif |
|
|
|
DeoptimizeIf(ne, instr->environment()); |
|
|
|
|
|
|
|
if (index->value() == 0) { |
|
|
|
__ ldr(result, FieldMemOperand(object, JSDate::kValueOffset)); |
|
|
@ -1642,6 +1664,68 @@ void LCodeGen::DoAddI(LAddI* instr) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoMathMinMax(LMathMinMax* instr) { |
|
|
|
LOperand* left = instr->InputAt(0); |
|
|
|
LOperand* right = instr->InputAt(1); |
|
|
|
HMathMinMax::Operation operation = instr->hydrogen()->operation(); |
|
|
|
Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge; |
|
|
|
if (instr->hydrogen()->representation().IsInteger32()) { |
|
|
|
Register left_reg = ToRegister(left); |
|
|
|
Operand right_op = (right->IsRegister() || right->IsConstantOperand()) |
|
|
|
? ToOperand(right) |
|
|
|
: Operand(EmitLoadRegister(right, ip)); |
|
|
|
Register result_reg = ToRegister(instr->result()); |
|
|
|
__ cmp(left_reg, right_op); |
|
|
|
if (!result_reg.is(left_reg)) { |
|
|
|
__ mov(result_reg, left_reg, LeaveCC, condition); |
|
|
|
} |
|
|
|
__ mov(result_reg, right_op, LeaveCC, NegateCondition(condition)); |
|
|
|
} else { |
|
|
|
ASSERT(instr->hydrogen()->representation().IsDouble()); |
|
|
|
DoubleRegister left_reg = ToDoubleRegister(left); |
|
|
|
DoubleRegister right_reg = ToDoubleRegister(right); |
|
|
|
DoubleRegister result_reg = ToDoubleRegister(instr->result()); |
|
|
|
Label check_nan_left, check_zero, return_left, return_right, done; |
|
|
|
__ VFPCompareAndSetFlags(left_reg, right_reg); |
|
|
|
__ b(vs, &check_nan_left); |
|
|
|
__ b(eq, &check_zero); |
|
|
|
__ b(condition, &return_left); |
|
|
|
__ b(al, &return_right); |
|
|
|
|
|
|
|
__ bind(&check_zero); |
|
|
|
__ VFPCompareAndSetFlags(left_reg, 0.0); |
|
|
|
__ b(ne, &return_left); // left == right != 0.
|
|
|
|
// At this point, both left and right are either 0 or -0.
|
|
|
|
if (operation == HMathMinMax::kMathMin) { |
|
|
|
// We could use a single 'vorr' instruction here if we had NEON support.
|
|
|
|
__ vneg(left_reg, left_reg); |
|
|
|
__ vsub(result_reg, left_reg, right_reg); |
|
|
|
__ vneg(result_reg, result_reg); |
|
|
|
} else { |
|
|
|
// Since we operate on +0 and/or -0, vadd and vand have the same effect;
|
|
|
|
// the decision for vadd is easy because vand is a NEON instruction.
|
|
|
|
__ vadd(result_reg, left_reg, right_reg); |
|
|
|
} |
|
|
|
__ b(al, &done); |
|
|
|
|
|
|
|
__ bind(&check_nan_left); |
|
|
|
__ VFPCompareAndSetFlags(left_reg, left_reg); |
|
|
|
__ b(vs, &return_left); // left == NaN.
|
|
|
|
__ bind(&return_right); |
|
|
|
if (!right_reg.is(result_reg)) { |
|
|
|
__ vmov(result_reg, right_reg); |
|
|
|
} |
|
|
|
__ b(al, &done); |
|
|
|
|
|
|
|
__ bind(&return_left); |
|
|
|
if (!left_reg.is(result_reg)) { |
|
|
|
__ vmov(result_reg, left_reg); |
|
|
|
} |
|
|
|
__ bind(&done); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoArithmeticD(LArithmeticD* instr) { |
|
|
|
DoubleRegister left = ToDoubleRegister(instr->InputAt(0)); |
|
|
|
DoubleRegister right = ToDoubleRegister(instr->InputAt(1)); |
|
|
@ -2152,9 +2236,7 @@ void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { |
|
|
|
Register input = ToRegister(instr->InputAt(0)); |
|
|
|
Register result = ToRegister(instr->result()); |
|
|
|
|
|
|
|
if (FLAG_debug_code) { |
|
|
|
__ AbortIfNotString(input); |
|
|
|
} |
|
|
|
__ AbortIfNotString(input); |
|
|
|
|
|
|
|
__ ldr(result, FieldMemOperand(input, String::kHashFieldOffset)); |
|
|
|
__ IndexFromHash(result, result); |
|
|
@ -2390,12 +2472,18 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, |
|
|
|
Register temp = ToRegister(instr->TempAt(0)); |
|
|
|
ASSERT(temp.is(r4)); |
|
|
|
__ LoadHeapObject(InstanceofStub::right(), instr->function()); |
|
|
|
static const int kAdditionalDelta = 4; |
|
|
|
static const int kAdditionalDelta = 5; |
|
|
|
int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta; |
|
|
|
Label before_push_delta; |
|
|
|
__ bind(&before_push_delta); |
|
|
|
__ BlockConstPoolFor(kAdditionalDelta); |
|
|
|
__ mov(temp, Operand(delta * kPointerSize)); |
|
|
|
// The mov above can generate one or two instructions. The delta was computed
|
|
|
|
// for two instructions, so we need to pad here in case of one instruction.
|
|
|
|
if (masm_->InstructionsGeneratedSince(&before_push_delta) != 2) { |
|
|
|
ASSERT_EQ(1, masm_->InstructionsGeneratedSince(&before_push_delta)); |
|
|
|
__ nop(); |
|
|
|
} |
|
|
|
__ StoreToSafepointRegisterSlot(temp, temp); |
|
|
|
CallCodeGeneric(stub.GetCode(), |
|
|
|
RelocInfo::CODE_TARGET, |
|
|
@ -2574,9 +2662,9 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, |
|
|
|
Handle<String> name, |
|
|
|
LEnvironment* env) { |
|
|
|
LookupResult lookup(isolate()); |
|
|
|
type->LookupInDescriptors(NULL, *name, &lookup); |
|
|
|
type->LookupDescriptor(NULL, *name, &lookup); |
|
|
|
ASSERT(lookup.IsFound() || lookup.IsCacheable()); |
|
|
|
if (lookup.IsFound() && lookup.type() == FIELD) { |
|
|
|
if (lookup.IsField()) { |
|
|
|
int index = lookup.GetLocalFieldIndexFromMap(*type); |
|
|
|
int offset = index * kPointerSize; |
|
|
|
if (index < 0) { |
|
|
@ -2588,7 +2676,7 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, |
|
|
|
__ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); |
|
|
|
__ ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize)); |
|
|
|
} |
|
|
|
} else if (lookup.IsFound() && lookup.type() == CONSTANT_FUNCTION) { |
|
|
|
} else if (lookup.IsConstantFunction()) { |
|
|
|
Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type)); |
|
|
|
__ LoadHeapObject(result, function); |
|
|
|
} else { |
|
|
@ -2772,15 +2860,31 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { |
|
|
|
|
|
|
|
void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { |
|
|
|
Register elements = ToRegister(instr->elements()); |
|
|
|
Register key = EmitLoadRegister(instr->key(), scratch0()); |
|
|
|
Register result = ToRegister(instr->result()); |
|
|
|
Register scratch = scratch0(); |
|
|
|
Register store_base = scratch; |
|
|
|
int offset = 0; |
|
|
|
|
|
|
|
// Load the result.
|
|
|
|
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); |
|
|
|
uint32_t offset = FixedArray::kHeaderSize + |
|
|
|
(instr->additional_index() << kPointerSizeLog2); |
|
|
|
__ ldr(result, FieldMemOperand(scratch, offset)); |
|
|
|
if (instr->key()->IsConstantOperand()) { |
|
|
|
LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); |
|
|
|
offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + |
|
|
|
instr->additional_index()); |
|
|
|
store_base = elements; |
|
|
|
} else { |
|
|
|
Register key = EmitLoadRegister(instr->key(), scratch0()); |
|
|
|
// Even though the HLoadKeyedFastElement instruction forces the input
|
|
|
|
// representation for the key to be an integer, the input gets replaced
|
|
|
|
// during bound check elimination with the index argument to the bounds
|
|
|
|
// check, which can be tagged, so that case must be handled here, too.
|
|
|
|
if (instr->hydrogen()->key()->representation().IsTagged()) { |
|
|
|
__ add(scratch, elements, |
|
|
|
Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); |
|
|
|
} else { |
|
|
|
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); |
|
|
|
} |
|
|
|
offset = FixedArray::OffsetOfElementAt(instr->additional_index()); |
|
|
|
} |
|
|
|
__ ldr(result, FieldMemOperand(store_base, offset)); |
|
|
|
|
|
|
|
// Check for the hole value.
|
|
|
|
if (instr->hydrogen()->RequiresHoleCheck()) { |
|
|
@ -2804,8 +2908,9 @@ void LCodeGen::DoLoadKeyedFastDoubleElement( |
|
|
|
DwVfpRegister result = ToDoubleRegister(instr->result()); |
|
|
|
Register scratch = scratch0(); |
|
|
|
|
|
|
|
int shift_size = |
|
|
|
ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); |
|
|
|
int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); |
|
|
|
int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) |
|
|
|
? (element_size_shift - kSmiTagSize) : element_size_shift; |
|
|
|
int constant_key = 0; |
|
|
|
if (key_is_constant) { |
|
|
|
constant_key = ToInteger32(LConstantOperand::cast(instr->key())); |
|
|
@ -2817,14 +2922,15 @@ void LCodeGen::DoLoadKeyedFastDoubleElement( |
|
|
|
} |
|
|
|
|
|
|
|
Operand operand = key_is_constant |
|
|
|
? Operand(((constant_key + instr->additional_index()) << shift_size) + |
|
|
|
? Operand(((constant_key + instr->additional_index()) << |
|
|
|
element_size_shift) + |
|
|
|
FixedDoubleArray::kHeaderSize - kHeapObjectTag) |
|
|
|
: Operand(key, LSL, shift_size); |
|
|
|
__ add(elements, elements, operand); |
|
|
|
if (!key_is_constant) { |
|
|
|
__ add(elements, elements, |
|
|
|
Operand((FixedDoubleArray::kHeaderSize - kHeapObjectTag) + |
|
|
|
(instr->additional_index() << shift_size))); |
|
|
|
(instr->additional_index() << element_size_shift))); |
|
|
|
} |
|
|
|
|
|
|
|
if (instr->hydrogen()->RequiresHoleCheck()) { |
|
|
@ -2837,6 +2943,42 @@ void LCodeGen::DoLoadKeyedFastDoubleElement( |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
MemOperand LCodeGen::PrepareKeyedOperand(Register key, |
|
|
|
Register base, |
|
|
|
bool key_is_constant, |
|
|
|
int constant_key, |
|
|
|
int element_size, |
|
|
|
int shift_size, |
|
|
|
int additional_index, |
|
|
|
int additional_offset) { |
|
|
|
if (additional_index != 0 && !key_is_constant) { |
|
|
|
additional_index *= 1 << (element_size - shift_size); |
|
|
|
__ add(scratch0(), key, Operand(additional_index)); |
|
|
|
} |
|
|
|
|
|
|
|
if (key_is_constant) { |
|
|
|
return MemOperand(base, |
|
|
|
(constant_key << element_size) + additional_offset); |
|
|
|
} |
|
|
|
|
|
|
|
if (additional_index == 0) { |
|
|
|
if (shift_size >= 0) { |
|
|
|
return MemOperand(base, key, LSL, shift_size); |
|
|
|
} else { |
|
|
|
ASSERT_EQ(-1, shift_size); |
|
|
|
return MemOperand(base, key, LSR, 1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (shift_size >= 0) { |
|
|
|
return MemOperand(base, scratch0(), LSL, shift_size); |
|
|
|
} else { |
|
|
|
ASSERT_EQ(-1, shift_size); |
|
|
|
return MemOperand(base, scratch0(), LSR, 1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoLoadKeyedSpecializedArrayElement( |
|
|
|
LLoadKeyedSpecializedArrayElement* instr) { |
|
|
|
Register external_pointer = ToRegister(instr->external_pointer()); |
|
|
@ -2852,15 +2994,17 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement( |
|
|
|
} else { |
|
|
|
key = ToRegister(instr->key()); |
|
|
|
} |
|
|
|
int shift_size = ElementsKindToShiftSize(elements_kind); |
|
|
|
int additional_offset = instr->additional_index() << shift_size; |
|
|
|
int element_size_shift = ElementsKindToShiftSize(elements_kind); |
|
|
|
int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) |
|
|
|
? (element_size_shift - kSmiTagSize) : element_size_shift; |
|
|
|
int additional_offset = instr->additional_index() << element_size_shift; |
|
|
|
|
|
|
|
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || |
|
|
|
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
|
|
|
CpuFeatures::Scope scope(VFP3); |
|
|
|
DwVfpRegister result = ToDoubleRegister(instr->result()); |
|
|
|
Operand operand = key_is_constant |
|
|
|
? Operand(constant_key << shift_size) |
|
|
|
? Operand(constant_key << element_size_shift) |
|
|
|
: Operand(key, LSL, shift_size); |
|
|
|
__ add(scratch0(), external_pointer, operand); |
|
|
|
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
|
|
@ -2871,15 +3015,10 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement( |
|
|
|
} |
|
|
|
} else { |
|
|
|
Register result = ToRegister(instr->result()); |
|
|
|
if (instr->additional_index() != 0 && !key_is_constant) { |
|
|
|
__ add(scratch0(), key, Operand(instr->additional_index())); |
|
|
|
} |
|
|
|
MemOperand mem_operand(key_is_constant |
|
|
|
? MemOperand(external_pointer, |
|
|
|
(constant_key << shift_size) + additional_offset) |
|
|
|
: (instr->additional_index() == 0 |
|
|
|
? MemOperand(external_pointer, key, LSL, shift_size) |
|
|
|
: MemOperand(external_pointer, scratch0(), LSL, shift_size))); |
|
|
|
MemOperand mem_operand = PrepareKeyedOperand( |
|
|
|
key, external_pointer, key_is_constant, constant_key, |
|
|
|
element_size_shift, shift_size, |
|
|
|
instr->additional_index(), additional_offset); |
|
|
|
switch (elements_kind) { |
|
|
|
case EXTERNAL_BYTE_ELEMENTS: |
|
|
|
__ ldrsb(result, mem_operand); |
|
|
@ -2899,11 +3038,10 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement( |
|
|
|
break; |
|
|
|
case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
|
|
|
__ ldr(result, mem_operand); |
|
|
|
__ cmp(result, Operand(0x80000000)); |
|
|
|
// TODO(danno): we could be more clever here, perhaps having a special
|
|
|
|
// version of the stub that detects if the overflow case actually
|
|
|
|
// happens, and generate code that returns a double rather than int.
|
|
|
|
DeoptimizeIf(cs, instr->environment()); |
|
|
|
if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { |
|
|
|
__ cmp(result, Operand(0x80000000)); |
|
|
|
DeoptimizeIf(cs, instr->environment()); |
|
|
|
} |
|
|
|
break; |
|
|
|
case EXTERNAL_FLOAT_ELEMENTS: |
|
|
|
case EXTERNAL_DOUBLE_ELEMENTS: |
|
|
@ -3089,7 +3227,7 @@ void LCodeGen::DoDrop(LDrop* instr) { |
|
|
|
|
|
|
|
void LCodeGen::DoThisFunction(LThisFunction* instr) { |
|
|
|
Register result = ToRegister(instr->result()); |
|
|
|
__ LoadHeapObject(result, instr->hydrogen()->closure()); |
|
|
|
__ ldr(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3119,7 +3257,7 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { |
|
|
|
|
|
|
|
void LCodeGen::DoGlobalObject(LGlobalObject* instr) { |
|
|
|
Register result = ToRegister(instr->result()); |
|
|
|
__ ldr(result, ContextOperand(cp, Context::GLOBAL_INDEX)); |
|
|
|
__ ldr(result, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3146,14 +3284,8 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
|
|
|
__ LoadHeapObject(r1, function); |
|
|
|
} |
|
|
|
|
|
|
|
// Change context if needed.
|
|
|
|
bool change_context = |
|
|
|
(info()->closure()->context() != function->context()) || |
|
|
|
scope()->contains_with() || |
|
|
|
(scope()->num_heap_slots() > 0); |
|
|
|
if (change_context) { |
|
|
|
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
|
|
|
} |
|
|
|
// Change context.
|
|
|
|
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
|
|
|
|
|
|
|
// Set r0 to arguments count if adaption is not needed. Assumes that r0
|
|
|
|
// is available to write to at this point.
|
|
|
@ -3481,11 +3613,11 @@ void LCodeGen::DoRandom(LRandom* instr) { |
|
|
|
static const int kSeedSize = sizeof(uint32_t); |
|
|
|
STATIC_ASSERT(kPointerSize == kSeedSize); |
|
|
|
|
|
|
|
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset)); |
|
|
|
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kNativeContextOffset)); |
|
|
|
static const int kRandomSeedOffset = |
|
|
|
FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize; |
|
|
|
__ ldr(r2, FieldMemOperand(r0, kRandomSeedOffset)); |
|
|
|
// r2: FixedArray of the global context's random seeds
|
|
|
|
// r2: FixedArray of the native context's random seeds
|
|
|
|
|
|
|
|
// Load state[0].
|
|
|
|
__ ldr(r1, FieldMemOperand(r2, ByteArray::kHeaderSize)); |
|
|
@ -3775,8 +3907,40 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DeoptIfTaggedButNotSmi(LEnvironment* environment, |
|
|
|
HValue* value, |
|
|
|
LOperand* operand) { |
|
|
|
if (value->representation().IsTagged() && !value->type().IsSmi()) { |
|
|
|
if (operand->IsRegister()) { |
|
|
|
__ tst(ToRegister(operand), Operand(kSmiTagMask)); |
|
|
|
} else { |
|
|
|
__ mov(ip, ToOperand(operand)); |
|
|
|
__ tst(ip, Operand(kSmiTagMask)); |
|
|
|
} |
|
|
|
DeoptimizeIf(ne, environment); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { |
|
|
|
__ cmp(ToRegister(instr->index()), ToRegister(instr->length())); |
|
|
|
DeoptIfTaggedButNotSmi(instr->environment(), |
|
|
|
instr->hydrogen()->length(), |
|
|
|
instr->length()); |
|
|
|
DeoptIfTaggedButNotSmi(instr->environment(), |
|
|
|
instr->hydrogen()->index(), |
|
|
|
instr->index()); |
|
|
|
if (instr->index()->IsConstantOperand()) { |
|
|
|
int constant_index = |
|
|
|
ToInteger32(LConstantOperand::cast(instr->index())); |
|
|
|
if (instr->hydrogen()->length()->representation().IsTagged()) { |
|
|
|
__ mov(ip, Operand(Smi::FromInt(constant_index))); |
|
|
|
} else { |
|
|
|
__ mov(ip, Operand(constant_index)); |
|
|
|
} |
|
|
|
__ cmp(ip, ToRegister(instr->length())); |
|
|
|
} else { |
|
|
|
__ cmp(ToRegister(instr->index()), ToRegister(instr->length())); |
|
|
|
} |
|
|
|
DeoptimizeIf(hs, instr->environment()); |
|
|
|
} |
|
|
|
|
|
|
@ -3786,31 +3950,37 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { |
|
|
|
Register elements = ToRegister(instr->object()); |
|
|
|
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; |
|
|
|
Register scratch = scratch0(); |
|
|
|
Register store_base = scratch; |
|
|
|
int offset = 0; |
|
|
|
|
|
|
|
// Do the store.
|
|
|
|
if (instr->key()->IsConstantOperand()) { |
|
|
|
ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); |
|
|
|
LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); |
|
|
|
int offset = |
|
|
|
(ToInteger32(const_operand) + instr->additional_index()) * kPointerSize |
|
|
|
+ FixedArray::kHeaderSize; |
|
|
|
__ str(value, FieldMemOperand(elements, offset)); |
|
|
|
offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + |
|
|
|
instr->additional_index()); |
|
|
|
store_base = elements; |
|
|
|
} else { |
|
|
|
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); |
|
|
|
if (instr->additional_index() != 0) { |
|
|
|
__ add(scratch, |
|
|
|
scratch, |
|
|
|
Operand(instr->additional_index() << kPointerSizeLog2)); |
|
|
|
// Even though the HLoadKeyedFastElement instruction forces the input
|
|
|
|
// representation for the key to be an integer, the input gets replaced
|
|
|
|
// during bound check elimination with the index argument to the bounds
|
|
|
|
// check, which can be tagged, so that case must be handled here, too.
|
|
|
|
if (instr->hydrogen()->key()->representation().IsTagged()) { |
|
|
|
__ add(scratch, elements, |
|
|
|
Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize)); |
|
|
|
} else { |
|
|
|
__ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); |
|
|
|
} |
|
|
|
__ str(value, FieldMemOperand(scratch, FixedArray::kHeaderSize)); |
|
|
|
offset = FixedArray::OffsetOfElementAt(instr->additional_index()); |
|
|
|
} |
|
|
|
__ str(value, FieldMemOperand(store_base, offset)); |
|
|
|
|
|
|
|
if (instr->hydrogen()->NeedsWriteBarrier()) { |
|
|
|
HType type = instr->hydrogen()->value()->type(); |
|
|
|
SmiCheck check_needed = |
|
|
|
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
|
|
|
// Compute address of modified element and store it into key register.
|
|
|
|
__ add(key, scratch, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
|
|
|
__ add(key, store_base, Operand(offset - kHeapObjectTag)); |
|
|
|
__ RecordWrite(elements, |
|
|
|
key, |
|
|
|
value, |
|
|
@ -3841,9 +4011,11 @@ void LCodeGen::DoStoreKeyedFastDoubleElement( |
|
|
|
} else { |
|
|
|
key = ToRegister(instr->key()); |
|
|
|
} |
|
|
|
int shift_size = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); |
|
|
|
int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); |
|
|
|
int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) |
|
|
|
? (element_size_shift - kSmiTagSize) : element_size_shift; |
|
|
|
Operand operand = key_is_constant |
|
|
|
? Operand((constant_key << shift_size) + |
|
|
|
? Operand((constant_key << element_size_shift) + |
|
|
|
FixedDoubleArray::kHeaderSize - kHeapObjectTag) |
|
|
|
: Operand(key, LSL, shift_size); |
|
|
|
__ add(scratch, elements, operand); |
|
|
@ -3861,7 +4033,7 @@ void LCodeGen::DoStoreKeyedFastDoubleElement( |
|
|
|
vs); |
|
|
|
} |
|
|
|
|
|
|
|
__ vstr(value, scratch, instr->additional_index() << shift_size); |
|
|
|
__ vstr(value, scratch, instr->additional_index() << element_size_shift); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3881,15 +4053,18 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement( |
|
|
|
} else { |
|
|
|
key = ToRegister(instr->key()); |
|
|
|
} |
|
|
|
int shift_size = ElementsKindToShiftSize(elements_kind); |
|
|
|
int additional_offset = instr->additional_index() << shift_size; |
|
|
|
int element_size_shift = ElementsKindToShiftSize(elements_kind); |
|
|
|
int shift_size = (instr->hydrogen()->key()->representation().IsTagged()) |
|
|
|
? (element_size_shift - kSmiTagSize) : element_size_shift; |
|
|
|
int additional_offset = instr->additional_index() << element_size_shift; |
|
|
|
|
|
|
|
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || |
|
|
|
elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { |
|
|
|
CpuFeatures::Scope scope(VFP3); |
|
|
|
DwVfpRegister value(ToDoubleRegister(instr->value())); |
|
|
|
Operand operand(key_is_constant ? Operand(constant_key << shift_size) |
|
|
|
: Operand(key, LSL, shift_size)); |
|
|
|
Operand operand(key_is_constant |
|
|
|
? Operand(constant_key << element_size_shift) |
|
|
|
: Operand(key, LSL, shift_size)); |
|
|
|
__ add(scratch0(), external_pointer, operand); |
|
|
|
if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { |
|
|
|
__ vcvt_f32_f64(double_scratch0().low(), value); |
|
|
@ -3899,16 +4074,10 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement( |
|
|
|
} |
|
|
|
} else { |
|
|
|
Register value(ToRegister(instr->value())); |
|
|
|
if (instr->additional_index() != 0 && !key_is_constant) { |
|
|
|
__ add(scratch0(), key, Operand(instr->additional_index())); |
|
|
|
} |
|
|
|
MemOperand mem_operand(key_is_constant |
|
|
|
? MemOperand(external_pointer, |
|
|
|
((constant_key + instr->additional_index()) |
|
|
|
<< shift_size)) |
|
|
|
: (instr->additional_index() == 0 |
|
|
|
? MemOperand(external_pointer, key, LSL, shift_size) |
|
|
|
: MemOperand(external_pointer, scratch0(), LSL, shift_size))); |
|
|
|
MemOperand mem_operand = PrepareKeyedOperand( |
|
|
|
key, external_pointer, key_is_constant, constant_key, |
|
|
|
element_size_shift, shift_size, |
|
|
|
instr->additional_index(), additional_offset); |
|
|
|
switch (elements_kind) { |
|
|
|
case EXTERNAL_PIXEL_ELEMENTS: |
|
|
|
case EXTERNAL_BYTE_ELEMENTS: |
|
|
@ -4131,12 +4300,26 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { |
|
|
|
LOperand* input = instr->InputAt(0); |
|
|
|
LOperand* output = instr->result(); |
|
|
|
|
|
|
|
SwVfpRegister flt_scratch = double_scratch0().low(); |
|
|
|
__ vmov(flt_scratch, ToRegister(input)); |
|
|
|
__ vcvt_f64_u32(ToDoubleRegister(output), flt_scratch); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoNumberTagI(LNumberTagI* instr) { |
|
|
|
class DeferredNumberTagI: public LDeferredCode { |
|
|
|
public: |
|
|
|
DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) |
|
|
|
: LDeferredCode(codegen), instr_(instr) { } |
|
|
|
virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); } |
|
|
|
virtual void Generate() { |
|
|
|
codegen()->DoDeferredNumberTagI(instr_, |
|
|
|
instr_->InputAt(0), |
|
|
|
SIGNED_INT32); |
|
|
|
} |
|
|
|
virtual LInstruction* instr() { return instr_; } |
|
|
|
private: |
|
|
|
LNumberTagI* instr_; |
|
|
@ -4152,9 +4335,38 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { |
|
|
|
void LCodeGen::DoNumberTagU(LNumberTagU* instr) { |
|
|
|
class DeferredNumberTagU: public LDeferredCode { |
|
|
|
public: |
|
|
|
DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr) |
|
|
|
: LDeferredCode(codegen), instr_(instr) { } |
|
|
|
virtual void Generate() { |
|
|
|
codegen()->DoDeferredNumberTagI(instr_, |
|
|
|
instr_->InputAt(0), |
|
|
|
UNSIGNED_INT32); |
|
|
|
} |
|
|
|
virtual LInstruction* instr() { return instr_; } |
|
|
|
private: |
|
|
|
LNumberTagU* instr_; |
|
|
|
}; |
|
|
|
|
|
|
|
LOperand* input = instr->InputAt(0); |
|
|
|
ASSERT(input->IsRegister() && input->Equals(instr->result())); |
|
|
|
Register reg = ToRegister(input); |
|
|
|
|
|
|
|
DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr); |
|
|
|
__ cmp(reg, Operand(Smi::kMaxValue)); |
|
|
|
__ b(hi, deferred->entry()); |
|
|
|
__ SmiTag(reg, reg); |
|
|
|
__ bind(deferred->exit()); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, |
|
|
|
LOperand* value, |
|
|
|
IntegerSignedness signedness) { |
|
|
|
Label slow; |
|
|
|
Register src = ToRegister(instr->InputAt(0)); |
|
|
|
Register src = ToRegister(value); |
|
|
|
Register dst = ToRegister(instr->result()); |
|
|
|
DoubleRegister dbl_scratch = double_scratch0(); |
|
|
|
SwVfpRegister flt_scratch = dbl_scratch.low(); |
|
|
@ -4162,16 +4374,22 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { |
|
|
|
// Preserve the value of all registers.
|
|
|
|
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); |
|
|
|
|
|
|
|
// There was overflow, so bits 30 and 31 of the original integer
|
|
|
|
// disagree. Try to allocate a heap number in new space and store
|
|
|
|
// the value in there. If that fails, call the runtime system.
|
|
|
|
Label done; |
|
|
|
if (dst.is(src)) { |
|
|
|
__ SmiUntag(src, dst); |
|
|
|
__ eor(src, src, Operand(0x80000000)); |
|
|
|
if (signedness == SIGNED_INT32) { |
|
|
|
// There was overflow, so bits 30 and 31 of the original integer
|
|
|
|
// disagree. Try to allocate a heap number in new space and store
|
|
|
|
// the value in there. If that fails, call the runtime system.
|
|
|
|
if (dst.is(src)) { |
|
|
|
__ SmiUntag(src, dst); |
|
|
|
__ eor(src, src, Operand(0x80000000)); |
|
|
|
} |
|
|
|
__ vmov(flt_scratch, src); |
|
|
|
__ vcvt_f64_s32(dbl_scratch, flt_scratch); |
|
|
|
} else { |
|
|
|
__ vmov(flt_scratch, src); |
|
|
|
__ vcvt_f64_u32(dbl_scratch, flt_scratch); |
|
|
|
} |
|
|
|
__ vmov(flt_scratch, src); |
|
|
|
__ vcvt_f64_s32(dbl_scratch, flt_scratch); |
|
|
|
|
|
|
|
if (FLAG_inline_new) { |
|
|
|
__ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); |
|
|
|
__ AllocateHeapNumber(r5, r3, r4, r6, &slow); |
|
|
@ -4751,7 +4969,7 @@ void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { |
|
|
|
|
|
|
|
|
|
|
|
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { |
|
|
|
Heap* heap = isolate()->heap(); |
|
|
|
Handle<FixedArray> literals(instr->environment()->closure()->literals()); |
|
|
|
ElementsKind boilerplate_elements_kind = |
|
|
|
instr->hydrogen()->boilerplate_elements_kind(); |
|
|
|
|
|
|
@ -4771,12 +4989,12 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { |
|
|
|
DeoptimizeIf(ne, instr->environment()); |
|
|
|
} |
|
|
|
|
|
|
|
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
|
|
|
__ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); |
|
|
|
// Set up the parameters to the stub/runtime call.
|
|
|
|
__ LoadHeapObject(r3, literals); |
|
|
|
__ mov(r2, Operand(Smi::FromInt(instr->hydrogen()->literal_index()))); |
|
|
|
// Boilerplate already exists, constant elements are never accessed.
|
|
|
|
// Pass an empty fixed array.
|
|
|
|
__ mov(r1, Operand(Handle<FixedArray>(heap->empty_fixed_array()))); |
|
|
|
__ mov(r1, Operand(isolate()->factory()->empty_fixed_array())); |
|
|
|
__ Push(r3, r2, r1); |
|
|
|
|
|
|
|
// Pick the right runtime function or stub to call.
|
|
|
@ -4870,8 +5088,8 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, |
|
|
|
for (int i = 0; i < elements_length; i++) { |
|
|
|
int64_t value = double_array->get_representation(i); |
|
|
|
// We only support little endian mode...
|
|
|
|
int32_t value_low = value & 0xFFFFFFFF; |
|
|
|
int32_t value_high = value >> 32; |
|
|
|
int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF); |
|
|
|
int32_t value_high = static_cast<int32_t>(value >> 32); |
|
|
|
int total_offset = |
|
|
|
elements_offset + FixedDoubleArray::OffsetOfElementAt(i); |
|
|
|
__ mov(r2, Operand(value_low)); |
|
|
@ -4984,15 +5202,13 @@ void LCodeGen::DoToFastProperties(LToFastProperties* instr) { |
|
|
|
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { |
|
|
|
Label materialized; |
|
|
|
// Registers will be used as follows:
|
|
|
|
// r3 = JS function.
|
|
|
|
// r7 = literals array.
|
|
|
|
// r1 = regexp literal.
|
|
|
|
// r0 = regexp literal clone.
|
|
|
|
// r2 and r4-r6 are used as temporaries.
|
|
|
|
__ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
|
|
|
__ ldr(r7, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); |
|
|
|
int literal_offset = FixedArray::kHeaderSize + |
|
|
|
instr->hydrogen()->literal_index() * kPointerSize; |
|
|
|
int literal_offset = |
|
|
|
FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index()); |
|
|
|
__ LoadHeapObject(r7, instr->hydrogen()->literals()); |
|
|
|
__ ldr(r1, FieldMemOperand(r7, literal_offset)); |
|
|
|
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
|
|
|
__ cmp(r1, ip); |
|
|
@ -5356,13 +5572,24 @@ void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { |
|
|
|
void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { |
|
|
|
Register map = ToRegister(instr->map()); |
|
|
|
Register result = ToRegister(instr->result()); |
|
|
|
__ LoadInstanceDescriptors(map, result); |
|
|
|
Register scratch = ToRegister(instr->scratch()); |
|
|
|
Label load_cache, done; |
|
|
|
__ EnumLength(result, map); |
|
|
|
__ cmp(result, Operand(Smi::FromInt(0))); |
|
|
|
__ b(ne, &load_cache); |
|
|
|
__ mov(result, Operand(isolate()->factory()->empty_fixed_array())); |
|
|
|
__ jmp(&done); |
|
|
|
|
|
|
|
__ bind(&load_cache); |
|
|
|
__ LoadInstanceDescriptors(map, result, scratch); |
|
|
|
__ ldr(result, |
|
|
|
FieldMemOperand(result, DescriptorArray::kEnumerationIndexOffset)); |
|
|
|
FieldMemOperand(result, DescriptorArray::kEnumCacheOffset)); |
|
|
|
__ ldr(result, |
|
|
|
FieldMemOperand(result, FixedArray::SizeFor(instr->idx()))); |
|
|
|
__ cmp(result, Operand(0)); |
|
|
|
DeoptimizeIf(eq, instr->environment()); |
|
|
|
|
|
|
|
__ bind(&done); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|