diff options
Diffstat (limited to 'src/3rdparty/v8/src/arm/lithium-codegen-arm.cc')
-rw-r--r-- | src/3rdparty/v8/src/arm/lithium-codegen-arm.cc | 1580 |
1 files changed, 983 insertions, 597 deletions
diff --git a/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc b/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc index 90060a9..67773ee 100644 --- a/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc +++ b/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc @@ -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))) { @@ -145,15 +138,23 @@ bool LCodeGen::GeneratePrologue() { // function calls. if (!info_->is_classic_mode() || info_->is_native()) { Label ok; + Label begin; + __ bind(&begin); __ cmp(r5, Operand(0)); __ b(eq, &ok); int receiver_offset = scope()->num_parameters() * kPointerSize; __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); __ str(r2, MemOperand(sp, receiver_offset)); __ bind(&ok); + //ASSERT_EQ(kSizeOfOptimizedStrictModePrologue, ok.pos() - begin.pos()); } + // The following three instructions must remain together and unmodified for + // code aging to work properly. __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); + // Add unused load of ip to ensure prologue sequence is identical for + // full-codegen and lithium-codegen. + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP. // Reserve space for the stack slots needed by the code. @@ -323,7 +324,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()); @@ -361,7 +363,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()); @@ -387,9 +390,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(); } @@ -399,33 +402,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()) { @@ -470,7 +473,9 @@ MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const { void LCodeGen::WriteTranslation(LEnvironment* environment, - Translation* translation) { + Translation* translation, + int* arguments_index, + int* arguments_count) { if (environment == NULL) return; // The translation includes one command per value in the environment. @@ -478,8 +483,21 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, // The output frame height does not include the parameters. int height = translation_size - environment->parameter_count(); - WriteTranslation(environment->outer(), translation); - int closure_id = DefineDeoptimizationLiteral(environment->closure()); + // Function parameters are arguments to the outermost environment. The + // arguments index points to the first element of a sequence of tagged + // values on the stack that represent the arguments. This needs to be + // kept in sync with the LArgumentsElements implementation. + *arguments_index = -environment->parameter_count(); + *arguments_count = environment->parameter_count(); + + WriteTranslation(environment->outer(), + translation, + arguments_index, + arguments_count); + 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); @@ -487,12 +505,31 @@ 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(); } + + // Inlined frames which push their arguments cause the index to be + // bumped and a new stack area to be used for materialization. + if (environment->entry() != NULL && + environment->entry()->arguments_pushed()) { + *arguments_index = *arguments_index < 0 + ? GetStackSlotCount() + : *arguments_index + *arguments_count; + *arguments_count = environment->entry()->arguments_count() + 1; + } + for (int i = 0; i < translation_size; ++i) { LOperand* value = environment->values()->at(i); // spilled_registers_ and spilled_double_registers_ are either @@ -503,7 +540,10 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, translation->MarkDuplicate(); AddToTranslation(translation, environment->spilled_registers()[value->index()], - environment->HasTaggedValueAt(i)); + environment->HasTaggedValueAt(i), + environment->HasUint32ValueAt(i), + *arguments_index, + *arguments_count); } else if ( value->IsDoubleRegister() && environment->spilled_double_registers()[value->index()] != NULL) { @@ -511,26 +551,39 @@ void LCodeGen::WriteTranslation(LEnvironment* environment, AddToTranslation( translation, environment->spilled_double_registers()[value->index()], - false); + false, + false, + *arguments_index, + *arguments_count); } } - AddToTranslation(translation, value, environment->HasTaggedValueAt(i)); + AddToTranslation(translation, + value, + environment->HasTaggedValueAt(i), + environment->HasUint32ValueAt(i), + *arguments_index, + *arguments_count); } } void LCodeGen::AddToTranslation(Translation* translation, LOperand* op, - bool is_tagged) { + bool is_tagged, + bool is_uint32, + int arguments_index, + int arguments_count) { if (op == NULL) { // TODO(twuerthinger): Introduce marker operands to indicate that this value // is not present and must be reconstructed from the deoptimizer. Currently // this is only used for the arguments object. - translation->StoreArgumentsObject(); + translation->StoreArgumentsObject(arguments_index, arguments_count); } else if (op->IsStackSlot()) { if (is_tagged) { translation->StoreStackSlot(op->index()); + } else if (is_uint32) { + translation->StoreUint32StackSlot(op->index()); } else { translation->StoreInt32StackSlot(op->index()); } @@ -544,6 +597,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); } @@ -551,8 +606,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(); @@ -562,19 +617,24 @@ void LCodeGen::AddToTranslation(Translation* translation, void LCodeGen::CallCode(Handle<Code> code, RelocInfo::Mode mode, - LInstruction* instr) { - CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); + LInstruction* instr, + TargetAddressStorageMode storage_mode) { + CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, storage_mode); } void LCodeGen::CallCodeGeneric(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr, - SafepointMode safepoint_mode) { + SafepointMode safepoint_mode, + TargetAddressStorageMode storage_mode) { ASSERT(instr != NULL); + // Block literal pool emission to ensure nop indicating no inlined smi code + // is in the correct position. + Assembler::BlockConstPoolScope block_const_pool(masm()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); - __ Call(code, mode); + __ Call(code, mode, TypeFeedbackId::None(), al, storage_mode); RecordSafepointWithLazyDeopt(instr, safepoint_mode); // Signal that we don't inline smi code before these stubs in the @@ -626,20 +686,22 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, int frame_count = 0; int jsframe_count = 0; + int args_index = 0; + int args_count = 0; for (LEnvironment* e = environment; e != NULL; e = e->outer()) { ++frame_count; if (e->frame_type() == JS_FUNCTION) { ++jsframe_count; } } - Translation translation(&translations_, frame_count, jsframe_count); - WriteTranslation(environment, &translation); + Translation translation(&translations_, frame_count, jsframe_count, zone()); + WriteTranslation(environment, &translation, &args_index, &args_count); int deoptimization_index = deoptimizations_.length(); int pc_offset = masm()->pc_offset(); environment->Register(deoptimization_index, translation.index(), (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); - deoptimizations_.Add(environment); + deoptimizations_.Add(environment, zone()); } } @@ -671,7 +733,7 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { // jump entry if this is the case. if (deopt_jump_table_.is_empty() || (deopt_jump_table_.last().address != entry)) { - deopt_jump_table_.Add(JumpTableEntry(entry)); + deopt_jump_table_.Add(JumpTableEntry(entry), zone()); } __ b(cc, &deopt_jump_table_.last().label); } @@ -695,13 +757,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())); @@ -716,7 +778,7 @@ int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) { for (int i = 0; i < deoptimization_literals_.length(); ++i) { if (deoptimization_literals_[i].is_identical_to(literal)) return i; } - deoptimization_literals_.Add(literal); + deoptimization_literals_.Add(literal, zone()); return result; } @@ -762,14 +824,14 @@ void LCodeGen::RecordSafepoint( for (int i = 0; i < operands->length(); i++) { LOperand* pointer = operands->at(i); if (pointer->IsStackSlot()) { - safepoint.DefinePointerSlot(pointer->index()); + safepoint.DefinePointerSlot(pointer->index(), zone()); } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { - safepoint.DefinePointerRegister(ToRegister(pointer)); + safepoint.DefinePointerRegister(ToRegister(pointer), zone()); } } if (kind & Safepoint::kWithRegisters) { // Register cp always contains a pointer to the context. - safepoint.DefinePointerRegister(cp); + safepoint.DefinePointerRegister(cp, zone()); } } @@ -781,7 +843,7 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers, void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) { - LPointerMap empty_pointers(RelocInfo::kNoPosition); + LPointerMap empty_pointers(RelocInfo::kNoPosition, zone()); RecordSafepoint(&empty_pointers, deopt_mode); } @@ -900,7 +962,7 @@ void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { void LCodeGen::DoModI(LModI* instr) { if (instr->hydrogen()->HasPowerOf2Divisor()) { - Register dividend = ToRegister(instr->InputAt(0)); + Register dividend = ToRegister(instr->left()); Register result = ToRegister(instr->result()); int32_t divisor = @@ -925,112 +987,135 @@ void LCodeGen::DoModI(LModI* instr) { } // These registers hold untagged 32 bit values. - Register left = ToRegister(instr->InputAt(0)); - Register right = ToRegister(instr->InputAt(1)); + Register left = ToRegister(instr->left()); + Register right = ToRegister(instr->right()); Register result = ToRegister(instr->result()); + Label done; - Register scratch = scratch0(); - Register scratch2 = ToRegister(instr->TempAt(0)); - DwVfpRegister dividend = ToDoubleRegister(instr->TempAt(1)); - DwVfpRegister divisor = ToDoubleRegister(instr->TempAt(2)); - DwVfpRegister quotient = double_scratch0(); - - ASSERT(!dividend.is(divisor)); - ASSERT(!dividend.is(quotient)); - ASSERT(!divisor.is(quotient)); - ASSERT(!scratch.is(left)); - ASSERT(!scratch.is(right)); - ASSERT(!scratch.is(result)); + if (CpuFeatures::IsSupported(SUDIV)) { + CpuFeatures::Scope scope(SUDIV); + // Check for x % 0. + if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { + __ cmp(right, Operand(0)); + DeoptimizeIf(eq, instr->environment()); + } - Label done, vfp_modulo, both_positive, right_negative; + // For r3 = r1 % r2; we can have the following ARM code + // sdiv r3, r1, r2 + // mls r3, r3, r2, r1 - // Check for x % 0. - if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { - __ cmp(right, Operand(0)); - DeoptimizeIf(eq, instr->environment()); - } + __ sdiv(result, left, right); + __ mls(result, result, right, left); + __ cmp(result, Operand(0)); + __ b(ne, &done); - __ Move(result, left); + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { + __ cmp(left, Operand(0)); + DeoptimizeIf(lt, instr->environment()); + } + } else { + Register scratch = scratch0(); + Register scratch2 = ToRegister(instr->temp()); + DwVfpRegister dividend = ToDoubleRegister(instr->temp2()); + DwVfpRegister divisor = ToDoubleRegister(instr->temp3()); + DwVfpRegister quotient = double_scratch0(); + + ASSERT(!dividend.is(divisor)); + ASSERT(!dividend.is(quotient)); + ASSERT(!divisor.is(quotient)); + ASSERT(!scratch.is(left)); + ASSERT(!scratch.is(right)); + ASSERT(!scratch.is(result)); + + Label vfp_modulo, both_positive, right_negative; + + // Check for x % 0. + if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { + __ cmp(right, Operand(0)); + DeoptimizeIf(eq, instr->environment()); + } - // (0 % x) must yield 0 (if x is finite, which is the case here). - __ cmp(left, Operand(0)); - __ b(eq, &done); - // Preload right in a vfp register. - __ vmov(divisor.low(), right); - __ b(lt, &vfp_modulo); + __ Move(result, left); - __ cmp(left, Operand(right)); - __ b(lt, &done); - - // Check for (positive) power of two on the right hand side. - __ JumpIfNotPowerOfTwoOrZeroAndNeg(right, - scratch, - &right_negative, - &both_positive); - // Perform modulo operation (scratch contains right - 1). - __ and_(result, scratch, Operand(left)); - __ b(&done); + // (0 % x) must yield 0 (if x is finite, which is the case here). + __ cmp(left, Operand(0)); + __ b(eq, &done); + // Preload right in a vfp register. + __ vmov(divisor.low(), right); + __ b(lt, &vfp_modulo); - __ bind(&right_negative); - // Negate right. The sign of the divisor does not matter. - __ rsb(right, right, Operand(0)); - - __ bind(&both_positive); - const int kUnfolds = 3; - // If the right hand side is smaller than the (nonnegative) - // left hand side, the left hand side is the result. - // Else try a few subtractions of the left hand side. - __ mov(scratch, left); - for (int i = 0; i < kUnfolds; i++) { - // Check if the left hand side is less or equal than the - // the right hand side. - __ cmp(scratch, Operand(right)); - __ mov(result, scratch, LeaveCC, lt); + __ cmp(left, Operand(right)); __ b(lt, &done); - // If not, reduce the left hand side by the right hand - // side and check again. - if (i < kUnfolds - 1) __ sub(scratch, scratch, right); - } - - __ bind(&vfp_modulo); - // Load the arguments in VFP registers. - // The divisor value is preloaded before. Be careful that 'right' is only live - // on entry. - __ vmov(dividend.low(), left); - // From here on don't use right as it may have been reallocated (for example - // to scratch2). - right = no_reg; - - __ vcvt_f64_s32(dividend, dividend.low()); - __ vcvt_f64_s32(divisor, divisor.low()); - - // We do not care about the sign of the divisor. - __ vabs(divisor, divisor); - // Compute the quotient and round it to a 32bit integer. - __ vdiv(quotient, dividend, divisor); - __ vcvt_s32_f64(quotient.low(), quotient); - __ vcvt_f64_s32(quotient, quotient.low()); - - // Compute the remainder in result. - DwVfpRegister double_scratch = dividend; - __ vmul(double_scratch, divisor, quotient); - __ vcvt_s32_f64(double_scratch.low(), double_scratch); - __ vmov(scratch, double_scratch.low()); - - if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { - __ sub(result, left, scratch); - } else { - Label ok; - // Check for -0. - __ sub(scratch2, left, scratch, SetCC); - __ b(ne, &ok); - __ cmp(left, Operand(0)); - DeoptimizeIf(mi, instr->environment()); - __ bind(&ok); - // Load the result and we are done. - __ mov(result, scratch2); - } + // Check for (positive) power of two on the right hand side. + __ JumpIfNotPowerOfTwoOrZeroAndNeg(right, + scratch, + &right_negative, + &both_positive); + // Perform modulo operation (scratch contains right - 1). + __ and_(result, scratch, Operand(left)); + __ b(&done); + + __ bind(&right_negative); + // Negate right. The sign of the divisor does not matter. + __ rsb(right, right, Operand(0)); + + __ bind(&both_positive); + const int kUnfolds = 3; + // If the right hand side is smaller than the (nonnegative) + // left hand side, the left hand side is the result. + // Else try a few subtractions of the left hand side. + __ mov(scratch, left); + for (int i = 0; i < kUnfolds; i++) { + // Check if the left hand side is less or equal than the + // the right hand side. + __ cmp(scratch, Operand(right)); + __ mov(result, scratch, LeaveCC, lt); + __ b(lt, &done); + // If not, reduce the left hand side by the right hand + // side and check again. + if (i < kUnfolds - 1) __ sub(scratch, scratch, right); + } + + __ bind(&vfp_modulo); + // Load the arguments in VFP registers. + // The divisor value is preloaded before. Be careful that 'right' + // is only live on entry. + __ vmov(dividend.low(), left); + // From here on don't use right as it may have been reallocated + // (for example to scratch2). + right = no_reg; + + __ vcvt_f64_s32(dividend, dividend.low()); + __ vcvt_f64_s32(divisor, divisor.low()); + + // We do not care about the sign of the divisor. + __ vabs(divisor, divisor); + // Compute the quotient and round it to a 32bit integer. + __ vdiv(quotient, dividend, divisor); + __ vcvt_s32_f64(quotient.low(), quotient); + __ vcvt_f64_s32(quotient, quotient.low()); + + // Compute the remainder in result. + DwVfpRegister double_scratch = dividend; + __ vmul(double_scratch, divisor, quotient); + __ vcvt_s32_f64(double_scratch.low(), double_scratch); + __ vmov(scratch, double_scratch.low()); + + if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { + __ sub(result, left, scratch); + } else { + Label ok; + // Check for -0. + __ sub(scratch2, left, scratch, SetCC); + __ b(ne, &ok); + __ cmp(left, Operand(0)); + DeoptimizeIf(mi, instr->environment()); + __ bind(&ok); + // Load the result and we are done. + __ mov(result, scratch2); + } + } __ bind(&done); } @@ -1135,15 +1220,18 @@ void LCodeGen::DoDivI(LDivI* instr) { DeferredDivI(LCodeGen* codegen, LDivI* instr) : LDeferredCode(codegen), instr_(instr) { } virtual void Generate() { - codegen()->DoDeferredBinaryOpStub(instr_, Token::DIV); + codegen()->DoDeferredBinaryOpStub(instr_->pointer_map(), + instr_->left(), + instr_->right(), + Token::DIV); } virtual LInstruction* instr() { return instr_; } private: LDivI* instr_; }; - const Register left = ToRegister(instr->InputAt(0)); - const Register right = ToRegister(instr->InputAt(1)); + const Register left = ToRegister(instr->left()); + const Register right = ToRegister(instr->right()); const Register scratch = scratch0(); const Register result = ToRegister(instr->result()); @@ -1191,7 +1279,7 @@ void LCodeGen::DoDivI(LDivI* instr) { // Call the stub. The numbers in r0 and r1 have // to be tagged to Smis. If that is not possible, deoptimize. - DeferredDivI* deferred = new DeferredDivI(this, instr); + DeferredDivI* deferred = new(zone()) DeferredDivI(this, instr); __ TrySmiTag(left, &deoptimize, scratch); __ TrySmiTag(right, &deoptimize, scratch); @@ -1212,15 +1300,15 @@ void LCodeGen::DoDivI(LDivI* instr) { void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { const Register result = ToRegister(instr->result()); - const Register left = ToRegister(instr->InputAt(0)); - const Register remainder = ToRegister(instr->TempAt(0)); + const Register left = ToRegister(instr->left()); + const Register remainder = ToRegister(instr->temp()); const Register scratch = scratch0(); // We only optimize this for division by constants, because the standard // integer division routine is usually slower than transitionning to VFP. // This could be optimized on processors with SDIV available. - ASSERT(instr->InputAt(1)->IsConstantOperand()); - int32_t divisor = ToInteger32(LConstantOperand::cast(instr->InputAt(1))); + ASSERT(instr->right()->IsConstantOperand()); + int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); if (divisor < 0) { __ cmp(left, Operand(0)); DeoptimizeIf(eq, instr->environment()); @@ -1238,11 +1326,12 @@ void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { } -template<int T> -void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, +void LCodeGen::DoDeferredBinaryOpStub(LPointerMap* pointer_map, + LOperand* left_argument, + LOperand* right_argument, Token::Value op) { - Register left = ToRegister(instr->InputAt(0)); - Register right = ToRegister(instr->InputAt(1)); + Register left = ToRegister(left_argument); + Register right = ToRegister(right_argument); PushSafepointRegistersScope scope(this, Safepoint::kWithRegistersAndDoubles); // Move left to r1 and right to r0 for the stub call. @@ -1261,7 +1350,7 @@ void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, } BinaryOpStub stub(op, OVERWRITE_LEFT); __ CallStub(&stub); - RecordSafepointWithRegistersAndDoubles(instr->pointer_map(), + RecordSafepointWithRegistersAndDoubles(pointer_map, 0, Safepoint::kNoLazyDeopt); // Overwrite the stored value of r0 with the result of the stub. @@ -1273,8 +1362,8 @@ void LCodeGen::DoMulI(LMulI* instr) { Register scratch = scratch0(); Register result = ToRegister(instr->result()); // Note that result may alias left. - Register left = ToRegister(instr->InputAt(0)); - LOperand* right_op = instr->InputAt(1); + Register left = ToRegister(instr->left()); + LOperand* right_op = instr->right(); bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); bool bailout_on_minus_zero = @@ -1341,7 +1430,7 @@ void LCodeGen::DoMulI(LMulI* instr) { } else { Register right = EmitLoadRegister(right_op, scratch); if (bailout_on_minus_zero) { - __ orr(ToRegister(instr->TempAt(0)), left, right); + __ orr(ToRegister(instr->temp()), left, right); } if (can_overflow) { @@ -1358,7 +1447,7 @@ void LCodeGen::DoMulI(LMulI* instr) { Label done; __ cmp(result, Operand(0)); __ b(ne, &done); - __ cmp(ToRegister(instr->TempAt(0)), Operand(0)); + __ cmp(ToRegister(instr->temp()), Operand(0)); DeoptimizeIf(mi, instr->environment()); __ bind(&done); } @@ -1367,8 +1456,8 @@ void LCodeGen::DoMulI(LMulI* instr) { void LCodeGen::DoBitI(LBitI* instr) { - LOperand* left_op = instr->InputAt(0); - LOperand* right_op = instr->InputAt(1); + LOperand* left_op = instr->left(); + LOperand* right_op = instr->right(); ASSERT(left_op->IsRegister()); Register left = ToRegister(left_op); Register result = ToRegister(instr->result()); @@ -1401,14 +1490,17 @@ void LCodeGen::DoBitI(LBitI* instr) { void LCodeGen::DoShiftI(LShiftI* instr) { // Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so // result may alias either of them. - LOperand* right_op = instr->InputAt(1); - Register left = ToRegister(instr->InputAt(0)); + LOperand* right_op = instr->right(); + Register left = ToRegister(instr->left()); Register result = ToRegister(instr->result()); Register scratch = scratch0(); if (right_op->IsRegister()) { // Mask the right_op operand. __ and_(scratch, ToRegister(right_op), Operand(0x1F)); switch (instr->op()) { + case Token::ROR: + __ mov(result, Operand(left, ROR, scratch)); + break; case Token::SAR: __ mov(result, Operand(left, ASR, scratch)); break; @@ -1432,6 +1524,13 @@ void LCodeGen::DoShiftI(LShiftI* instr) { int value = ToInteger32(LConstantOperand::cast(right_op)); uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); switch (instr->op()) { + case Token::ROR: + if (shift_count != 0) { + __ mov(result, Operand(left, ROR, shift_count)); + } else { + __ Move(result, left); + } + break; case Token::SAR: if (shift_count != 0) { __ mov(result, Operand(left, ASR, shift_count)); @@ -1466,8 +1565,8 @@ void LCodeGen::DoShiftI(LShiftI* instr) { void LCodeGen::DoSubI(LSubI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); LOperand* result = instr->result(); bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); SBit set_cond = can_overflow ? SetCC : LeaveCC; @@ -1496,7 +1595,7 @@ void LCodeGen::DoConstantD(LConstantD* instr) { ASSERT(instr->result()->IsDoubleRegister()); DwVfpRegister result = ToDoubleRegister(instr->result()); double v = instr->value(); - __ Vmov(result, v); + __ Vmov(result, v, scratch0()); } @@ -1513,21 +1612,28 @@ void LCodeGen::DoConstantT(LConstantT* instr) { void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); + Register array = ToRegister(instr->value()); __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset)); } void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { Register result = ToRegister(instr->result()); - Register array = ToRegister(instr->InputAt(0)); + Register array = ToRegister(instr->value()); __ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset)); } +void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) { + Register result = ToRegister(instr->result()); + Register map = ToRegister(instr->value()); + __ EnumLength(result, map); +} + + void LCodeGen::DoElementsKind(LElementsKind* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); // Load map into |result|. __ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset)); @@ -1540,9 +1646,9 @@ void LCodeGen::DoElementsKind(LElementsKind* instr) { void LCodeGen::DoValueOf(LValueOf* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); - Register map = ToRegister(instr->TempAt(0)); + Register map = ToRegister(instr->temp()); Label done; // If the object is a smi return the object. @@ -1561,9 +1667,9 @@ void LCodeGen::DoValueOf(LValueOf* instr) { void LCodeGen::DoDateField(LDateField* instr) { - Register object = ToRegister(instr->InputAt(0)); + Register object = ToRegister(instr->date()); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->TempAt(0)); + Register scratch = ToRegister(instr->temp()); Smi* index = instr->index(); Label runtime, done; ASSERT(object.is(result)); @@ -1571,11 +1677,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)); @@ -1601,14 +1706,14 @@ void LCodeGen::DoDateField(LDateField* instr) { void LCodeGen::DoBitNotI(LBitNotI* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); __ mvn(result, Operand(input)); } void LCodeGen::DoThrow(LThrow* instr) { - Register input_reg = EmitLoadRegister(instr->InputAt(0), ip); + Register input_reg = EmitLoadRegister(instr->value(), ip); __ push(input_reg); CallRuntime(Runtime::kThrow, 1, instr); @@ -1619,8 +1724,8 @@ void LCodeGen::DoThrow(LThrow* instr) { void LCodeGen::DoAddI(LAddI* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); LOperand* result = instr->result(); bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); SBit set_cond = can_overflow ? SetCC : LeaveCC; @@ -1639,9 +1744,71 @@ void LCodeGen::DoAddI(LAddI* instr) { } +void LCodeGen::DoMathMinMax(LMathMinMax* instr) { + LOperand* left = instr->left(); + LOperand* right = instr->right(); + 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)); + DoubleRegister left = ToDoubleRegister(instr->left()); + DoubleRegister right = ToDoubleRegister(instr->right()); DoubleRegister result = ToDoubleRegister(instr->result()); switch (instr->op()) { case Token::ADD: @@ -1680,11 +1847,14 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) { void LCodeGen::DoArithmeticT(LArithmeticT* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(r1)); - ASSERT(ToRegister(instr->InputAt(1)).is(r0)); + ASSERT(ToRegister(instr->left()).is(r1)); + ASSERT(ToRegister(instr->right()).is(r0)); ASSERT(ToRegister(instr->result()).is(r0)); BinaryOpStub stub(instr->op(), NO_OVERWRITE); + // Block literal pool emission to ensure nop indicating no inlined smi code + // is in the correct position. + Assembler::BlockConstPoolScope block_const_pool(masm()); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); __ nop(); // Signals no inlined code. } @@ -1723,11 +1893,11 @@ void LCodeGen::DoBranch(LBranch* instr) { Representation r = instr->hydrogen()->value()->representation(); if (r.IsInteger32()) { - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); __ cmp(reg, Operand(0)); EmitBranch(true_block, false_block, ne); } else if (r.IsDouble()) { - DoubleRegister reg = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister reg = ToDoubleRegister(instr->value()); Register scratch = scratch0(); // Test the double value. Zero and NaN are false. @@ -1736,7 +1906,7 @@ void LCodeGen::DoBranch(LBranch* instr) { EmitBranch(true_block, false_block, eq); } else { ASSERT(r.IsTagged()); - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); HType type = instr->hydrogen()->value()->type(); if (type.IsBoolean()) { __ CompareRoot(reg, Heap::kTrueValueRootIndex); @@ -1875,8 +2045,8 @@ Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); + LOperand* left = instr->left(); + LOperand* right = instr->right(); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); Condition cond = TokenToCondition(instr->op(), false); @@ -1916,8 +2086,8 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { - Register left = ToRegister(instr->InputAt(0)); - Register right = ToRegister(instr->InputAt(1)); + Register left = ToRegister(instr->left()); + Register right = ToRegister(instr->right()); int false_block = chunk_->LookupDestination(instr->false_block_id()); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -1927,7 +2097,7 @@ void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { - Register left = ToRegister(instr->InputAt(0)); + Register left = ToRegister(instr->left()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -1938,7 +2108,7 @@ void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { Register scratch = scratch0(); - Register reg = ToRegister(instr->InputAt(0)); + Register reg = ToRegister(instr->value()); int false_block = chunk_->LookupDestination(instr->false_block_id()); // If the expression is known to be untagged or a smi, then it's definitely @@ -2006,8 +2176,8 @@ Condition LCodeGen::EmitIsObject(Register input, void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp1 = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp1 = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2032,8 +2202,8 @@ Condition LCodeGen::EmitIsString(Register input, void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp1 = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp1 = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2050,15 +2220,15 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); - Register input_reg = EmitLoadRegister(instr->InputAt(0), ip); + Register input_reg = EmitLoadRegister(instr->value(), ip); __ tst(input_reg, Operand(kSmiTagMask)); EmitBranch(true_block, false_block, eq); } void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register input = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2128,7 +2298,7 @@ static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { Register scratch = scratch0(); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -2143,12 +2313,10 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); - if (FLAG_debug_code) { - __ AbortIfNotString(input); - } + __ AssertString(input); __ ldr(result, FieldMemOperand(input, String::kHashFieldOffset)); __ IndexFromHash(result, result); @@ -2157,7 +2325,7 @@ void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { void LCodeGen::DoHasCachedArrayIndexAndBranch( LHasCachedArrayIndexAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register scratch = scratch0(); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -2238,9 +2406,9 @@ void LCodeGen::EmitClassOfTest(Label* is_true, void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register temp = scratch0(); - Register temp2 = ToRegister(instr->TempAt(0)); + Register temp2 = ToRegister(instr->temp()); Handle<String> class_name = instr->hydrogen()->class_name(); int true_block = chunk_->LookupDestination(instr->true_block_id()); @@ -2256,8 +2424,8 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { - Register reg = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register reg = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); int true_block = instr->true_block_id(); int false_block = instr->false_block_id(); @@ -2268,8 +2436,8 @@ void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { void LCodeGen::DoInstanceOf(LInstanceOf* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(r0)); // Object is in r0. - ASSERT(ToRegister(instr->InputAt(1)).is(r1)); // Function is in r1. + ASSERT(ToRegister(instr->left()).is(r0)); // Object is in r0. + ASSERT(ToRegister(instr->right()).is(r1)); // Function is in r1. InstanceofStub stub(InstanceofStub::kArgsInRegisters); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); @@ -2297,11 +2465,11 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { }; DeferredInstanceOfKnownGlobal* deferred; - deferred = new DeferredInstanceOfKnownGlobal(this, instr); + deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr); Label done, false_result; - Register object = ToRegister(instr->InputAt(0)); - Register temp = ToRegister(instr->TempAt(0)); + Register object = ToRegister(instr->value()); + Register temp = ToRegister(instr->temp()); Register result = ToRegister(instr->result()); ASSERT(object.is(r0)); @@ -2316,20 +2484,26 @@ void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { Label cache_miss; Register map = temp; __ ldr(map, FieldMemOperand(object, HeapObject::kMapOffset)); - __ bind(deferred->map_check()); // Label for calculating code patching. - // We use Factory::the_hole_value() on purpose instead of loading from the - // root array to force relocation to be able to later patch with - // the cached map. - Handle<JSGlobalPropertyCell> cell = - factory()->NewJSGlobalPropertyCell(factory()->the_hole_value()); - __ mov(ip, Operand(Handle<Object>(cell))); - __ ldr(ip, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset)); - __ cmp(map, Operand(ip)); - __ b(ne, &cache_miss); - // We use Factory::the_hole_value() on purpose instead of loading from the - // root array to force relocation to be able to later patch - // with true or false. - __ mov(result, Operand(factory()->the_hole_value())); + { + // Block constant pool emission to ensure the positions of instructions are + // as expected by the patcher. See InstanceofStub::Generate(). + Assembler::BlockConstPoolScope block_const_pool(masm()); + __ bind(deferred->map_check()); // Label for calculating code patching. + // We use Factory::the_hole_value() on purpose instead of loading from the + // root array to force relocation to be able to later patch with + // the cached map. + PredictableCodeSizeScope predictable(masm_); + Handle<JSGlobalPropertyCell> cell = + factory()->NewJSGlobalPropertyCell(factory()->the_hole_value()); + __ mov(ip, Operand(Handle<Object>(cell))); + __ ldr(ip, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset)); + __ cmp(map, Operand(ip)); + __ b(ne, &cache_miss); + // We use Factory::the_hole_value() on purpose instead of loading from the + // root array to force relocation to be able to later patch + // with true or false. + __ mov(result, Operand(factory()->the_hole_value())); + } __ b(&done); // The inlined call site cache did not match. Check null and string before @@ -2376,15 +2550,24 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, // Get the temp register reserved by the instruction. This needs to be r4 as // its slot of the pushing of safepoint registers is used to communicate the // offset to the location of the map check. - Register temp = ToRegister(instr->TempAt(0)); + Register temp = ToRegister(instr->temp()); ASSERT(temp.is(r4)); __ LoadHeapObject(InstanceofStub::right(), instr->function()); - static const int kAdditionalDelta = 4; + static const int kAdditionalDelta = 5; + // Make sure that code size is predicable, since we use specific constants + // offsets in the code to find embedded values.. + PredictableCodeSizeScope predictable(masm_); 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, @@ -2467,7 +2650,7 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { // it as no longer deleted. if (instr->hydrogen()->RequiresHoleCheck()) { // We use a temp to check the payload (CompareRoot might clobber ip). - Register payload = ToRegister(instr->TempAt(0)); + Register payload = ToRegister(instr->temp()); __ ldr(payload, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset)); __ CompareRoot(payload, Heap::kTheHoleValueRootIndex); DeoptimizeIf(eq, instr->environment()); @@ -2546,7 +2729,7 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { - Register object = ToRegister(instr->InputAt(0)); + Register object = ToRegister(instr->object()); Register result = ToRegister(instr->result()); if (instr->hydrogen()->is_in_object()) { __ ldr(result, FieldMemOperand(object, instr->hydrogen()->offset())); @@ -2560,12 +2743,12 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, Register object, Handle<Map> type, - Handle<String> name) { + Handle<String> name, + LEnvironment* env) { LookupResult lookup(isolate()); - type->LookupInDescriptors(NULL, *name, &lookup); - ASSERT(lookup.IsFound() && - (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); - if (lookup.type() == FIELD) { + type->LookupDescriptor(NULL, *name, &lookup); + ASSERT(lookup.IsFound() || lookup.IsCacheable()); + if (lookup.IsField()) { int index = lookup.GetLocalFieldIndexFromMap(*type); int offset = index * kPointerSize; if (index < 0) { @@ -2577,9 +2760,23 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); __ ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize)); } - } else { + } else if (lookup.IsConstantFunction()) { Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type)); __ LoadHeapObject(result, function); + } else { + // Negative lookup. + // Check prototypes. + Handle<HeapObject> current(HeapObject::cast((*type)->prototype())); + Heap* heap = type->GetHeap(); + while (*current != heap->null_value()) { + __ LoadHeapObject(result, current); + __ ldr(result, FieldMemOperand(result, HeapObject::kMapOffset)); + __ cmp(result, Operand(Handle<Map>(current->map()))); + DeoptimizeIf(ne, env); + current = + Handle<HeapObject>(HeapObject::cast(current->map()->prototype())); + } + __ LoadRoot(result, Heap::kUndefinedValueRootIndex); } } @@ -2587,7 +2784,7 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { Register object = ToRegister(instr->object()); Register result = ToRegister(instr->result()); - Register scratch = scratch0(); + Register object_map = scratch0(); int map_count = instr->hydrogen()->types()->length(); bool need_generic = instr->hydrogen()->need_generic(); @@ -2598,18 +2795,24 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { } Handle<String> name = instr->hydrogen()->name(); Label done; - __ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); + __ ldr(object_map, FieldMemOperand(object, HeapObject::kMapOffset)); for (int i = 0; i < map_count; ++i) { bool last = (i == map_count - 1); Handle<Map> map = instr->hydrogen()->types()->at(i); - __ cmp(scratch, Operand(map)); + Label check_passed; + __ CompareMap( + object_map, map, &check_passed, ALLOW_ELEMENT_TRANSITION_MAPS); if (last && !need_generic) { DeoptimizeIf(ne, instr->environment()); - EmitLoadFieldOrConstantFunction(result, object, map, name); + __ bind(&check_passed); + EmitLoadFieldOrConstantFunction( + result, object, map, name, instr->environment()); } else { Label next; __ b(ne, &next); - EmitLoadFieldOrConstantFunction(result, object, map, name); + __ bind(&check_passed); + EmitLoadFieldOrConstantFunction( + result, object, map, name, instr->environment()); __ b(&done); __ bind(&next); } @@ -2617,7 +2820,7 @@ void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { if (need_generic) { __ mov(r2, Operand(name)); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } __ bind(&done); } @@ -2630,7 +2833,7 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { // Name is always in r2. __ mov(r2, Operand(instr->name())); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } @@ -2680,7 +2883,7 @@ void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { void LCodeGen::DoLoadElements(LLoadElements* instr) { Register result = ToRegister(instr->result()); - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->object()); Register scratch = scratch0(); __ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset)); @@ -2697,8 +2900,10 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) { __ ldr(scratch, FieldMemOperand(scratch, Map::kBitField2Offset)); __ ubfx(scratch, scratch, Map::kElementsKindShift, Map::kElementsKindBitCount); - __ cmp(scratch, Operand(FAST_ELEMENTS)); - __ b(eq, &done); + __ cmp(scratch, Operand(GetInitialFastElementsKind())); + __ b(lt, &fail); + __ cmp(scratch, Operand(TERMINAL_FAST_ELEMENTS_KIND)); + __ b(le, &done); __ cmp(scratch, Operand(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND)); __ b(lt, &fail); __ cmp(scratch, Operand(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND)); @@ -2713,7 +2918,7 @@ void LCodeGen::DoLoadElements(LLoadElements* instr) { void LCodeGen::DoLoadExternalArrayPointer( LLoadExternalArrayPointer* instr) { Register to_reg = ToRegister(instr->result()); - Register from_reg = ToRegister(instr->InputAt(0)); + Register from_reg = ToRegister(instr->object()); __ ldr(to_reg, FieldMemOperand(from_reg, ExternalArray::kExternalPointerOffset)); } @@ -2724,82 +2929,16 @@ void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { Register length = ToRegister(instr->length()); Register index = ToRegister(instr->index()); Register result = ToRegister(instr->result()); - - // Bailout index is not a valid argument index. Use unsigned check to get - // negative check for free. - __ sub(length, length, index, SetCC); - DeoptimizeIf(ls, instr->environment()); - // There are two words between the frame pointer and the last argument. // Subtracting from length accounts for one of them add one more. + __ sub(length, length, index); __ add(length, length, Operand(1)); __ ldr(result, MemOperand(arguments, length, LSL, kPointerSizeLog2)); } -void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { - Register elements = ToRegister(instr->elements()); - Register key = EmitLoadRegister(instr->key(), scratch0()); - Register result = ToRegister(instr->result()); - Register scratch = scratch0(); - - // Load the result. - __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); - uint32_t offset = FixedArray::kHeaderSize + - (instr->additional_index() << kPointerSizeLog2); - __ ldr(result, FieldMemOperand(scratch, offset)); - - // Check for the hole value. - if (instr->hydrogen()->RequiresHoleCheck()) { - __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); - __ cmp(result, scratch); - DeoptimizeIf(eq, instr->environment()); - } -} - - -void LCodeGen::DoLoadKeyedFastDoubleElement( - LLoadKeyedFastDoubleElement* instr) { - Register elements = ToRegister(instr->elements()); - bool key_is_constant = instr->key()->IsConstantOperand(); - Register key = no_reg; - DwVfpRegister result = ToDoubleRegister(instr->result()); - Register scratch = scratch0(); - - int shift_size = - ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); - int constant_key = 0; - if (key_is_constant) { - constant_key = ToInteger32(LConstantOperand::cast(instr->key())); - if (constant_key & 0xF0000000) { - Abort("array index constant value too big."); - } - } else { - key = ToRegister(instr->key()); - } - - Operand operand = key_is_constant - ? Operand(((constant_key + instr->additional_index()) << shift_size) + - 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))); - } - - __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); - __ cmp(scratch, Operand(kHoleNanUpper32)); - DeoptimizeIf(eq, instr->environment()); - - __ vldr(result, elements, 0); -} - - -void LCodeGen::DoLoadKeyedSpecializedArrayElement( - LLoadKeyedSpecializedArrayElement* instr) { - Register external_pointer = ToRegister(instr->external_pointer()); +void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { + Register external_pointer = ToRegister(instr->elements()); Register key = no_reg; ElementsKind elements_kind = instr->elements_kind(); bool key_is_constant = instr->key()->IsConstantOperand(); @@ -2812,15 +2951,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) { @@ -2831,15 +2972,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); @@ -2859,17 +2995,19 @@ 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: + case FAST_HOLEY_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: UNREACHABLE(); @@ -2879,12 +3017,142 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement( } +void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { + Register elements = ToRegister(instr->elements()); + bool key_is_constant = instr->key()->IsConstantOperand(); + Register key = no_reg; + DwVfpRegister result = ToDoubleRegister(instr->result()); + Register scratch = scratch0(); + + 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())); + if (constant_key & 0xF0000000) { + Abort("array index constant value too big."); + } + } else { + key = ToRegister(instr->key()); + } + + Operand operand = key_is_constant + ? 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() << element_size_shift))); + } + + __ vldr(result, elements, 0); + if (instr->hydrogen()->RequiresHoleCheck()) { + __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); + __ cmp(scratch, Operand(kHoleNanUpper32)); + DeoptimizeIf(eq, instr->environment()); + } +} + + +void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { + Register elements = ToRegister(instr->elements()); + Register result = ToRegister(instr->result()); + Register scratch = scratch0(); + Register store_base = scratch; + int offset = 0; + + 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 HLoadKeyed 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()) { + if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { + __ tst(result, Operand(kSmiTagMask)); + DeoptimizeIf(ne, instr->environment()); + } else { + __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); + __ cmp(result, scratch); + DeoptimizeIf(eq, instr->environment()); + } + } +} + + +void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { + if (instr->is_external()) { + DoLoadKeyedExternalArray(instr); + } else if (instr->hydrogen()->representation().IsDouble()) { + DoLoadKeyedFixedDoubleArray(instr); + } else { + DoLoadKeyedFixedArray(instr); + } +} + + +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::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(r1)); ASSERT(ToRegister(instr->key()).is(r0)); Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } @@ -2910,7 +3178,7 @@ void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { - Register elem = ToRegister(instr->InputAt(0)); + Register elem = ToRegister(instr->elements()); Register result = ToRegister(instr->result()); Label done; @@ -3029,7 +3297,7 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoPushArgument(LPushArgument* instr) { - LOperand* argument = instr->InputAt(0); + LOperand* argument = instr->value(); if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { Abort("DoPushArgument not implemented for double type."); } else { @@ -3046,7 +3314,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)); } @@ -3076,12 +3344,14 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { void LCodeGen::DoGlobalObject(LGlobalObject* instr) { Register result = ToRegister(instr->result()); - __ ldr(result, ContextOperand(cp, instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX)); + __ ldr(result, ContextOperand(cp, instr->qml_global() + ? Context::QML_GLOBAL_OBJECT_INDEX + : Context::GLOBAL_OBJECT_INDEX)); } void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { - Register global = ToRegister(instr->global()); + Register global = ToRegister(instr->global_object()); Register result = ToRegister(instr->result()); __ ldr(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset)); } @@ -3103,14 +3373,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. @@ -3147,7 +3411,7 @@ void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); Register scratch = scratch0(); @@ -3213,7 +3477,7 @@ void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); __ cmp(input, Operand(0)); __ Move(result, input, pl); @@ -3243,7 +3507,7 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { Representation r = instr->hydrogen()->value()->representation(); if (r.IsDouble()) { - DwVfpRegister input = ToDoubleRegister(instr->InputAt(0)); + DwVfpRegister input = ToDoubleRegister(instr->value()); DwVfpRegister result = ToDoubleRegister(instr->result()); __ vabs(result, input); } else if (r.IsInteger32()) { @@ -3251,8 +3515,8 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { } else { // Representation is tagged. DeferredMathAbsTaggedHeapNumber* deferred = - new DeferredMathAbsTaggedHeapNumber(this, instr); - Register input = ToRegister(instr->InputAt(0)); + new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr); + Register input = ToRegister(instr->value()); // Smi check. __ JumpIfNotSmi(input, deferred->entry()); // If smi, handle it directly. @@ -3263,29 +3527,24 @@ void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); Register result = ToRegister(instr->result()); - SwVfpRegister single_scratch = double_scratch0().low(); - Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->TempAt(0)); + Register scratch = scratch0(); __ EmitVFPTruncate(kRoundToMinusInf, - single_scratch, + result, input, - scratch1, - scratch2); + scratch, + double_scratch0()); DeoptimizeIf(ne, instr->environment()); - // Move the result back to general purpose register r0. - __ vmov(result, single_scratch); - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { // Test for -0. Label done; __ cmp(result, Operand(0)); __ b(ne, &done); - __ vmov(scratch1, input.high()); - __ tst(scratch1, Operand(HeapNumber::kSignMask)); + __ vmov(scratch, input.high()); + __ tst(scratch, Operand(HeapNumber::kSignMask)); DeoptimizeIf(ne, instr->environment()); __ bind(&done); } @@ -3293,8 +3552,9 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); Register result = ToRegister(instr->result()); + DwVfpRegister double_scratch1 = ToDoubleRegister(instr->temp()); Register scratch = scratch0(); Label done, check_sign_on_zero; @@ -3319,12 +3579,12 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { __ cmp(scratch, Operand(HeapNumber::kExponentBias + 32)); DeoptimizeIf(ge, instr->environment()); + __ Vmov(double_scratch0(), 0.5, scratch); + __ vadd(double_scratch0(), input, double_scratch0()); + // Save the original sign for later comparison. __ and_(scratch, result, Operand(HeapNumber::kSignMask)); - __ Vmov(double_scratch0(), 0.5); - __ vadd(double_scratch0(), input, double_scratch0()); - // Check sign of the result: if the sign changed, the input // value was in ]0.5, 0[ and the result should be -0. __ vmov(result, double_scratch0().high()); @@ -3337,12 +3597,11 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { } __ EmitVFPTruncate(kRoundToMinusInf, - double_scratch0().low(), - double_scratch0(), result, - scratch); + double_scratch0(), + scratch, + double_scratch1); DeoptimizeIf(ne, instr->environment()); - __ vmov(result, double_scratch0().low()); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { // Test for -0. @@ -3358,22 +3617,22 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); DoubleRegister result = ToDoubleRegister(instr->result()); __ vsqrt(result, input); } void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { - DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input = ToDoubleRegister(instr->value()); DoubleRegister result = ToDoubleRegister(instr->result()); - DoubleRegister temp = ToDoubleRegister(instr->TempAt(0)); + DoubleRegister temp = ToDoubleRegister(instr->temp()); // Note that according to ECMA-262 15.8.2.13: // Math.pow(-Infinity, 0.5) == Infinity // Math.sqrt(-Infinity) == NaN Label done; - __ vmov(temp, -V8_INFINITY); + __ vmov(temp, -V8_INFINITY, scratch0()); __ VFPCompareAndSetFlags(input, temp); __ vneg(result, temp, eq); __ b(&done, eq); @@ -3389,11 +3648,11 @@ void LCodeGen::DoPower(LPower* instr) { Representation exponent_type = instr->hydrogen()->right()->representation(); // Having marked this as a call, we can use any registers. // Just make sure that the input/output registers are the expected ones. - ASSERT(!instr->InputAt(1)->IsDoubleRegister() || - ToDoubleRegister(instr->InputAt(1)).is(d2)); - ASSERT(!instr->InputAt(1)->IsRegister() || - ToRegister(instr->InputAt(1)).is(r2)); - ASSERT(ToDoubleRegister(instr->InputAt(0)).is(d1)); + ASSERT(!instr->right()->IsDoubleRegister() || + ToDoubleRegister(instr->right()).is(d2)); + ASSERT(!instr->right()->IsRegister() || + ToRegister(instr->right()).is(r2)); + ASSERT(ToDoubleRegister(instr->left()).is(d1)); ASSERT(ToDoubleRegister(instr->result()).is(d3)); if (exponent_type.IsTagged()) { @@ -3428,21 +3687,21 @@ void LCodeGen::DoRandom(LRandom* instr) { LRandom* instr_; }; - DeferredDoRandom* deferred = new DeferredDoRandom(this, instr); + DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr); // Having marked this instruction as a call we can use any // registers. ASSERT(ToDoubleRegister(instr->result()).is(d7)); - ASSERT(ToRegister(instr->InputAt(0)).is(r0)); + ASSERT(ToRegister(instr->global_object()).is(r0)); 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)); @@ -3590,7 +3849,7 @@ void LCodeGen::DoCallKeyed(LCallKeyed* instr) { int arity = instr->arity(); Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arity); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); } @@ -3603,7 +3862,7 @@ void LCodeGen::DoCallNamed(LCallNamed* instr) { Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity, mode); __ mov(r2, Operand(instr->name())); - CallCode(ic, mode, instr); + CallCode(ic, mode, instr, NEVER_INLINE_TARGET_ADDRESS); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); } @@ -3628,7 +3887,7 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity, mode); __ mov(r2, Operand(instr->name())); - CallCode(ic, mode, instr); + CallCode(ic, mode, instr, NEVER_INLINE_TARGET_ADDRESS); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); } @@ -3644,7 +3903,7 @@ void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { void LCodeGen::DoCallNew(LCallNew* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(r1)); + ASSERT(ToRegister(instr->constructor()).is(r1)); ASSERT(ToRegister(instr->result()).is(r0)); CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); @@ -3669,6 +3928,18 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { if (!instr->transition().is_null()) { __ mov(scratch, Operand(instr->transition())); __ str(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); + if (instr->hydrogen()->NeedsWriteBarrierForMap()) { + Register temp = ToRegister(instr->temp()); + // Update the write barrier for the map field. + __ RecordWriteField(object, + HeapObject::kMapOffset, + scratch, + temp, + kLRHasBeenSaved, + kSaveFPRegs, + OMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + } } // Do the store. @@ -3716,104 +3987,50 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) ? isolate()->builtins()->StoreIC_Initialize_Strict() : isolate()->builtins()->StoreIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } -void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { - __ cmp(ToRegister(instr->index()), ToRegister(instr->length())); - DeoptimizeIf(hs, instr->environment()); -} - - -void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { - Register value = ToRegister(instr->value()); - Register elements = ToRegister(instr->object()); - Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; - Register scratch = scratch0(); - - // 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)); - } else { - __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); - if (instr->additional_index() != 0) { - __ add(scratch, - scratch, - Operand(instr->additional_index() << kPointerSizeLog2)); +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)); } - __ str(value, FieldMemOperand(scratch, FixedArray::kHeaderSize)); - } - - 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)); - __ RecordWrite(elements, - key, - value, - kLRHasBeenSaved, - kSaveFPRegs, - EMIT_REMEMBERED_SET, - check_needed); + DeoptimizeIf(ne, environment); } } -void LCodeGen::DoStoreKeyedFastDoubleElement( - LStoreKeyedFastDoubleElement* instr) { - DwVfpRegister value = ToDoubleRegister(instr->value()); - Register elements = ToRegister(instr->elements()); - Register key = no_reg; - Register scratch = scratch0(); - bool key_is_constant = instr->key()->IsConstantOperand(); - int constant_key = 0; - - // Calculate the effective address of the slot in the array to store the - // double value. - if (key_is_constant) { - constant_key = ToInteger32(LConstantOperand::cast(instr->key())); - if (constant_key & 0xF0000000) { - Abort("array index constant value too big."); +void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { + 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 { - key = ToRegister(instr->key()); + __ cmp(ToRegister(instr->index()), ToRegister(instr->length())); } - int shift_size = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); - Operand operand = key_is_constant - ? Operand((constant_key << shift_size) + - FixedDoubleArray::kHeaderSize - kHeapObjectTag) - : Operand(key, LSL, shift_size); - __ add(scratch, elements, operand); - if (!key_is_constant) { - __ add(scratch, scratch, - Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); - } - - if (instr->NeedsCanonicalization()) { - // Check for NaN. All NaNs must be canonicalized. - __ VFPCompareAndSetFlags(value, value); - // Only load canonical NaN if the comparison above set the overflow. - __ Vmov(value, - FixedDoubleArray::canonical_not_the_hole_nan_as_double(), - vs); - } - - __ vstr(value, scratch, instr->additional_index() << shift_size); + DeoptimizeIf(hs, instr->environment()); } -void LCodeGen::DoStoreKeyedSpecializedArrayElement( - LStoreKeyedSpecializedArrayElement* instr) { - - Register external_pointer = ToRegister(instr->external_pointer()); +void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { + Register external_pointer = ToRegister(instr->elements()); Register key = no_reg; ElementsKind elements_kind = instr->elements_kind(); bool key_is_constant = instr->key()->IsConstantOperand(); @@ -3826,15 +4043,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); @@ -3844,16 +4064,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: @@ -3872,7 +4086,10 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement( case EXTERNAL_DOUBLE_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: + case FAST_HOLEY_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: case DICTIONARY_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS: UNREACHABLE(); @@ -3882,6 +4099,110 @@ void LCodeGen::DoStoreKeyedSpecializedArrayElement( } +void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { + DwVfpRegister value = ToDoubleRegister(instr->value()); + Register elements = ToRegister(instr->elements()); + Register key = no_reg; + Register scratch = scratch0(); + bool key_is_constant = instr->key()->IsConstantOperand(); + int constant_key = 0; + + // Calculate the effective address of the slot in the array to store the + // double value. + if (key_is_constant) { + constant_key = ToInteger32(LConstantOperand::cast(instr->key())); + if (constant_key & 0xF0000000) { + Abort("array index constant value too big."); + } + } else { + key = ToRegister(instr->key()); + } + 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 << element_size_shift) + + FixedDoubleArray::kHeaderSize - kHeapObjectTag) + : Operand(key, LSL, shift_size); + __ add(scratch, elements, operand); + if (!key_is_constant) { + __ add(scratch, scratch, + Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); + } + + if (instr->NeedsCanonicalization()) { + // Check for NaN. All NaNs must be canonicalized. + __ VFPCompareAndSetFlags(value, value); + // Only load canonical NaN if the comparison above set the overflow. + __ Vmov(value, + FixedDoubleArray::canonical_not_the_hole_nan_as_double(), + no_reg, vs); + } + + __ vstr(value, scratch, instr->additional_index() << element_size_shift); +} + + +void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { + Register value = ToRegister(instr->value()); + Register elements = ToRegister(instr->elements()); + 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()); + offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + + instr->additional_index()); + store_base = elements; + } else { + // Even though the HLoadKeyed 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()); + } + __ 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, store_base, Operand(offset - kHeapObjectTag)); + __ RecordWrite(elements, + key, + value, + kLRHasBeenSaved, + kSaveFPRegs, + EMIT_REMEMBERED_SET, + check_needed); + } +} + + +void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { + // By cases: external, fast double + if (instr->is_external()) { + DoStoreKeyedExternalArray(instr); + } else if (instr->hydrogen()->value()->representation().IsDouble()) { + DoStoreKeyedFixedDoubleArray(instr); + } else { + DoStoreKeyedFixedArray(instr); + } +} + + void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { ASSERT(ToRegister(instr->object()).is(r2)); ASSERT(ToRegister(instr->key()).is(r1)); @@ -3890,13 +4211,13 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() : isolate()->builtins()->KeyedStoreIC_Initialize(); - CallCode(ic, RelocInfo::CODE_TARGET, instr); + CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { Register object_reg = ToRegister(instr->object()); - Register new_map_reg = ToRegister(instr->new_map_reg()); + Register new_map_reg = ToRegister(instr->new_map_temp()); Register scratch = scratch0(); Handle<Map> from_map = instr->original_map(); @@ -3909,21 +4230,23 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { __ cmp(scratch, Operand(from_map)); __ b(ne, ¬_applicable); __ mov(new_map_reg, Operand(to_map)); - if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) { + + if (IsSimpleMapChangeTransition(from_kind, to_kind)) { __ str(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset)); // Write barrier. __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, scratch, kLRHasBeenSaved, kDontSaveFPRegs); - } else if (from_kind == FAST_SMI_ONLY_ELEMENTS && - to_kind == FAST_DOUBLE_ELEMENTS) { - Register fixed_object_reg = ToRegister(instr->temp_reg()); + } else if (IsFastSmiElementsKind(from_kind) && + IsFastDoubleElementsKind(to_kind)) { + Register fixed_object_reg = ToRegister(instr->temp()); ASSERT(fixed_object_reg.is(r2)); ASSERT(new_map_reg.is(r3)); __ mov(fixed_object_reg, object_reg); CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), RelocInfo::CODE_TARGET, instr); - } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) { - Register fixed_object_reg = ToRegister(instr->temp_reg()); + } else if (IsFastDoubleElementsKind(from_kind) && + IsFastObjectElementsKind(to_kind)) { + Register fixed_object_reg = ToRegister(instr->temp()); ASSERT(fixed_object_reg.is(r2)); ASSERT(new_map_reg.is(r3)); __ mov(fixed_object_reg, object_reg); @@ -3956,7 +4279,7 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { }; DeferredStringCharCodeAt* deferred = - new DeferredStringCharCodeAt(this, instr); + new(zone()) DeferredStringCharCodeAt(this, instr); StringCharLoadGenerator::Generate(masm(), ToRegister(instr->string()), @@ -3991,9 +4314,7 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { __ push(index); } CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr); - if (FLAG_debug_code) { - __ AbortIfNotSmi(r0); - } + __ AssertSmi(r0); __ SmiUntag(r0); __ StoreToSafepointRegisterSlot(r0, result); } @@ -4011,7 +4332,7 @@ void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { }; DeferredStringCharFromCode* deferred = - new DeferredStringCharFromCode(this, instr); + new(zone()) DeferredStringCharFromCode(this, instr); ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); Register char_code = ToRegister(instr->char_code()); @@ -4048,14 +4369,14 @@ void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { void LCodeGen::DoStringLength(LStringLength* instr) { - Register string = ToRegister(instr->InputAt(0)); + Register string = ToRegister(instr->string()); Register result = ToRegister(instr->result()); __ ldr(result, FieldMemOperand(string, String::kLengthOffset)); } void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister() || input->IsStackSlot()); LOperand* output = instr->result(); ASSERT(output->IsDoubleRegister()); @@ -4071,30 +4392,73 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { } +void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { + LOperand* input = instr->value(); + 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_->value(), + SIGNED_INT32); + } virtual LInstruction* instr() { return instr_; } private: LNumberTagI* instr_; }; - Register src = ToRegister(instr->InputAt(0)); + Register src = ToRegister(instr->value()); Register dst = ToRegister(instr->result()); - DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr); + DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr); __ SmiTag(dst, src, SetCC); __ b(vs, deferred->entry()); __ bind(deferred->exit()); } -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_->value(), + UNSIGNED_INT32); + } + virtual LInstruction* instr() { return instr_; } + private: + LNumberTagU* instr_; + }; + + LOperand* input = instr->value(); + 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(); @@ -4102,19 +4466,25 @@ 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); + __ AllocateHeapNumber(r5, r3, r4, r6, &slow, DONT_TAG_RESULT); __ Move(dst, r5); __ b(&done); } @@ -4129,12 +4499,13 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { __ StoreToSafepointRegisterSlot(ip, dst); CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); __ Move(dst, r0); + __ sub(dst, dst, Operand(kHeapObjectTag)); // Done. Put the value in dbl_scratch into the value of the allocated heap // number. __ bind(&done); - __ sub(ip, dst, Operand(kHeapObjectTag)); - __ vstr(dbl_scratch, ip, HeapNumber::kValueOffset); + __ vstr(dbl_scratch, dst, HeapNumber::kValueOffset); + __ add(dst, dst, Operand(kHeapObjectTag)); __ StoreToSafepointRegisterSlot(dst, dst); } @@ -4150,22 +4521,25 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { LNumberTagD* instr_; }; - DoubleRegister input_reg = ToDoubleRegister(instr->InputAt(0)); + DoubleRegister input_reg = ToDoubleRegister(instr->value()); Register scratch = scratch0(); Register reg = ToRegister(instr->result()); - Register temp1 = ToRegister(instr->TempAt(0)); - Register temp2 = ToRegister(instr->TempAt(1)); + Register temp1 = ToRegister(instr->temp()); + Register temp2 = ToRegister(instr->temp2()); - DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); + DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); if (FLAG_inline_new) { __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry()); + // We want the untagged address first for performance + __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry(), + DONT_TAG_RESULT); } else { __ jmp(deferred->entry()); } __ bind(deferred->exit()); - __ sub(ip, reg, Operand(kHeapObjectTag)); - __ vstr(input_reg, ip, HeapNumber::kValueOffset); + __ vstr(input_reg, reg, HeapNumber::kValueOffset); + // Now that we have finished with the object's real address tag it + __ add(reg, reg, Operand(kHeapObjectTag)); } @@ -4178,18 +4552,19 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); + __ sub(r0, r0, Operand(kHeapObjectTag)); __ StoreToSafepointRegisterSlot(r0, reg); } void LCodeGen::DoSmiTag(LSmiTag* instr) { ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); - __ SmiTag(ToRegister(instr->result()), ToRegister(instr->InputAt(0))); + __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value())); } void LCodeGen::DoSmiUntag(LSmiUntag* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register result = ToRegister(instr->result()); if (instr->needs_check()) { STATIC_ASSERT(kHeapObjectTag == 1); @@ -4261,11 +4636,11 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { - Register input_reg = ToRegister(instr->InputAt(0)); + Register input_reg = ToRegister(instr->value()); Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->TempAt(0)); + Register scratch2 = ToRegister(instr->temp()); DwVfpRegister double_scratch = double_scratch0(); - SwVfpRegister single_scratch = double_scratch.low(); + DwVfpRegister double_scratch2 = ToDoubleRegister(instr->temp3()); ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2)); ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1)); @@ -4284,8 +4659,8 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { __ cmp(scratch1, Operand(ip)); if (instr->truncating()) { - Register scratch3 = ToRegister(instr->TempAt(1)); - DwVfpRegister double_scratch2 = ToDoubleRegister(instr->TempAt(2)); + Register scratch3 = ToRegister(instr->temp2()); + SwVfpRegister single_scratch = double_scratch.low(); ASSERT(!scratch3.is(input_reg) && !scratch3.is(scratch1) && !scratch3.is(scratch2)); @@ -4320,14 +4695,12 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { __ sub(ip, input_reg, Operand(kHeapObjectTag)); __ vldr(double_scratch, ip, HeapNumber::kValueOffset); __ EmitVFPTruncate(kRoundToZero, - single_scratch, + input_reg, double_scratch, scratch1, - scratch2, + double_scratch2, kCheckForInexactConversion); DeoptimizeIf(ne, instr->environment()); - // Load the result. - __ vmov(input_reg, single_scratch); if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { __ cmp(input_reg, Operand(0)); @@ -4352,13 +4725,13 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { LTaggedToI* instr_; }; - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); ASSERT(input->Equals(instr->result())); Register input_reg = ToRegister(input); - DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr); + DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr); // Optimistically untag the input. // If the input is a HeapObject, SmiUntag will set the carry flag. @@ -4371,7 +4744,7 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) { void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); LOperand* result = instr->result(); ASSERT(result->IsDoubleRegister()); @@ -4389,14 +4762,14 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { void LCodeGen::DoDoubleToI(LDoubleToI* instr) { Register result_reg = ToRegister(instr->result()); Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->TempAt(0)); - DwVfpRegister double_input = ToDoubleRegister(instr->InputAt(0)); - SwVfpRegister single_scratch = double_scratch0().low(); + Register scratch2 = ToRegister(instr->temp()); + DwVfpRegister double_input = ToDoubleRegister(instr->value()); Label done; if (instr->truncating()) { - Register scratch3 = ToRegister(instr->TempAt(1)); + Register scratch3 = ToRegister(instr->temp2()); + SwVfpRegister single_scratch = double_scratch0().low(); __ EmitECMATruncate(result_reg, double_input, single_scratch, @@ -4404,39 +4777,38 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { scratch2, scratch3); } else { - VFPRoundingMode rounding_mode = kRoundToMinusInf; - __ EmitVFPTruncate(rounding_mode, - single_scratch, + DwVfpRegister double_scratch = double_scratch0(); + __ EmitVFPTruncate(kRoundToMinusInf, + result_reg, double_input, scratch1, - scratch2, + double_scratch, kCheckForInexactConversion); + // Deoptimize if we had a vfp invalid exception, // including inexact operation. DeoptimizeIf(ne, instr->environment()); - // Retrieve the result. - __ vmov(result_reg, single_scratch); } __ bind(&done); } void LCodeGen::DoCheckSmi(LCheckSmi* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); __ tst(ToRegister(input), Operand(kSmiTagMask)); DeoptimizeIf(ne, instr->environment()); } void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); __ tst(ToRegister(input), Operand(kSmiTagMask)); DeoptimizeIf(eq, instr->environment()); } void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); Register scratch = scratch0(); __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); @@ -4509,7 +4881,7 @@ void LCodeGen::DoCheckMapCommon(Register reg, void LCodeGen::DoCheckMaps(LCheckMaps* instr) { Register scratch = scratch0(); - LOperand* input = instr->InputAt(0); + LOperand* input = instr->value(); ASSERT(input->IsRegister()); Register reg = ToRegister(input); @@ -4529,7 +4901,7 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) { void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { DoubleRegister value_reg = ToDoubleRegister(instr->unclamped()); Register result_reg = ToRegister(instr->result()); - DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0)); + DoubleRegister temp_reg = ToDoubleRegister(instr->temp()); __ ClampDoubleToUint8(result_reg, value_reg, temp_reg); } @@ -4545,7 +4917,7 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { Register scratch = scratch0(); Register input_reg = ToRegister(instr->unclamped()); Register result_reg = ToRegister(instr->result()); - DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0)); + DoubleRegister temp_reg = ToDoubleRegister(instr->temp()); Label is_smi, done, heap_number; // Both smi and heap number cases are handled. @@ -4579,8 +4951,9 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { - Register temp1 = ToRegister(instr->TempAt(0)); - Register temp2 = ToRegister(instr->TempAt(1)); + ASSERT(instr->temp()->Equals(instr->result())); + Register temp1 = ToRegister(instr->temp()); + Register temp2 = ToRegister(instr->temp2()); Handle<JSObject> holder = instr->holder(); Handle<JSObject> current_prototype = instr->prototype(); @@ -4603,7 +4976,6 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { DoCheckMapCommon(temp1, temp2, Handle<Map>(current_prototype->map()), ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment()); - DeoptimizeIf(ne, instr->environment()); } @@ -4618,11 +4990,12 @@ void LCodeGen::DoAllocateObject(LAllocateObject* instr) { LAllocateObject* instr_; }; - DeferredAllocateObject* deferred = new DeferredAllocateObject(this, instr); + DeferredAllocateObject* deferred = + new(zone()) DeferredAllocateObject(this, instr); Register result = ToRegister(instr->result()); - Register scratch = ToRegister(instr->TempAt(0)); - Register scratch2 = ToRegister(instr->TempAt(1)); + Register scratch = ToRegister(instr->temp()); + Register scratch2 = ToRegister(instr->temp2()); Handle<JSFunction> constructor = instr->hydrogen()->constructor(); Handle<Map> initial_map(constructor->initial_map()); int instance_size = initial_map->instance_size(); @@ -4690,14 +5063,15 @@ 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(); // Deopt if the array literal boilerplate ElementsKind is of a type different // than the expected one. The check isn't necessary if the boilerplate has - // already been converted to FAST_ELEMENTS. - if (boilerplate_elements_kind != FAST_ELEMENTS) { + // already been converted to TERMINAL_FAST_ELEMENTS_KIND. + if (CanTransitionToMoreGeneralFastElementsKind( + boilerplate_elements_kind, true)) { __ LoadHeapObject(r1, instr->hydrogen()->boilerplate_object()); // Load map into r2. __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); @@ -4709,12 +5083,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. @@ -4808,8 +5182,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)); @@ -4848,10 +5222,11 @@ void LCodeGen::DoFastLiteral(LFastLiteral* instr) { ElementsKind boilerplate_elements_kind = instr->hydrogen()->boilerplate()->GetElementsKind(); - // Deopt if the literal boilerplate ElementsKind is of a type different than - // the expected one. The check isn't necessary if the boilerplate has already - // been converted to FAST_ELEMENTS. - if (boilerplate_elements_kind != FAST_ELEMENTS) { + // Deopt if the array literal boilerplate ElementsKind is of a type different + // than the expected one. The check isn't necessary if the boilerplate has + // already been converted to TERMINAL_FAST_ELEMENTS_KIND. + if (CanTransitionToMoreGeneralFastElementsKind( + boilerplate_elements_kind, true)) { __ LoadHeapObject(r1, instr->hydrogen()->boilerplate()); // Load map into r2. __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); @@ -4912,7 +5287,7 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { void LCodeGen::DoToFastProperties(LToFastProperties* instr) { - ASSERT(ToRegister(instr->InputAt(0)).is(r0)); + ASSERT(ToRegister(instr->value()).is(r0)); __ push(r0); CallRuntime(Runtime::kToFastProperties, 1, instr); } @@ -4921,15 +5296,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); @@ -4995,14 +5368,14 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); __ push(input); CallRuntime(Runtime::kTypeof, 1, instr); } void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { - Register input = ToRegister(instr->InputAt(0)); + Register input = ToRegister(instr->value()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); Label* true_label = chunk_->GetAssemblyLabel(true_block); @@ -5092,7 +5465,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label, void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { - Register temp1 = ToRegister(instr->TempAt(0)); + Register temp1 = ToRegister(instr->temp()); int true_block = chunk_->LookupDestination(instr->true_block_id()); int false_block = chunk_->LookupDestination(instr->false_block_id()); @@ -5126,6 +5499,8 @@ void LCodeGen::EnsureSpaceForLazyDeopt() { int current_pc = masm()->pc_offset(); int patch_size = Deoptimizer::patch_size(); if (current_pc < last_lazy_deopt_pc_ + patch_size) { + // Block literal pool emission for duration of padding. + Assembler::BlockConstPoolScope block_const_pool(masm()); int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc; ASSERT_EQ(0, padding_size % Assembler::kInstrSize); while (padding_size > 0) { @@ -5211,6 +5586,7 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { __ cmp(sp, Operand(ip)); __ b(hs, &done); StackCheckStub stub; + PredictableCodeSizeScope predictable(masm_); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); EnsureSpaceForLazyDeopt(); __ bind(&done); @@ -5220,7 +5596,7 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { ASSERT(instr->hydrogen()->is_backwards_branch()); // Perform stack overflow check if this goto needs it before jumping. DeferredStackCheck* deferred_stack_check = - new DeferredStackCheck(this, instr); + new(zone()) DeferredStackCheck(this, instr); __ LoadRoot(ip, Heap::kStackLimitRootIndex); __ cmp(sp, Operand(ip)); __ b(lo, deferred_stack_check->entry()); @@ -5291,13 +5667,23 @@ void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { Register map = ToRegister(instr->map()); Register result = ToRegister(instr->result()); + 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); __ 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); } |