| Index: src/arm/full-codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/full-codegen-arm.cc (revision 6796)
|
| +++ src/arm/full-codegen-arm.cc (working copy)
|
| @@ -341,7 +341,17 @@
|
| FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
|
| Token::Value op, Expression* left, Expression* right) {
|
| ASSERT(ShouldInlineSmiCase(op));
|
| - return kNoConstants;
|
| + if (op == Token::DIV || op == Token::MOD || op == Token::MUL) {
|
| + // We never generate inlined constant smi operations for these.
|
| + return kNoConstants;
|
| + } else if (right->IsSmiLiteral()) {
|
| + return kRightConstant;
|
| + } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) {
|
| + // Don't inline shifts with constant left hand side.
|
| + return kLeftConstant;
|
| + } else {
|
| + return kNoConstants;
|
| + }
|
| }
|
|
|
|
|
| @@ -1598,14 +1608,308 @@
|
| }
|
|
|
|
|
| +void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
|
| + OverwriteMode mode,
|
| + bool left_is_constant_smi,
|
| + Smi* value) {
|
| + Label call_stub, done;
|
| + // Optimistically add smi value with unknown object. If result overflows or is
|
| + // not a smi then we had either a smi overflow or added a smi with a tagged
|
| + // pointer.
|
| + __ mov(r1, Operand(value));
|
| + __ add(r2, r0, r1, SetCC);
|
| + __ b(vs, &call_stub);
|
| + JumpPatchSite patch_site(masm_);
|
| + patch_site.EmitJumpIfNotSmi(r2, &call_stub);
|
| + __ mov(r0, r2);
|
| + __ b(&done);
|
| +
|
| + // Call the shared stub.
|
| + __ bind(&call_stub);
|
| + if (!left_is_constant_smi) {
|
| + __ Swap(r0, r1, r2);
|
| + }
|
| + TypeRecordingBinaryOpStub stub(Token::ADD, mode);
|
| + EmitCallIC(stub.GetCode(), &patch_site);
|
| +
|
| + __ bind(&done);
|
| + context()->Plug(r0);
|
| +}
|
| +
|
| +
|
| +void FullCodeGenerator::EmitConstantSmiSub(Expression* expr,
|
| + OverwriteMode mode,
|
| + bool left_is_constant_smi,
|
| + Smi* value) {
|
| + Label call_stub, done;
|
| + // Optimistically subtract smi value and unknown object. If result overflows
|
| + // or is not a smi then we had either a smi overflow or subtraction between a
|
| + // smi and a tagged pointer.
|
| + __ mov(r1, Operand(value));
|
| + if (left_is_constant_smi) {
|
| + __ sub(r2, r1, r0, SetCC);
|
| + } else {
|
| + __ sub(r2, r0, r1, SetCC);
|
| + }
|
| + __ b(vs, &call_stub);
|
| + JumpPatchSite patch_site(masm_);
|
| + patch_site.EmitJumpIfNotSmi(r2, &call_stub);
|
| + __ mov(r0, r2);
|
| + __ b(&done);
|
| +
|
| + // Call the shared stub.
|
| + __ bind(&call_stub);
|
| + if (!left_is_constant_smi) {
|
| + __ Swap(r0, r1, r2);
|
| + }
|
| + TypeRecordingBinaryOpStub stub(Token::SUB, mode);
|
| + EmitCallIC(stub.GetCode(), &patch_site);
|
| +
|
| + __ bind(&done);
|
| + context()->Plug(r0);
|
| +}
|
| +
|
| +
|
| +void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr,
|
| + Token::Value op,
|
| + OverwriteMode mode,
|
| + Smi* value) {
|
| + Label call_stub, smi_case, done;
|
| + int shift_value = value->value() & 0x1f;
|
| +
|
| + JumpPatchSite patch_site(masm_);
|
| + patch_site.EmitJumpIfSmi(r0, &smi_case);
|
| +
|
| + // Call stub.
|
| + __ bind(&call_stub);
|
| + __ mov(r1, r0);
|
| + __ mov(r0, Operand(value));
|
| + TypeRecordingBinaryOpStub stub(op, mode);
|
| + EmitCallIC(stub.GetCode(), &patch_site);
|
| + __ b(&done);
|
| +
|
| + // Smi case.
|
| + __ bind(&smi_case);
|
| + switch (op) {
|
| + case Token::SHL:
|
| + if (shift_value != 0) {
|
| + __ mov(r1, r0);
|
| + if (shift_value > 1) {
|
| + __ mov(r1, Operand(r1, LSL, shift_value - 1));
|
| + }
|
| + // Convert int result to smi, checking that it is in int range.
|
| + __ SmiTag(r1, SetCC);
|
| + __ b(vs, &call_stub);
|
| + __ mov(r0, r1); // Put result back into r0.
|
| + }
|
| + break;
|
| + case Token::SAR:
|
| + if (shift_value != 0) {
|
| + __ mov(r0, Operand(r0, ASR, shift_value));
|
| + __ bic(r0, r0, Operand(kSmiTagMask));
|
| + }
|
| + break;
|
| + case Token::SHR:
|
| + // SHR must return a positive value. When shifting by 0 or 1 we need to
|
| + // check that smi tagging the result will not create a negative value.
|
| + if (shift_value < 2) {
|
| + __ mov(r2, Operand(shift_value));
|
| + __ SmiUntag(r1, r0);
|
| + if (shift_value != 0) {
|
| + __ mov(r1, Operand(r1, LSR, shift_value));
|
| + }
|
| + __ tst(r1, Operand(0xc0000000));
|
| + __ b(ne, &call_stub);
|
| + __ SmiTag(r0, r1); // result in r0.
|
| + } else {
|
| + __ SmiUntag(r0);
|
| + __ mov(r0, Operand(r0, LSR, shift_value));
|
| + __ SmiTag(r0);
|
| + }
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + __ bind(&done);
|
| + context()->Plug(r0);
|
| +}
|
| +
|
| +
|
| +void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr,
|
| + Token::Value op,
|
| + OverwriteMode mode,
|
| + Smi* value) {
|
| + Label smi_case, done;
|
| +
|
| + JumpPatchSite patch_site(masm_);
|
| + patch_site.EmitJumpIfSmi(r0, &smi_case);
|
| +
|
| + // The order of the arguments does not matter for bit-ops with a
|
| + // constant operand.
|
| + __ mov(r1, Operand(value));
|
| + TypeRecordingBinaryOpStub stub(op, mode);
|
| + EmitCallIC(stub.GetCode(), &patch_site);
|
| + __ jmp(&done);
|
| +
|
| + // Smi case.
|
| + __ bind(&smi_case);
|
| + __ mov(r1, Operand(value));
|
| + switch (op) {
|
| + case Token::BIT_OR:
|
| + __ orr(r0, r0, Operand(r1));
|
| + break;
|
| + case Token::BIT_XOR:
|
| + __ eor(r0, r0, Operand(r1));
|
| + break;
|
| + case Token::BIT_AND:
|
| + __ and_(r0, r0, Operand(r1));
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + __ bind(&done);
|
| + context()->Plug(r0);
|
| +}
|
| +
|
| +
|
| +void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr,
|
| + Token::Value op,
|
| + OverwriteMode mode,
|
| + bool left_is_constant_smi,
|
| + Smi* value) {
|
| + switch (op) {
|
| + case Token::BIT_OR:
|
| + case Token::BIT_XOR:
|
| + case Token::BIT_AND:
|
| + EmitConstantSmiBitOp(expr, op, mode, value);
|
| + break;
|
| + case Token::SHL:
|
| + case Token::SAR:
|
| + case Token::SHR:
|
| + ASSERT(!left_is_constant_smi);
|
| + EmitConstantSmiShiftOp(expr, op, mode, value);
|
| + break;
|
| + case Token::ADD:
|
| + EmitConstantSmiAdd(expr, mode, left_is_constant_smi, value);
|
| + break;
|
| + case Token::SUB:
|
| + EmitConstantSmiSub(expr, mode, left_is_constant_smi, value);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
|
| Token::Value op,
|
| OverwriteMode mode,
|
| - Expression* left,
|
| - Expression* right,
|
| + Expression* left_expr,
|
| + Expression* right_expr,
|
| ConstantOperand constant) {
|
| - ASSERT(constant == kNoConstants); // Only handled case.
|
| - EmitBinaryOp(op, mode);
|
| + if (constant == kRightConstant) {
|
| + Smi* value = Smi::cast(*right_expr->AsLiteral()->handle());
|
| + EmitConstantSmiBinaryOp(expr, op, mode, false, value);
|
| + return;
|
| + } else if (constant == kLeftConstant) {
|
| + Smi* value = Smi::cast(*left_expr->AsLiteral()->handle());
|
| + EmitConstantSmiBinaryOp(expr, op, mode, true, value);
|
| + return;
|
| + }
|
| +
|
| + Label done, smi_case, stub_call;
|
| +
|
| + Register scratch1 = r2;
|
| + Register scratch2 = r3;
|
| +
|
| + // Get the arguments.
|
| + Register left = r1;
|
| + Register right = r0;
|
| + __ pop(left);
|
| +
|
| + // Perform combined smi check on both operands.
|
| + __ orr(scratch1, left, Operand(right));
|
| + STATIC_ASSERT(kSmiTag == 0);
|
| + JumpPatchSite patch_site(masm_);
|
| + patch_site.EmitJumpIfSmi(scratch1, &smi_case);
|
| +
|
| + __ bind(&stub_call);
|
| + TypeRecordingBinaryOpStub stub(op, mode);
|
| + EmitCallIC(stub.GetCode(), &patch_site);
|
| + __ jmp(&done);
|
| +
|
| + __ bind(&smi_case);
|
| + // Smi case. This code works the same way as the smi-smi case in the type
|
| + // recording binary operation stub, see
|
| + // TypeRecordingBinaryOpStub::GenerateSmiSmiOperation for comments.
|
| + switch (op) {
|
| + case Token::SAR:
|
| + __ b(&stub_call);
|
| + __ GetLeastBitsFromSmi(scratch1, right, 5);
|
| + __ mov(right, Operand(left, ASR, scratch1));
|
| + __ bic(right, right, Operand(kSmiTagMask));
|
| + break;
|
| + case Token::SHL: {
|
| + __ b(&stub_call);
|
| + __ SmiUntag(scratch1, left);
|
| + __ GetLeastBitsFromSmi(scratch2, right, 5);
|
| + __ mov(scratch1, Operand(scratch1, LSL, scratch2));
|
| + __ add(scratch2, scratch1, Operand(0x40000000), SetCC);
|
| + __ b(mi, &stub_call);
|
| + __ SmiTag(right, scratch1);
|
| + break;
|
| + }
|
| + case Token::SHR: {
|
| + __ b(&stub_call);
|
| + __ SmiUntag(scratch1, left);
|
| + __ GetLeastBitsFromSmi(scratch2, right, 5);
|
| + __ mov(scratch1, Operand(scratch1, LSR, scratch2));
|
| + __ tst(scratch1, Operand(0xc0000000));
|
| + __ b(ne, &stub_call);
|
| + __ SmiTag(right, scratch1);
|
| + break;
|
| + }
|
| + case Token::ADD:
|
| + __ add(scratch1, left, Operand(right), SetCC);
|
| + __ b(vs, &stub_call);
|
| + __ mov(right, scratch1);
|
| + break;
|
| + case Token::SUB:
|
| + __ sub(scratch1, left, Operand(right), SetCC);
|
| + __ b(vs, &stub_call);
|
| + __ mov(right, scratch1);
|
| + break;
|
| + case Token::MUL: {
|
| + __ SmiUntag(ip, right);
|
| + __ smull(scratch1, scratch2, left, ip);
|
| + __ mov(ip, Operand(scratch1, ASR, 31));
|
| + __ cmp(ip, Operand(scratch2));
|
| + __ b(ne, &stub_call);
|
| + __ tst(scratch1, Operand(scratch1));
|
| + __ mov(right, Operand(scratch1), LeaveCC, ne);
|
| + __ b(ne, &done);
|
| + __ add(scratch2, right, Operand(left), SetCC);
|
| + __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl);
|
| + __ b(mi, &stub_call);
|
| + break;
|
| + }
|
| + case Token::BIT_OR:
|
| + __ orr(right, left, Operand(right));
|
| + break;
|
| + case Token::BIT_AND:
|
| + __ and_(right, left, Operand(right));
|
| + break;
|
| + case Token::BIT_XOR:
|
| + __ eor(right, left, Operand(right));
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + __ bind(&done);
|
| + context()->Plug(r0);
|
| }
|
|
|
|
|
| @@ -3287,13 +3591,16 @@
|
|
|
| // Inline smi case if we are in a loop.
|
| Label stub_call, done;
|
| + JumpPatchSite patch_site(masm_);
|
| +
|
| int count_value = expr->op() == Token::INC ? 1 : -1;
|
| if (ShouldInlineSmiCase(expr->op())) {
|
| __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
|
| __ b(vs, &stub_call);
|
| // We could eliminate this smi check if we split the code at
|
| // the first smi check before calling ToNumber.
|
| - __ JumpIfSmi(r0, &done);
|
| + patch_site.EmitJumpIfSmi(r0, &done);
|
| +
|
| __ bind(&stub_call);
|
| // Call stub. Undo operation first.
|
| __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
|
| @@ -3303,8 +3610,8 @@
|
| // Record position before stub call.
|
| SetSourcePosition(expr->position());
|
|
|
| - GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0);
|
| - __ CallStub(&stub);
|
| + TypeRecordingBinaryOpStub stub(Token::ADD, NO_OVERWRITE);
|
| + EmitCallIC(stub.GetCode(), &patch_site);
|
| __ bind(&done);
|
|
|
| // Store the value returned in r0.
|
|
|