| Index: src/arm/lithium-codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/lithium-codegen-arm.cc (revision 8618)
|
| +++ src/arm/lithium-codegen-arm.cc (working copy)
|
| @@ -146,11 +146,11 @@
|
| // fp: Caller's frame pointer.
|
| // lr: Caller's pc.
|
|
|
| - // Strict mode functions need to replace the receiver with undefined
|
| - // when called as functions (without an explicit receiver
|
| - // object). r5 is zero for method calls and non-zero for function
|
| - // calls.
|
| - if (info_->is_strict_mode()) {
|
| + // Strict mode functions and builtins need to replace the receiver
|
| + // with undefined when called as functions (without an explicit
|
| + // receiver object). r5 is zero for method calls and non-zero for
|
| + // function calls.
|
| + if (info_->is_strict_mode() || info_->is_native()) {
|
| Label ok;
|
| __ cmp(r5, Operand(0));
|
| __ b(eq, &ok);
|
| @@ -189,7 +189,7 @@
|
| FastNewContextStub stub(heap_slots);
|
| __ CallStub(&stub);
|
| } else {
|
| - __ CallRuntime(Runtime::kNewContext, 1);
|
| + __ CallRuntime(Runtime::kNewFunctionContext, 1);
|
| }
|
| RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
|
| // Context is returned in both r0 and cp. It replaces the context
|
| @@ -255,11 +255,20 @@
|
|
|
| bool LCodeGen::GenerateDeferredCode() {
|
| ASSERT(is_generating());
|
| - for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
|
| - LDeferredCode* code = deferred_[i];
|
| - __ bind(code->entry());
|
| - code->Generate();
|
| - __ jmp(code->exit());
|
| + if (deferred_.length() > 0) {
|
| + for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
|
| + LDeferredCode* code = deferred_[i];
|
| + __ bind(code->entry());
|
| + code->Generate();
|
| + __ jmp(code->exit());
|
| + }
|
| +
|
| + // Pad code to ensure that the last piece of deferred code have
|
| + // room for lazy bailout.
|
| + while ((masm()->pc_offset() - LastSafepointEnd())
|
| + < Deoptimizer::patch_size()) {
|
| + __ nop();
|
| + }
|
| }
|
|
|
| // Force constant pool emission at the end of the deferred code to make
|
| @@ -768,7 +777,7 @@
|
|
|
|
|
| void LCodeGen::RecordPosition(int position) {
|
| - if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return;
|
| + if (position == RelocInfo::kNoPosition) return;
|
| masm()->positions_recorder()->RecordPosition(position);
|
| }
|
|
|
| @@ -871,6 +880,7 @@
|
| void LCodeGen::DoModI(LModI* instr) {
|
| if (instr->hydrogen()->HasPowerOf2Divisor()) {
|
| Register dividend = ToRegister(instr->InputAt(0));
|
| + Register result = ToRegister(instr->result());
|
|
|
| int32_t divisor =
|
| HConstant::cast(instr->hydrogen()->right())->Integer32Value();
|
| @@ -880,15 +890,15 @@
|
| Label positive_dividend, done;
|
| __ cmp(dividend, Operand(0));
|
| __ b(pl, &positive_dividend);
|
| - __ rsb(dividend, dividend, Operand(0));
|
| - __ and_(dividend, dividend, Operand(divisor - 1));
|
| - __ rsb(dividend, dividend, Operand(0), SetCC);
|
| + __ rsb(result, dividend, Operand(0));
|
| + __ and_(result, result, Operand(divisor - 1), SetCC);
|
| if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - __ b(ne, &done);
|
| - DeoptimizeIf(al, instr->environment());
|
| + DeoptimizeIf(eq, instr->environment());
|
| }
|
| + __ rsb(result, result, Operand(0));
|
| + __ b(&done);
|
| __ bind(&positive_dividend);
|
| - __ and_(dividend, dividend, Operand(divisor - 1));
|
| + __ and_(result, dividend, Operand(divisor - 1));
|
| __ bind(&done);
|
| return;
|
| }
|
| @@ -904,8 +914,6 @@
|
| DwVfpRegister divisor = ToDoubleRegister(instr->TempAt(2));
|
| DwVfpRegister quotient = double_scratch0();
|
|
|
| - ASSERT(result.is(left));
|
| -
|
| ASSERT(!dividend.is(divisor));
|
| ASSERT(!dividend.is(quotient));
|
| ASSERT(!divisor.is(quotient));
|
| @@ -921,6 +929,8 @@
|
| DeoptimizeIf(eq, instr->environment());
|
| }
|
|
|
| + __ Move(result, left);
|
| +
|
| // (0 % x) must yield 0 (if x is finite, which is the case here).
|
| __ cmp(left, Operand(0));
|
| __ b(eq, &done);
|
| @@ -1117,68 +1127,125 @@
|
|
|
| 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));
|
| - Register right = EmitLoadRegister(instr->InputAt(1), scratch);
|
| + LOperand* right_op = instr->InputAt(1);
|
|
|
| - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) &&
|
| - !instr->InputAt(1)->IsConstantOperand()) {
|
| - __ orr(ToRegister(instr->TempAt(0)), left, right);
|
| - }
|
| + bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
| + bool bailout_on_minus_zero =
|
| + instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
|
|
|
| - if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
|
| - // scratch:left = left * right.
|
| - __ smull(left, scratch, left, right);
|
| - __ mov(ip, Operand(left, ASR, 31));
|
| - __ cmp(ip, Operand(scratch));
|
| - DeoptimizeIf(ne, instr->environment());
|
| + if (right_op->IsConstantOperand() && !can_overflow) {
|
| + // Use optimized code for specific constants.
|
| + int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
|
| +
|
| + if (bailout_on_minus_zero && (constant < 0)) {
|
| + // The case of a null constant will be handled separately.
|
| + // If constant is negative and left is null, the result should be -0.
|
| + __ cmp(left, Operand(0));
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
| +
|
| + switch (constant) {
|
| + case -1:
|
| + __ rsb(result, left, Operand(0));
|
| + break;
|
| + case 0:
|
| + if (bailout_on_minus_zero) {
|
| + // If left is strictly negative and the constant is null, the
|
| + // result is -0. Deoptimize if required, otherwise return 0.
|
| + __ cmp(left, Operand(0));
|
| + DeoptimizeIf(mi, instr->environment());
|
| + }
|
| + __ mov(result, Operand(0));
|
| + break;
|
| + case 1:
|
| + __ Move(result, left);
|
| + break;
|
| + default:
|
| + // Multiplying by powers of two and powers of two plus or minus
|
| + // one can be done faster with shifted operands.
|
| + // For other constants we emit standard code.
|
| + int32_t mask = constant >> 31;
|
| + uint32_t constant_abs = (constant + mask) ^ mask;
|
| +
|
| + if (IsPowerOf2(constant_abs) ||
|
| + IsPowerOf2(constant_abs - 1) ||
|
| + IsPowerOf2(constant_abs + 1)) {
|
| + if (IsPowerOf2(constant_abs)) {
|
| + int32_t shift = WhichPowerOf2(constant_abs);
|
| + __ mov(result, Operand(left, LSL, shift));
|
| + } else if (IsPowerOf2(constant_abs - 1)) {
|
| + int32_t shift = WhichPowerOf2(constant_abs - 1);
|
| + __ add(result, left, Operand(left, LSL, shift));
|
| + } else if (IsPowerOf2(constant_abs + 1)) {
|
| + int32_t shift = WhichPowerOf2(constant_abs + 1);
|
| + __ rsb(result, left, Operand(left, LSL, shift));
|
| + }
|
| +
|
| + // Correct the sign of the result is the constant is negative.
|
| + if (constant < 0) __ rsb(result, result, Operand(0));
|
| +
|
| + } else {
|
| + // Generate standard code.
|
| + __ mov(ip, Operand(constant));
|
| + __ mul(result, left, ip);
|
| + }
|
| + }
|
| +
|
| } else {
|
| - __ mul(left, left, right);
|
| - }
|
| + Register right = EmitLoadRegister(right_op, scratch);
|
| + if (bailout_on_minus_zero) {
|
| + __ orr(ToRegister(instr->TempAt(0)), left, right);
|
| + }
|
|
|
| - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - // Bail out if the result is supposed to be negative zero.
|
| - Label done;
|
| - __ cmp(left, Operand(0));
|
| - __ b(ne, &done);
|
| - if (instr->InputAt(1)->IsConstantOperand()) {
|
| - if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) <= 0) {
|
| - DeoptimizeIf(al, instr->environment());
|
| - }
|
| + if (can_overflow) {
|
| + // scratch:result = left * right.
|
| + __ smull(result, scratch, left, right);
|
| + __ cmp(scratch, Operand(result, ASR, 31));
|
| + DeoptimizeIf(ne, instr->environment());
|
| } else {
|
| - // Test the non-zero operand for negative sign.
|
| + __ mul(result, left, right);
|
| + }
|
| +
|
| + if (bailout_on_minus_zero) {
|
| + // Bail out if the result is supposed to be negative zero.
|
| + Label done;
|
| + __ cmp(result, Operand(0));
|
| + __ b(ne, &done);
|
| __ cmp(ToRegister(instr->TempAt(0)), Operand(0));
|
| DeoptimizeIf(mi, instr->environment());
|
| + __ bind(&done);
|
| }
|
| - __ bind(&done);
|
| }
|
| }
|
|
|
|
|
| void LCodeGen::DoBitI(LBitI* instr) {
|
| - LOperand* left = instr->InputAt(0);
|
| - LOperand* right = instr->InputAt(1);
|
| - ASSERT(left->Equals(instr->result()));
|
| - ASSERT(left->IsRegister());
|
| - Register result = ToRegister(left);
|
| - Operand right_operand(no_reg);
|
| + LOperand* left_op = instr->InputAt(0);
|
| + LOperand* right_op = instr->InputAt(1);
|
| + ASSERT(left_op->IsRegister());
|
| + Register left = ToRegister(left_op);
|
| + Register result = ToRegister(instr->result());
|
| + Operand right(no_reg);
|
|
|
| - if (right->IsStackSlot() || right->IsArgument()) {
|
| - Register right_reg = EmitLoadRegister(right, ip);
|
| - right_operand = Operand(right_reg);
|
| + if (right_op->IsStackSlot() || right_op->IsArgument()) {
|
| + right = Operand(EmitLoadRegister(right_op, ip));
|
| } else {
|
| - ASSERT(right->IsRegister() || right->IsConstantOperand());
|
| - right_operand = ToOperand(right);
|
| + ASSERT(right_op->IsRegister() || right_op->IsConstantOperand());
|
| + right = ToOperand(right_op);
|
| }
|
|
|
| switch (instr->op()) {
|
| case Token::BIT_AND:
|
| - __ and_(result, ToRegister(left), right_operand);
|
| + __ and_(result, left, right);
|
| break;
|
| case Token::BIT_OR:
|
| - __ orr(result, ToRegister(left), right_operand);
|
| + __ orr(result, left, right);
|
| break;
|
| case Token::BIT_XOR:
|
| - __ eor(result, ToRegister(left), right_operand);
|
| + __ eor(result, left, right);
|
| break;
|
| default:
|
| UNREACHABLE();
|
| @@ -1188,54 +1255,62 @@
|
|
|
|
|
| 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));
|
| + Register result = ToRegister(instr->result());
|
| Register scratch = scratch0();
|
| - LOperand* left = instr->InputAt(0);
|
| - LOperand* right = instr->InputAt(1);
|
| - ASSERT(left->Equals(instr->result()));
|
| - ASSERT(left->IsRegister());
|
| - Register result = ToRegister(left);
|
| - if (right->IsRegister()) {
|
| - // Mask the right operand.
|
| - __ and_(scratch, ToRegister(right), Operand(0x1F));
|
| + if (right_op->IsRegister()) {
|
| + // Mask the right_op operand.
|
| + __ and_(scratch, ToRegister(right_op), Operand(0x1F));
|
| switch (instr->op()) {
|
| case Token::SAR:
|
| - __ mov(result, Operand(result, ASR, scratch));
|
| + __ mov(result, Operand(left, ASR, scratch));
|
| break;
|
| case Token::SHR:
|
| if (instr->can_deopt()) {
|
| - __ mov(result, Operand(result, LSR, scratch), SetCC);
|
| + __ mov(result, Operand(left, LSR, scratch), SetCC);
|
| DeoptimizeIf(mi, instr->environment());
|
| } else {
|
| - __ mov(result, Operand(result, LSR, scratch));
|
| + __ mov(result, Operand(left, LSR, scratch));
|
| }
|
| break;
|
| case Token::SHL:
|
| - __ mov(result, Operand(result, LSL, scratch));
|
| + __ mov(result, Operand(left, LSL, scratch));
|
| break;
|
| default:
|
| UNREACHABLE();
|
| break;
|
| }
|
| } else {
|
| - int value = ToInteger32(LConstantOperand::cast(right));
|
| + // Mask the right_op operand.
|
| + int value = ToInteger32(LConstantOperand::cast(right_op));
|
| uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
|
| switch (instr->op()) {
|
| case Token::SAR:
|
| if (shift_count != 0) {
|
| - __ mov(result, Operand(result, ASR, shift_count));
|
| + __ mov(result, Operand(left, ASR, shift_count));
|
| + } else {
|
| + __ Move(result, left);
|
| }
|
| break;
|
| case Token::SHR:
|
| - if (shift_count == 0 && instr->can_deopt()) {
|
| - __ tst(result, Operand(0x80000000));
|
| - DeoptimizeIf(ne, instr->environment());
|
| + if (shift_count != 0) {
|
| + __ mov(result, Operand(left, LSR, shift_count));
|
| } else {
|
| - __ mov(result, Operand(result, LSR, shift_count));
|
| + if (instr->can_deopt()) {
|
| + __ tst(left, Operand(0x80000000));
|
| + DeoptimizeIf(ne, instr->environment());
|
| + }
|
| + __ Move(result, left);
|
| }
|
| break;
|
| case Token::SHL:
|
| if (shift_count != 0) {
|
| - __ mov(result, Operand(result, LSL, shift_count));
|
| + __ mov(result, Operand(left, LSL, shift_count));
|
| + } else {
|
| + __ Move(result, left);
|
| }
|
| break;
|
| default:
|
| @@ -1249,16 +1324,16 @@
|
| void LCodeGen::DoSubI(LSubI* instr) {
|
| LOperand* left = instr->InputAt(0);
|
| LOperand* right = instr->InputAt(1);
|
| - ASSERT(left->Equals(instr->result()));
|
| + LOperand* result = instr->result();
|
| bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
| SBit set_cond = can_overflow ? SetCC : LeaveCC;
|
|
|
| if (right->IsStackSlot() || right->IsArgument()) {
|
| Register right_reg = EmitLoadRegister(right, ip);
|
| - __ sub(ToRegister(left), ToRegister(left), Operand(right_reg), set_cond);
|
| + __ sub(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond);
|
| } else {
|
| ASSERT(right->IsRegister() || right->IsConstantOperand());
|
| - __ sub(ToRegister(left), ToRegister(left), ToOperand(right), set_cond);
|
| + __ sub(ToRegister(result), ToRegister(left), ToOperand(right), set_cond);
|
| }
|
|
|
| if (can_overflow) {
|
| @@ -1277,7 +1352,7 @@
|
| ASSERT(instr->result()->IsDoubleRegister());
|
| DwVfpRegister result = ToDoubleRegister(instr->result());
|
| double v = instr->value();
|
| - __ vmov(result, v);
|
| + __ Vmov(result, v);
|
| }
|
|
|
|
|
| @@ -1308,19 +1383,34 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoElementsKind(LElementsKind* instr) {
|
| + Register result = ToRegister(instr->result());
|
| + Register input = ToRegister(instr->InputAt(0));
|
| +
|
| + // Load map into |result|.
|
| + __ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset));
|
| + // Load the map's "bit field 2" into |result|. We only need the first byte,
|
| + // but the following bit field extraction takes care of that anyway.
|
| + __ ldr(result, FieldMemOperand(result, Map::kBitField2Offset));
|
| + // Retrieve elements_kind from bit field 2.
|
| + __ ubfx(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoValueOf(LValueOf* instr) {
|
| Register input = ToRegister(instr->InputAt(0));
|
| Register result = ToRegister(instr->result());
|
| Register map = ToRegister(instr->TempAt(0));
|
| - ASSERT(input.is(result));
|
| Label done;
|
|
|
| // If the object is a smi return the object.
|
| __ tst(input, Operand(kSmiTagMask));
|
| + __ Move(result, input, eq);
|
| __ b(eq, &done);
|
|
|
| // If the object is not a value type, return the object.
|
| __ CompareObjectType(input, map, map, JS_VALUE_TYPE);
|
| + __ Move(result, input, ne);
|
| __ b(ne, &done);
|
| __ ldr(result, FieldMemOperand(input, JSValue::kValueOffset));
|
|
|
| @@ -1329,9 +1419,9 @@
|
|
|
|
|
| void LCodeGen::DoBitNotI(LBitNotI* instr) {
|
| - LOperand* input = instr->InputAt(0);
|
| - ASSERT(input->Equals(instr->result()));
|
| - __ mvn(ToRegister(input), Operand(ToRegister(input)));
|
| + Register input = ToRegister(instr->InputAt(0));
|
| + Register result = ToRegister(instr->result());
|
| + __ mvn(result, Operand(input));
|
| }
|
|
|
|
|
| @@ -1349,16 +1439,16 @@
|
| void LCodeGen::DoAddI(LAddI* instr) {
|
| LOperand* left = instr->InputAt(0);
|
| LOperand* right = instr->InputAt(1);
|
| - ASSERT(left->Equals(instr->result()));
|
| + LOperand* result = instr->result();
|
| bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
|
| SBit set_cond = can_overflow ? SetCC : LeaveCC;
|
|
|
| if (right->IsStackSlot() || right->IsArgument()) {
|
| Register right_reg = EmitLoadRegister(right, ip);
|
| - __ add(ToRegister(left), ToRegister(left), Operand(right_reg), set_cond);
|
| + __ add(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond);
|
| } else {
|
| ASSERT(right->IsRegister() || right->IsConstantOperand());
|
| - __ add(ToRegister(left), ToRegister(left), ToOperand(right), set_cond);
|
| + __ add(ToRegister(result), ToRegister(left), ToOperand(right), set_cond);
|
| }
|
|
|
| if (can_overflow) {
|
| @@ -1370,18 +1460,19 @@
|
| void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
|
| DoubleRegister left = ToDoubleRegister(instr->InputAt(0));
|
| DoubleRegister right = ToDoubleRegister(instr->InputAt(1));
|
| + DoubleRegister result = ToDoubleRegister(instr->result());
|
| switch (instr->op()) {
|
| case Token::ADD:
|
| - __ vadd(left, left, right);
|
| + __ vadd(result, left, right);
|
| break;
|
| case Token::SUB:
|
| - __ vsub(left, left, right);
|
| + __ vsub(result, left, right);
|
| break;
|
| case Token::MUL:
|
| - __ vmul(left, left, right);
|
| + __ vmul(result, left, right);
|
| break;
|
| case Token::DIV:
|
| - __ vdiv(left, left, right);
|
| + __ vdiv(result, left, right);
|
| break;
|
| case Token::MOD: {
|
| // Save r0-r3 on the stack.
|
| @@ -1393,7 +1484,7 @@
|
| ExternalReference::double_fp_operation(Token::MOD, isolate()),
|
| 0, 2);
|
| // Move the result in the double result register.
|
| - __ GetCFunctionDoubleResult(ToDoubleRegister(instr->result()));
|
| + __ GetCFunctionDoubleResult(result);
|
|
|
| // Restore r0-r3.
|
| __ ldm(ia_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
|
| @@ -1447,7 +1538,7 @@
|
| int true_block = chunk_->LookupDestination(instr->true_block_id());
|
| int false_block = chunk_->LookupDestination(instr->false_block_id());
|
|
|
| - Representation r = instr->hydrogen()->representation();
|
| + Representation r = instr->hydrogen()->value()->representation();
|
| if (r.IsInteger32()) {
|
| Register reg = ToRegister(instr->InputAt(0));
|
| __ cmp(reg, Operand(0));
|
| @@ -1463,7 +1554,7 @@
|
| } else {
|
| ASSERT(r.IsTagged());
|
| Register reg = ToRegister(instr->InputAt(0));
|
| - if (instr->hydrogen()->type().IsBoolean()) {
|
| + if (instr->hydrogen()->value()->type().IsBoolean()) {
|
| __ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
| __ cmp(reg, ip);
|
| EmitBranch(true_block, false_block, eq);
|
| @@ -1482,12 +1573,11 @@
|
| __ b(eq, false_label);
|
| __ cmp(reg, Operand(0));
|
| __ b(eq, false_label);
|
| - __ tst(reg, Operand(kSmiTagMask));
|
| - __ b(eq, true_label);
|
| + __ JumpIfSmi(reg, true_label);
|
|
|
| // Test double values. Zero and NaN are false.
|
| Label call_stub;
|
| - DoubleRegister dbl_scratch = d0;
|
| + DoubleRegister dbl_scratch = double_scratch0();
|
| Register scratch = scratch0();
|
| __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
|
| __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
|
| @@ -1515,45 +1605,17 @@
|
| }
|
|
|
|
|
| -void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
|
| +void LCodeGen::EmitGoto(int block) {
|
| block = chunk_->LookupDestination(block);
|
| int next_block = GetNextEmittedBlock(current_block_);
|
| if (block != next_block) {
|
| - // Perform stack overflow check if this goto needs it before jumping.
|
| - if (deferred_stack_check != NULL) {
|
| - __ LoadRoot(ip, Heap::kStackLimitRootIndex);
|
| - __ cmp(sp, Operand(ip));
|
| - __ b(hs, chunk_->GetAssemblyLabel(block));
|
| - __ jmp(deferred_stack_check->entry());
|
| - deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
|
| - } else {
|
| - __ jmp(chunk_->GetAssemblyLabel(block));
|
| - }
|
| + __ jmp(chunk_->GetAssemblyLabel(block));
|
| }
|
| }
|
|
|
|
|
| -void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
|
| - PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
|
| - CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoGoto(LGoto* instr) {
|
| - class DeferredStackCheck: public LDeferredCode {
|
| - public:
|
| - DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
|
| - : LDeferredCode(codegen), instr_(instr) { }
|
| - virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
|
| - private:
|
| - LGoto* instr_;
|
| - };
|
| -
|
| - DeferredStackCheck* deferred = NULL;
|
| - if (instr->include_stack_check()) {
|
| - deferred = new DeferredStackCheck(this, instr);
|
| - }
|
| - EmitGoto(instr->block_id(), deferred);
|
| + EmitGoto(instr->block_id());
|
| }
|
|
|
|
|
| @@ -1590,34 +1652,6 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoCmpID(LCmpID* instr) {
|
| - LOperand* left = instr->InputAt(0);
|
| - LOperand* right = instr->InputAt(1);
|
| - LOperand* result = instr->result();
|
| - Register scratch = scratch0();
|
| -
|
| - Label unordered, done;
|
| - if (instr->is_double()) {
|
| - // Compare left and right as doubles and load the
|
| - // resulting flags into the normal status register.
|
| - __ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right));
|
| - // If a NaN is involved, i.e. the result is unordered (V set),
|
| - // jump to unordered to return false.
|
| - __ b(vs, &unordered);
|
| - } else {
|
| - EmitCmpI(left, right);
|
| - }
|
| -
|
| - Condition cc = TokenToCondition(instr->op(), instr->is_double());
|
| - __ LoadRoot(ToRegister(result), Heap::kTrueValueRootIndex);
|
| - __ b(cc, &done);
|
| -
|
| - __ bind(&unordered);
|
| - __ LoadRoot(ToRegister(result), Heap::kFalseValueRootIndex);
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
|
| LOperand* left = instr->InputAt(0);
|
| LOperand* right = instr->InputAt(1);
|
| @@ -1640,20 +1674,9 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
|
| +void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
|
| Register left = ToRegister(instr->InputAt(0));
|
| Register right = ToRegister(instr->InputAt(1));
|
| - Register result = ToRegister(instr->result());
|
| -
|
| - __ cmp(left, Operand(right));
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
|
| -}
|
| -
|
| -
|
| -void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
|
| - Register left = ToRegister(instr->InputAt(0));
|
| - Register right = ToRegister(instr->InputAt(1));
|
| int false_block = chunk_->LookupDestination(instr->false_block_id());
|
| int true_block = chunk_->LookupDestination(instr->true_block_id());
|
|
|
| @@ -1662,62 +1685,16 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoCmpSymbolEq(LCmpSymbolEq* instr) {
|
| +void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
|
| Register left = ToRegister(instr->InputAt(0));
|
| - Register right = ToRegister(instr->InputAt(1));
|
| - Register result = ToRegister(instr->result());
|
| -
|
| - __ cmp(left, Operand(right));
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
|
| -}
|
| -
|
| -
|
| -void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) {
|
| - Register left = ToRegister(instr->InputAt(0));
|
| - Register right = ToRegister(instr->InputAt(1));
|
| - int false_block = chunk_->LookupDestination(instr->false_block_id());
|
| int true_block = chunk_->LookupDestination(instr->true_block_id());
|
| + int false_block = chunk_->LookupDestination(instr->false_block_id());
|
|
|
| - __ cmp(left, Operand(right));
|
| + __ cmp(left, Operand(instr->hydrogen()->right()));
|
| EmitBranch(true_block, false_block, eq);
|
| }
|
|
|
|
|
| -void LCodeGen::DoIsNull(LIsNull* instr) {
|
| - Register reg = ToRegister(instr->InputAt(0));
|
| - Register result = ToRegister(instr->result());
|
| -
|
| - __ LoadRoot(ip, Heap::kNullValueRootIndex);
|
| - __ cmp(reg, ip);
|
| - if (instr->is_strict()) {
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
|
| - } else {
|
| - Label true_value, false_value, done;
|
| - __ b(eq, &true_value);
|
| - __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| - __ cmp(ip, reg);
|
| - __ b(eq, &true_value);
|
| - __ tst(reg, Operand(kSmiTagMask));
|
| - __ b(eq, &false_value);
|
| - // Check for undetectable objects by looking in the bit field in
|
| - // the map. The object has already been smi checked.
|
| - Register scratch = result;
|
| - __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
|
| - __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
|
| - __ tst(scratch, Operand(1 << Map::kIsUndetectable));
|
| - __ b(ne, &true_value);
|
| - __ bind(&false_value);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex);
|
| - __ jmp(&done);
|
| - __ bind(&true_value);
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex);
|
| - __ bind(&done);
|
| - }
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
|
| Register scratch = scratch0();
|
| Register reg = ToRegister(instr->InputAt(0));
|
| @@ -1739,8 +1716,7 @@
|
| __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| __ cmp(reg, ip);
|
| __ b(eq, true_label);
|
| - __ tst(reg, Operand(kSmiTagMask));
|
| - __ b(eq, false_label);
|
| + __ JumpIfSmi(reg, false_label);
|
| // Check for undetectable objects by looking in the bit field in
|
| // the map. The object has already been smi checked.
|
| __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
|
| @@ -1753,13 +1729,13 @@
|
|
|
| Condition LCodeGen::EmitIsObject(Register input,
|
| Register temp1,
|
| - Register temp2,
|
| Label* is_not_object,
|
| Label* is_object) {
|
| + Register temp2 = scratch0();
|
| __ JumpIfSmi(input, is_not_object);
|
|
|
| - __ LoadRoot(temp1, Heap::kNullValueRootIndex);
|
| - __ cmp(input, temp1);
|
| + __ LoadRoot(temp2, Heap::kNullValueRootIndex);
|
| + __ cmp(input, temp2);
|
| __ b(eq, is_object);
|
|
|
| // Load map.
|
| @@ -1771,33 +1747,13 @@
|
|
|
| // Load instance type and check that it is in object type range.
|
| __ ldrb(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
|
| - __ cmp(temp2, Operand(FIRST_JS_OBJECT_TYPE));
|
| + __ cmp(temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
| __ b(lt, is_not_object);
|
| - __ cmp(temp2, Operand(LAST_JS_OBJECT_TYPE));
|
| + __ cmp(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
| return le;
|
| }
|
|
|
|
|
| -void LCodeGen::DoIsObject(LIsObject* instr) {
|
| - Register reg = ToRegister(instr->InputAt(0));
|
| - Register result = ToRegister(instr->result());
|
| - Register temp = scratch0();
|
| - Label is_false, is_true, done;
|
| -
|
| - Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true);
|
| - __ b(true_cond, &is_true);
|
| -
|
| - __ bind(&is_false);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex);
|
| - __ b(&done);
|
| -
|
| - __ bind(&is_true);
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex);
|
| -
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
| Register reg = ToRegister(instr->InputAt(0));
|
| Register temp1 = ToRegister(instr->TempAt(0));
|
| @@ -1809,25 +1765,12 @@
|
| Label* false_label = chunk_->GetAssemblyLabel(false_block);
|
|
|
| Condition true_cond =
|
| - EmitIsObject(reg, temp1, temp2, false_label, true_label);
|
| + EmitIsObject(reg, temp1, false_label, true_label);
|
|
|
| EmitBranch(true_block, false_block, true_cond);
|
| }
|
|
|
|
|
| -void LCodeGen::DoIsSmi(LIsSmi* instr) {
|
| - ASSERT(instr->hydrogen()->value()->representation().IsTagged());
|
| - Register result = ToRegister(instr->result());
|
| - Register input_reg = EmitLoadRegister(instr->InputAt(0), ip);
|
| - __ tst(input_reg, Operand(kSmiTagMask));
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex);
|
| - Label done;
|
| - __ b(eq, &done);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex);
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
|
| int true_block = chunk_->LookupDestination(instr->true_block_id());
|
| int false_block = chunk_->LookupDestination(instr->false_block_id());
|
| @@ -1838,25 +1781,6 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) {
|
| - Register input = ToRegister(instr->InputAt(0));
|
| - Register result = ToRegister(instr->result());
|
| -
|
| - ASSERT(instr->hydrogen()->value()->representation().IsTagged());
|
| - Label false_label, done;
|
| - __ JumpIfSmi(input, &false_label);
|
| - __ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset));
|
| - __ ldrb(result, FieldMemOperand(result, Map::kBitFieldOffset));
|
| - __ tst(result, Operand(1 << Map::kIsUndetectable));
|
| - __ b(eq, &false_label);
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex);
|
| - __ jmp(&done);
|
| - __ bind(&false_label);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex);
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
|
| Register input = ToRegister(instr->InputAt(0));
|
| Register temp = ToRegister(instr->TempAt(0));
|
| @@ -1872,7 +1796,7 @@
|
| }
|
|
|
|
|
| -static InstanceType TestType(HHasInstanceType* instr) {
|
| +static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
|
| InstanceType from = instr->from();
|
| InstanceType to = instr->to();
|
| if (from == FIRST_TYPE) return to;
|
| @@ -1881,7 +1805,7 @@
|
| }
|
|
|
|
|
| -static Condition BranchCondition(HHasInstanceType* instr) {
|
| +static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
|
| InstanceType from = instr->from();
|
| InstanceType to = instr->to();
|
| if (from == to) return eq;
|
| @@ -1892,23 +1816,6 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
|
| - Register input = ToRegister(instr->InputAt(0));
|
| - Register result = ToRegister(instr->result());
|
| -
|
| - ASSERT(instr->hydrogen()->value()->representation().IsTagged());
|
| - Label done;
|
| - __ tst(input, Operand(kSmiTagMask));
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex, eq);
|
| - __ b(eq, &done);
|
| - __ CompareObjectType(input, result, result, TestType(instr->hydrogen()));
|
| - Condition cond = BranchCondition(instr->hydrogen());
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex, cond);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex, NegateCondition(cond));
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
|
| Register scratch = scratch0();
|
| Register input = ToRegister(instr->InputAt(0));
|
| @@ -1918,8 +1825,7 @@
|
|
|
| Label* false_label = chunk_->GetAssemblyLabel(false_block);
|
|
|
| - __ tst(input, Operand(kSmiTagMask));
|
| - __ b(eq, false_label);
|
| + __ JumpIfSmi(input, false_label);
|
|
|
| __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen()));
|
| EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
|
| @@ -1939,20 +1845,6 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
|
| - Register input = ToRegister(instr->InputAt(0));
|
| - Register result = ToRegister(instr->result());
|
| - Register scratch = scratch0();
|
| -
|
| - ASSERT(instr->hydrogen()->value()->representation().IsTagged());
|
| - __ ldr(scratch,
|
| - FieldMemOperand(input, String::kHashFieldOffset));
|
| - __ tst(scratch, Operand(String::kContainsCachedArrayIndexMask));
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoHasCachedArrayIndexAndBranch(
|
| LHasCachedArrayIndexAndBranch* instr) {
|
| Register input = ToRegister(instr->InputAt(0));
|
| @@ -1978,28 +1870,28 @@
|
| Register temp2) {
|
| ASSERT(!input.is(temp));
|
| ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register.
|
| - __ tst(input, Operand(kSmiTagMask));
|
| - __ b(eq, is_false);
|
| - __ CompareObjectType(input, temp, temp2, FIRST_JS_OBJECT_TYPE);
|
| + __ JumpIfSmi(input, is_false);
|
| + __ CompareObjectType(input, temp, temp2, FIRST_SPEC_OBJECT_TYPE);
|
| __ b(lt, is_false);
|
|
|
| // Map is now in temp.
|
| // Functions have class 'Function'.
|
| - __ CompareInstanceType(temp, temp2, JS_FUNCTION_TYPE);
|
| + __ CompareInstanceType(temp, temp2, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
|
| if (class_name->IsEqualTo(CStrVector("Function"))) {
|
| - __ b(eq, is_true);
|
| + __ b(ge, is_true);
|
| } else {
|
| - __ b(eq, is_false);
|
| + __ b(ge, is_false);
|
| }
|
|
|
| // Check if the constructor in the map is a function.
|
| __ ldr(temp, FieldMemOperand(temp, Map::kConstructorOffset));
|
|
|
| - // As long as JS_FUNCTION_TYPE is the last instance type and it is
|
| - // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
|
| - // LAST_JS_OBJECT_TYPE.
|
| - ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
|
| - ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
|
| + // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type and
|
| + // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
|
| + // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
|
| + STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
|
| + STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
|
| + LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
|
|
|
| // Objects with a non-function constructor have class 'Object'.
|
| __ CompareObjectType(temp, temp2, temp2, JS_FUNCTION_TYPE);
|
| @@ -2025,27 +1917,6 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
|
| - Register input = ToRegister(instr->InputAt(0));
|
| - Register result = ToRegister(instr->result());
|
| - ASSERT(input.is(result));
|
| - Handle<String> class_name = instr->hydrogen()->class_name();
|
| -
|
| - Label done, is_true, is_false;
|
| -
|
| - EmitClassOfTest(&is_true, &is_false, class_name, input, scratch0(), input);
|
| - __ b(ne, &is_false);
|
| -
|
| - __ bind(&is_true);
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex);
|
| - __ jmp(&done);
|
| -
|
| - __ bind(&is_false);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex);
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
|
| Register input = ToRegister(instr->InputAt(0));
|
| Register temp = scratch0();
|
| @@ -2089,20 +1960,6 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
|
| - ASSERT(ToRegister(instr->InputAt(0)).is(r0)); // Object is in r0.
|
| - ASSERT(ToRegister(instr->InputAt(1)).is(r1)); // Function is in r1.
|
| -
|
| - int true_block = chunk_->LookupDestination(instr->true_block_id());
|
| - int false_block = chunk_->LookupDestination(instr->false_block_id());
|
| -
|
| - InstanceofStub stub(InstanceofStub::kArgsInRegisters);
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| - __ cmp(r0, Operand(0));
|
| - EmitBranch(true_block, false_block, eq);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
|
| class DeferredInstanceOfKnownGlobal: public LDeferredCode {
|
| public:
|
| @@ -2257,25 +2114,6 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
|
| - Token::Value op = instr->op();
|
| - int true_block = chunk_->LookupDestination(instr->true_block_id());
|
| - int false_block = chunk_->LookupDestination(instr->false_block_id());
|
| -
|
| - Handle<Code> ic = CompareIC::GetUninitialized(op);
|
| - CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| -
|
| - // The compare stub expects compare condition and the input operands
|
| - // reversed for GT and LTE.
|
| - Condition condition = ComputeCompareCondition(op);
|
| - if (op == Token::GT || op == Token::LTE) {
|
| - condition = ReverseCondition(condition);
|
| - }
|
| - __ cmp(r0, Operand(0));
|
| - EmitBranch(true_block, false_block, condition);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoReturn(LReturn* instr) {
|
| if (FLAG_trace) {
|
| // Push the return value on the stack as the parameter.
|
| @@ -2519,7 +2357,7 @@
|
|
|
| __ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset));
|
| if (FLAG_debug_code) {
|
| - Label done;
|
| + Label done, fail;
|
| __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
|
| __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
|
| __ cmp(scratch, ip);
|
| @@ -2527,11 +2365,18 @@
|
| __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
|
| __ cmp(scratch, ip);
|
| __ b(eq, &done);
|
| - __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
|
| - __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
|
| - __ sub(scratch, scratch, Operand(FIRST_EXTERNAL_ARRAY_TYPE));
|
| - __ cmp(scratch, Operand(kExternalArrayTypeCount));
|
| - __ Check(cc, "Check for fast elements failed.");
|
| + // |scratch| still contains |input|'s map.
|
| + __ ldr(scratch, FieldMemOperand(scratch, Map::kBitField2Offset));
|
| + __ ubfx(scratch, scratch, Map::kElementsKindShift,
|
| + Map::kElementsKindBitCount);
|
| + __ cmp(scratch, Operand(JSObject::FAST_ELEMENTS));
|
| + __ b(eq, &done);
|
| + __ cmp(scratch, Operand(JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
|
| + __ b(lt, &fail);
|
| + __ cmp(scratch, Operand(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
|
| + __ b(le, &done);
|
| + __ bind(&fail);
|
| + __ Abort("Check for fast or external elements failed.");
|
| __ bind(&done);
|
| }
|
| }
|
| @@ -2569,7 +2414,6 @@
|
| Register key = EmitLoadRegister(instr->key(), scratch0());
|
| Register result = ToRegister(instr->result());
|
| Register scratch = scratch0();
|
| - ASSERT(result.is(elements));
|
|
|
| // Load the result.
|
| __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
|
| @@ -2588,7 +2432,7 @@
|
| LLoadKeyedSpecializedArrayElement* instr) {
|
| Register external_pointer = ToRegister(instr->external_pointer());
|
| Register key = no_reg;
|
| - ExternalArrayType array_type = instr->array_type();
|
| + JSObject::ElementsKind elements_kind = instr->elements_kind();
|
| bool key_is_constant = instr->key()->IsConstantOperand();
|
| int constant_key = 0;
|
| if (key_is_constant) {
|
| @@ -2599,18 +2443,19 @@
|
| } else {
|
| key = ToRegister(instr->key());
|
| }
|
| - int shift_size = ExternalArrayTypeToShiftSize(array_type);
|
| + int shift_size = ElementsKindToShiftSize(elements_kind);
|
|
|
| - if (array_type == kExternalFloatArray || array_type == kExternalDoubleArray) {
|
| + if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
|
| + elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
|
| CpuFeatures::Scope scope(VFP3);
|
| DwVfpRegister result(ToDoubleRegister(instr->result()));
|
| Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
|
| : Operand(key, LSL, shift_size));
|
| __ add(scratch0(), external_pointer, operand);
|
| - if (array_type == kExternalFloatArray) {
|
| + if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
|
| __ vldr(result.low(), scratch0(), 0);
|
| __ vcvt_f64_f32(result, result.low());
|
| - } else { // i.e. array_type == kExternalDoubleArray
|
| + } else { // i.e. elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS
|
| __ vldr(result, scratch0(), 0);
|
| }
|
| } else {
|
| @@ -2618,24 +2463,24 @@
|
| MemOperand mem_operand(key_is_constant
|
| ? MemOperand(external_pointer, constant_key * (1 << shift_size))
|
| : MemOperand(external_pointer, key, LSL, shift_size));
|
| - switch (array_type) {
|
| - case kExternalByteArray:
|
| + switch (elements_kind) {
|
| + case JSObject::EXTERNAL_BYTE_ELEMENTS:
|
| __ ldrsb(result, mem_operand);
|
| break;
|
| - case kExternalUnsignedByteArray:
|
| - case kExternalPixelArray:
|
| + case JSObject::EXTERNAL_PIXEL_ELEMENTS:
|
| + case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
| __ ldrb(result, mem_operand);
|
| break;
|
| - case kExternalShortArray:
|
| + case JSObject::EXTERNAL_SHORT_ELEMENTS:
|
| __ ldrsh(result, mem_operand);
|
| break;
|
| - case kExternalUnsignedShortArray:
|
| + case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
|
| __ ldrh(result, mem_operand);
|
| break;
|
| - case kExternalIntArray:
|
| + case JSObject::EXTERNAL_INT_ELEMENTS:
|
| __ ldr(result, mem_operand);
|
| break;
|
| - case kExternalUnsignedIntArray:
|
| + case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
|
| __ ldr(result, mem_operand);
|
| __ cmp(result, Operand(0x80000000));
|
| // TODO(danno): we could be more clever here, perhaps having a special
|
| @@ -2643,8 +2488,12 @@
|
| // happens, and generate code that returns a double rather than int.
|
| DeoptimizeIf(cs, instr->environment());
|
| break;
|
| - case kExternalFloatArray:
|
| - case kExternalDoubleArray:
|
| + case JSObject::EXTERNAL_FLOAT_ELEMENTS:
|
| + case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
|
| + case JSObject::FAST_DOUBLE_ELEMENTS:
|
| + case JSObject::FAST_ELEMENTS:
|
| + case JSObject::DICTIONARY_ELEMENTS:
|
| + case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
|
| UNREACHABLE();
|
| break;
|
| }
|
| @@ -2710,9 +2559,26 @@
|
| ASSERT(function.is(r1)); // Required by InvokeFunction.
|
| ASSERT(ToRegister(instr->result()).is(r0));
|
|
|
| - // If the receiver is null or undefined, we have to pass the global object
|
| - // as a receiver.
|
| + // If the receiver is null or undefined, we have to pass the global
|
| + // object as a receiver to normal functions. Values have to be
|
| + // passed unchanged to builtins and strict-mode functions.
|
| Label global_object, receiver_ok;
|
| +
|
| + // Do not transform the receiver to object for strict mode
|
| + // functions.
|
| + __ ldr(scratch,
|
| + FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
|
| + __ ldr(scratch,
|
| + FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
|
| + __ tst(scratch,
|
| + Operand(1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize)));
|
| + __ b(ne, &receiver_ok);
|
| +
|
| + // Do not transform the receiver to object for builtins.
|
| + __ tst(scratch, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
|
| + __ b(ne, &receiver_ok);
|
| +
|
| + // Normal function. Replace undefined or null with global receiver.
|
| __ LoadRoot(scratch, Heap::kNullValueRootIndex);
|
| __ cmp(receiver, scratch);
|
| __ b(eq, &global_object);
|
| @@ -2723,12 +2589,14 @@
|
| // Deoptimize if the receiver is not a JS object.
|
| __ tst(receiver, Operand(kSmiTagMask));
|
| DeoptimizeIf(eq, instr->environment());
|
| - __ CompareObjectType(receiver, scratch, scratch, FIRST_JS_OBJECT_TYPE);
|
| - DeoptimizeIf(lo, instr->environment());
|
| + __ CompareObjectType(receiver, scratch, scratch, FIRST_SPEC_OBJECT_TYPE);
|
| + DeoptimizeIf(lt, instr->environment());
|
| __ jmp(&receiver_ok);
|
|
|
| __ bind(&global_object);
|
| __ ldr(receiver, GlobalObjectOperand());
|
| + __ ldr(receiver,
|
| + FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
|
| __ bind(&receiver_ok);
|
|
|
| // Copy the arguments to this function possibly from the
|
| @@ -2768,7 +2636,8 @@
|
| // The number of arguments is stored in receiver which is r0, as expected
|
| // by InvokeFunction.
|
| v8::internal::ParameterCount actual(receiver);
|
| - __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator);
|
| + __ InvokeFunction(function, actual, CALL_FUNCTION,
|
| + safepoint_generator, CALL_AS_METHOD);
|
| __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
| }
|
|
|
| @@ -2784,6 +2653,12 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoThisFunction(LThisFunction* instr) {
|
| + Register result = ToRegister(instr->result());
|
| + __ ldr(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoContext(LContext* instr) {
|
| Register result = ToRegister(instr->result());
|
| __ mov(result, cp);
|
| @@ -2794,8 +2669,7 @@
|
| Register context = ToRegister(instr->context());
|
| Register result = ToRegister(instr->result());
|
| __ ldr(result,
|
| - MemOperand(context, Context::SlotOffset(Context::CLOSURE_INDEX)));
|
| - __ ldr(result, FieldMemOperand(result, JSFunction::kContextOffset));
|
| + MemOperand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
|
| }
|
|
|
|
|
| @@ -2859,8 +2733,8 @@
|
|
|
|
|
| void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
|
| - ASSERT(instr->InputAt(0)->Equals(instr->result()));
|
| Register input = ToRegister(instr->InputAt(0));
|
| + Register result = ToRegister(instr->result());
|
| Register scratch = scratch0();
|
|
|
| // Deoptimize if not a heap number.
|
| @@ -2874,10 +2748,10 @@
|
| scratch = no_reg;
|
| __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
|
| // Check the sign of the argument. If the argument is positive, just
|
| - // return it. We do not need to patch the stack since |input| and
|
| - // |result| are the same register and |input| would be restored
|
| - // unchanged by popping safepoint registers.
|
| + // return it.
|
| __ tst(exponent, Operand(HeapNumber::kSignMask));
|
| + // Move the input to the result if necessary.
|
| + __ Move(result, input);
|
| __ b(eq, &done);
|
|
|
| // Input is negative. Reverse its sign.
|
| @@ -2917,7 +2791,7 @@
|
| __ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
|
| __ str(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
|
|
|
| - __ StoreToSafepointRegisterSlot(tmp1, input);
|
| + __ StoreToSafepointRegisterSlot(tmp1, result);
|
| }
|
|
|
| __ bind(&done);
|
| @@ -2926,11 +2800,13 @@
|
|
|
| void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
|
| Register input = ToRegister(instr->InputAt(0));
|
| + Register result = ToRegister(instr->result());
|
| __ cmp(input, Operand(0));
|
| + __ Move(result, input, pl);
|
| // We can make rsb conditional because the previous cmp instruction
|
| // will clear the V (overflow) flag and rsb won't set this flag
|
| // if input is positive.
|
| - __ rsb(input, input, Operand(0), SetCC, mi);
|
| + __ rsb(result, input, Operand(0), SetCC, mi);
|
| // Deoptimize on overflow.
|
| DeoptimizeIf(vs, instr->environment());
|
| }
|
| @@ -2950,11 +2826,11 @@
|
| LUnaryMathOperation* instr_;
|
| };
|
|
|
| - ASSERT(instr->InputAt(0)->Equals(instr->result()));
|
| Representation r = instr->hydrogen()->value()->representation();
|
| if (r.IsDouble()) {
|
| DwVfpRegister input = ToDoubleRegister(instr->InputAt(0));
|
| - __ vabs(input, input);
|
| + DwVfpRegister result = ToDoubleRegister(instr->result());
|
| + __ vabs(result, input);
|
| } else if (r.IsInteger32()) {
|
| EmitIntegerMathAbs(instr);
|
| } else {
|
| @@ -3032,7 +2908,7 @@
|
| // Save the original sign for later comparison.
|
| __ and_(scratch2, scratch1, Operand(HeapNumber::kSignMask));
|
|
|
| - __ vmov(double_scratch0(), 0.5);
|
| + __ Vmov(double_scratch0(), 0.5);
|
| __ vadd(input, input, double_scratch0());
|
|
|
| // Check sign of the result: if the sign changed, the input
|
| @@ -3069,24 +2945,17 @@
|
|
|
| void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
|
| DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
|
| - ASSERT(ToDoubleRegister(instr->result()).is(input));
|
| - __ vsqrt(input, input);
|
| + DoubleRegister result = ToDoubleRegister(instr->result());
|
| + __ vsqrt(result, input);
|
| }
|
|
|
|
|
| void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
|
| DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
|
| - Register scratch = scratch0();
|
| - SwVfpRegister single_scratch = double_scratch0().low();
|
| - DoubleRegister double_scratch = double_scratch0();
|
| - ASSERT(ToDoubleRegister(instr->result()).is(input));
|
| -
|
| + DoubleRegister result = ToDoubleRegister(instr->result());
|
| // Add +0 to convert -0 to +0.
|
| - __ mov(scratch, Operand(0));
|
| - __ vmov(single_scratch, scratch);
|
| - __ vcvt_f64_s32(double_scratch, single_scratch);
|
| - __ vadd(input, input, double_scratch);
|
| - __ vsqrt(input, input);
|
| + __ vadd(result, input, kDoubleRegZero);
|
| + __ vsqrt(result, result);
|
| }
|
|
|
|
|
| @@ -3216,7 +3085,7 @@
|
| RegisterEnvironmentForDeoptimization(env);
|
| SafepointGenerator generator(this, pointers, env->deoptimization_index());
|
| ParameterCount count(instr->arity());
|
| - __ InvokeFunction(r1, count, CALL_FUNCTION, generator);
|
| + __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
|
| __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
| }
|
|
|
| @@ -3376,7 +3245,7 @@
|
|
|
| Register external_pointer = ToRegister(instr->external_pointer());
|
| Register key = no_reg;
|
| - ExternalArrayType array_type = instr->array_type();
|
| + JSObject::ElementsKind elements_kind = instr->elements_kind();
|
| bool key_is_constant = instr->key()->IsConstantOperand();
|
| int constant_key = 0;
|
| if (key_is_constant) {
|
| @@ -3387,18 +3256,19 @@
|
| } else {
|
| key = ToRegister(instr->key());
|
| }
|
| - int shift_size = ExternalArrayTypeToShiftSize(array_type);
|
| + int shift_size = ElementsKindToShiftSize(elements_kind);
|
|
|
| - if (array_type == kExternalFloatArray || array_type == kExternalDoubleArray) {
|
| + if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
|
| + elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
|
| CpuFeatures::Scope scope(VFP3);
|
| DwVfpRegister value(ToDoubleRegister(instr->value()));
|
| Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
|
| : Operand(key, LSL, shift_size));
|
| __ add(scratch0(), external_pointer, operand);
|
| - if (array_type == kExternalFloatArray) {
|
| + if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
|
| __ vcvt_f32_f64(double_scratch0().low(), value);
|
| __ vstr(double_scratch0().low(), scratch0(), 0);
|
| - } else { // i.e. array_type == kExternalDoubleArray
|
| + } else { // i.e. elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS
|
| __ vstr(value, scratch0(), 0);
|
| }
|
| } else {
|
| @@ -3406,22 +3276,26 @@
|
| MemOperand mem_operand(key_is_constant
|
| ? MemOperand(external_pointer, constant_key * (1 << shift_size))
|
| : MemOperand(external_pointer, key, LSL, shift_size));
|
| - switch (array_type) {
|
| - case kExternalPixelArray:
|
| - case kExternalByteArray:
|
| - case kExternalUnsignedByteArray:
|
| + switch (elements_kind) {
|
| + case JSObject::EXTERNAL_PIXEL_ELEMENTS:
|
| + case JSObject::EXTERNAL_BYTE_ELEMENTS:
|
| + case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
| __ strb(value, mem_operand);
|
| break;
|
| - case kExternalShortArray:
|
| - case kExternalUnsignedShortArray:
|
| + case JSObject::EXTERNAL_SHORT_ELEMENTS:
|
| + case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
|
| __ strh(value, mem_operand);
|
| break;
|
| - case kExternalIntArray:
|
| - case kExternalUnsignedIntArray:
|
| + case JSObject::EXTERNAL_INT_ELEMENTS:
|
| + case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
|
| __ str(value, mem_operand);
|
| break;
|
| - case kExternalFloatArray:
|
| - case kExternalDoubleArray:
|
| + case JSObject::EXTERNAL_FLOAT_ELEMENTS:
|
| + case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
|
| + case JSObject::FAST_DOUBLE_ELEMENTS:
|
| + case JSObject::FAST_ELEMENTS:
|
| + case JSObject::DICTIONARY_ELEMENTS:
|
| + case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
|
| UNREACHABLE();
|
| break;
|
| }
|
| @@ -3682,8 +3556,8 @@
|
| void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
|
| Label slow;
|
| Register reg = ToRegister(instr->InputAt(0));
|
| - DoubleRegister dbl_scratch = d0;
|
| - SwVfpRegister flt_scratch = s0;
|
| + DoubleRegister dbl_scratch = double_scratch0();
|
| + SwVfpRegister flt_scratch = dbl_scratch.low();
|
|
|
| // Preserve the value of all registers.
|
| PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
|
| @@ -3789,35 +3663,40 @@
|
|
|
| void LCodeGen::EmitNumberUntagD(Register input_reg,
|
| DoubleRegister result_reg,
|
| + bool deoptimize_on_undefined,
|
| LEnvironment* env) {
|
| Register scratch = scratch0();
|
| - SwVfpRegister flt_scratch = s0;
|
| - ASSERT(!result_reg.is(d0));
|
| + SwVfpRegister flt_scratch = double_scratch0().low();
|
| + ASSERT(!result_reg.is(double_scratch0()));
|
|
|
| Label load_smi, heap_number, done;
|
|
|
| // Smi check.
|
| - __ tst(input_reg, Operand(kSmiTagMask));
|
| - __ b(eq, &load_smi);
|
| + __ JumpIfSmi(input_reg, &load_smi);
|
|
|
| // Heap number map check.
|
| __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
|
| __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
|
| __ cmp(scratch, Operand(ip));
|
| - __ b(eq, &heap_number);
|
| + if (deoptimize_on_undefined) {
|
| + DeoptimizeIf(ne, env);
|
| + } else {
|
| + Label heap_number;
|
| + __ b(eq, &heap_number);
|
|
|
| - __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| - __ cmp(input_reg, Operand(ip));
|
| - DeoptimizeIf(ne, env);
|
| + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| + __ cmp(input_reg, Operand(ip));
|
| + DeoptimizeIf(ne, env);
|
|
|
| - // Convert undefined to NaN.
|
| - __ LoadRoot(ip, Heap::kNanValueRootIndex);
|
| - __ sub(ip, ip, Operand(kHeapObjectTag));
|
| - __ vldr(result_reg, ip, HeapNumber::kValueOffset);
|
| - __ jmp(&done);
|
| + // Convert undefined to NaN.
|
| + __ LoadRoot(ip, Heap::kNanValueRootIndex);
|
| + __ sub(ip, ip, Operand(kHeapObjectTag));
|
| + __ vldr(result_reg, ip, HeapNumber::kValueOffset);
|
| + __ jmp(&done);
|
|
|
| + __ bind(&heap_number);
|
| + }
|
| // Heap number to double register conversion.
|
| - __ bind(&heap_number);
|
| __ sub(ip, input_reg, Operand(kHeapObjectTag));
|
| __ vldr(result_reg, ip, HeapNumber::kValueOffset);
|
| __ jmp(&done);
|
| @@ -3951,7 +3830,9 @@
|
| Register input_reg = ToRegister(input);
|
| DoubleRegister result_reg = ToDoubleRegister(result);
|
|
|
| - EmitNumberUntagD(input_reg, result_reg, instr->environment());
|
| + EmitNumberUntagD(input_reg, result_reg,
|
| + instr->hydrogen()->deoptimize_on_undefined(),
|
| + instr->environment());
|
| }
|
|
|
|
|
| @@ -4297,29 +4178,6 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
|
| - Register input = ToRegister(instr->InputAt(0));
|
| - Register result = ToRegister(instr->result());
|
| - Label true_label;
|
| - Label false_label;
|
| - Label done;
|
| -
|
| - Condition final_branch_condition = EmitTypeofIs(&true_label,
|
| - &false_label,
|
| - input,
|
| - instr->type_literal());
|
| - __ b(final_branch_condition, &true_label);
|
| - __ bind(&false_label);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex);
|
| - __ b(&done);
|
| -
|
| - __ bind(&true_label);
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex);
|
| -
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
|
| Register input = ToRegister(instr->InputAt(0));
|
| int true_block = chunk_->LookupDestination(instr->true_block_id());
|
| @@ -4375,17 +4233,19 @@
|
|
|
| } else if (type_name->Equals(heap()->function_symbol())) {
|
| __ JumpIfSmi(input, false_label);
|
| - __ CompareObjectType(input, input, scratch, FIRST_FUNCTION_CLASS_TYPE);
|
| + __ CompareObjectType(input, input, scratch,
|
| + FIRST_CALLABLE_SPEC_OBJECT_TYPE);
|
| final_branch_condition = ge;
|
|
|
| } else if (type_name->Equals(heap()->object_symbol())) {
|
| __ JumpIfSmi(input, false_label);
|
| __ CompareRoot(input, Heap::kNullValueRootIndex);
|
| __ b(eq, true_label);
|
| - __ CompareObjectType(input, input, scratch, FIRST_JS_OBJECT_TYPE);
|
| - __ b(lo, false_label);
|
| - __ CompareInstanceType(input, scratch, FIRST_FUNCTION_CLASS_TYPE);
|
| - __ b(hs, false_label);
|
| + __ CompareObjectType(input, input, scratch,
|
| + FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
| + __ b(lt, false_label);
|
| + __ CompareInstanceType(input, scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
| + __ b(gt, false_label);
|
| // Check for undetectable objects => false.
|
| __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
|
| __ tst(ip, Operand(1 << Map::kIsUndetectable));
|
| @@ -4401,26 +4261,6 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
|
| - Register result = ToRegister(instr->result());
|
| - Label true_label;
|
| - Label false_label;
|
| - Label done;
|
| -
|
| - EmitIsConstructCall(result, scratch0());
|
| - __ b(eq, &true_label);
|
| -
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex);
|
| - __ b(&done);
|
| -
|
| -
|
| - __ bind(&true_label);
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex);
|
| -
|
| - __ bind(&done);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
|
| Register temp1 = ToRegister(instr->TempAt(0));
|
| int true_block = chunk_->LookupDestination(instr->true_block_id());
|
| @@ -4495,15 +4335,50 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
|
| + {
|
| + PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
|
| + __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
|
| + RegisterLazyDeoptimization(
|
| + instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
|
| + }
|
| +
|
| + // The gap code includes the restoring of the safepoint registers.
|
| + int pc = masm()->pc_offset();
|
| + safepoints_.SetPcAfterGap(pc);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoStackCheck(LStackCheck* instr) {
|
| - // Perform stack overflow check.
|
| - Label ok;
|
| - __ LoadRoot(ip, Heap::kStackLimitRootIndex);
|
| - __ cmp(sp, Operand(ip));
|
| - __ b(hs, &ok);
|
| - StackCheckStub stub;
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| - __ bind(&ok);
|
| + class DeferredStackCheck: public LDeferredCode {
|
| + public:
|
| + DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
|
| + : LDeferredCode(codegen), instr_(instr) { }
|
| + virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
|
| + private:
|
| + LStackCheck* instr_;
|
| + };
|
| +
|
| + if (instr->hydrogen()->is_function_entry()) {
|
| + // Perform stack overflow check.
|
| + Label done;
|
| + __ LoadRoot(ip, Heap::kStackLimitRootIndex);
|
| + __ cmp(sp, Operand(ip));
|
| + __ b(hs, &done);
|
| + StackCheckStub stub;
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + __ bind(&done);
|
| + } else {
|
| + 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);
|
| + __ LoadRoot(ip, Heap::kStackLimitRootIndex);
|
| + __ cmp(sp, Operand(ip));
|
| + __ b(lo, deferred_stack_check->entry());
|
| + __ bind(instr->done_label());
|
| + deferred_stack_check->SetExit(instr->done_label());
|
| + }
|
| }
|
|
|
|
|
|
|