diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 61fbd76415..e7b2758afd 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -246,6 +246,13 @@ void FullCodeGenerator::EmitReturnSequence() { } +FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( + Token::Value op, Expression* left, Expression* right) { + ASSERT(ShouldInlineSmiCase(op)); + return kNoConstants; +} + + void FullCodeGenerator::Apply(Expression::Context context, Register reg) { switch (context) { case Expression::kUninitialized: @@ -1144,10 +1151,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; LhsKind assign_type = VARIABLE; - Property* prop = expr->target()->AsProperty(); - if (prop != NULL) { - assign_type = - (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; + Property* property = expr->target()->AsProperty(); + if (property != NULL) { + assign_type = (property->key()->IsPropertyName()) + ? NAMED_PROPERTY + : KEYED_PROPERTY; } // Evaluate LHS expression. @@ -1158,61 +1166,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { case NAMED_PROPERTY: if (expr->is_compound()) { // We need the receiver both on the stack and in the accumulator. - VisitForValue(prop->obj(), kAccumulator); + VisitForValue(property->obj(), kAccumulator); __ push(result_register()); } else { - VisitForValue(prop->obj(), kStack); + VisitForValue(property->obj(), kStack); } break; case KEYED_PROPERTY: - // We need the key and receiver on both the stack and in r0 and r1. if (expr->is_compound()) { - VisitForValue(prop->obj(), kStack); - VisitForValue(prop->key(), kAccumulator); + VisitForValue(property->obj(), kStack); + VisitForValue(property->key(), kAccumulator); __ ldr(r1, MemOperand(sp, 0)); __ push(r0); } else { - VisitForValue(prop->obj(), kStack); - VisitForValue(prop->key(), kStack); + VisitForValue(property->obj(), kStack); + VisitForValue(property->key(), kStack); } break; } - // If we have a compound assignment: Get value of LHS expression and - // store in on top of the stack. if (expr->is_compound()) { Location saved_location = location_; - location_ = kStack; + location_ = kAccumulator; switch (assign_type) { case VARIABLE: EmitVariableLoad(expr->target()->AsVariableProxy()->var(), Expression::kValue); break; case NAMED_PROPERTY: - EmitNamedPropertyLoad(prop); - __ push(result_register()); + EmitNamedPropertyLoad(property); break; case KEYED_PROPERTY: - EmitKeyedPropertyLoad(prop); - __ push(result_register()); + EmitKeyedPropertyLoad(property); break; } - location_ = saved_location; - } - // Evaluate RHS expression. - Expression* rhs = expr->value(); - VisitForValue(rhs, kAccumulator); + Token::Value op = expr->binary_op(); + ConstantOperand constant = ShouldInlineSmiCase(op) + ? GetConstantOperand(op, expr->target(), expr->value()) + : kNoConstants; + ASSERT(constant == kRightConstant || constant == kNoConstants); + if (constant == kNoConstants) { + __ push(r0); // Left operand goes on the stack. + VisitForValue(expr->value(), kAccumulator); + } - // If we have a compound assignment: Apply operator. - if (expr->is_compound()) { - Location saved_location = location_; - location_ = kAccumulator; OverwriteMode mode = expr->value()->ResultOverwriteAllowed() ? OVERWRITE_RIGHT : NO_OVERWRITE; - EmitBinaryOp(expr->binary_op(), Expression::kValue, mode); + SetSourcePosition(expr->position() + 1); + if (ShouldInlineSmiCase(op)) { + EmitInlineSmiBinaryOp(expr, + op, + Expression::kValue, + mode, + expr->target(), + expr->value(), + constant); + } else { + EmitBinaryOp(op, Expression::kValue, mode); + } location_ = saved_location; + + } else { + VisitForValue(expr->value(), kAccumulator); } // Record source position before possible IC call. @@ -1253,6 +1270,18 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { } +void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, + Token::Value op, + Expression::Context context, + OverwriteMode mode, + Expression* left, + Expression* right, + ConstantOperand constant) { + ASSERT(constant == kNoConstants); // Only handled case. + EmitBinaryOp(op, context, mode); +} + + void FullCodeGenerator::EmitBinaryOp(Token::Value op, Expression::Context context, OverwriteMode mode) { diff --git a/src/ast.h b/src/ast.h index d1a740c496..5071b2cd73 100644 --- a/src/ast.h +++ b/src/ast.h @@ -205,6 +205,9 @@ class Expression: public AstNode { // False for operations that can return one of their operands. virtual bool ResultOverwriteAllowed() { return false; } + // True iff the expression is a literal represented as a smi. + virtual bool IsSmiLiteral() { return false; } + // Static type information for this expression. StaticType* type() { return &type_; } @@ -775,6 +778,7 @@ class Literal: public Expression { virtual void Accept(AstVisitor* v); virtual bool IsTrivial() { return true; } + virtual bool IsSmiLiteral() { return handle_->IsSmi(); } // Type testing & conversion. virtual Literal* AsLiteral() { return this; } diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 65c1e2adea..b5baa2a9f6 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -516,18 +516,21 @@ void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) { void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { Comment cmnt(masm_, "[ BinaryOperation"); + Token::Value op = expr->op(); + Expression* left = expr->left(); + Expression* right = expr->right(); - OverwriteMode overwrite_mode = NO_OVERWRITE; - if (expr->left()->ResultOverwriteAllowed()) { - overwrite_mode = OVERWRITE_LEFT; - } else if (expr->right()->ResultOverwriteAllowed()) { - overwrite_mode = OVERWRITE_RIGHT; + OverwriteMode mode = NO_OVERWRITE; + if (left->ResultOverwriteAllowed()) { + mode = OVERWRITE_LEFT; + } else if (right->ResultOverwriteAllowed()) { + mode = OVERWRITE_RIGHT; } - switch (expr->op()) { + switch (op) { case Token::COMMA: - VisitForEffect(expr->left()); - Visit(expr->right()); + VisitForEffect(left); + Visit(right); break; case Token::OR: @@ -545,12 +548,31 @@ void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { case Token::BIT_XOR: case Token::SHL: case Token::SHR: - case Token::SAR: - VisitForValue(expr->left(), kStack); - VisitForValue(expr->right(), kAccumulator); + case Token::SAR: { + // Figure out if either of the operands is a constant. + ConstantOperand constant = ShouldInlineSmiCase(op) + ? GetConstantOperand(op, left, right) + : kNoConstants; + + // Load only the operands that we need to materialize. + if (constant == kNoConstants) { + VisitForValue(left, kStack); + VisitForValue(right, kAccumulator); + } else if (constant == kRightConstant) { + VisitForValue(left, kAccumulator); + } else { + ASSERT(constant == kLeftConstant); + VisitForValue(right, kAccumulator); + } + SetSourcePosition(expr->position()); - EmitBinaryOp(expr->op(), context_, overwrite_mode); + if (ShouldInlineSmiCase(op)) { + EmitInlineSmiBinaryOp(expr, op, context_, mode, left, right, constant); + } else { + EmitBinaryOp(op, context_, mode); + } break; + } default: UNREACHABLE(); diff --git a/src/full-codegen.h b/src/full-codegen.h index 1f7527901c..840c825014 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -237,6 +237,12 @@ class FullCodeGenerator: public AstVisitor { kStack }; + enum ConstantOperand { + kNoConstants, + kLeftConstant, + kRightConstant + }; + // Compute the frame pointer relative offset for a given local or // parameter slot. int SlotOffset(Slot* slot); @@ -245,6 +251,11 @@ class FullCodeGenerator: public AstVisitor { // operation. bool ShouldInlineSmiCase(Token::Value op); + // Compute which (if any) of the operands is a compile-time constant. + ConstantOperand GetConstantOperand(Token::Value op, + Expression* left, + Expression* right); + // Emit code to convert a pure value (in a register, slot, as a literal, // or on top of the stack) into the result expected according to an // expression context. @@ -361,7 +372,6 @@ class FullCodeGenerator: public AstVisitor { void EmitCallWithIC(Call* expr, Handle name, RelocInfo::Mode mode); void EmitKeyedCallWithIC(Call* expr, Expression* key, RelocInfo::Mode mode); - // Platform-specific code for inline runtime calls. void EmitInlineRuntimeCall(CallRuntime* expr); @@ -393,6 +403,47 @@ class FullCodeGenerator: public AstVisitor { Expression::Context context, OverwriteMode mode); + // Helper functions for generating inlined smi code for certain + // binary operations. + void EmitInlineSmiBinaryOp(Expression* expr, + Token::Value op, + Expression::Context context, + OverwriteMode mode, + Expression* left, + Expression* right, + ConstantOperand constant); + + void EmitConstantSmiBinaryOp(Expression* expr, + Token::Value op, + Expression::Context context, + OverwriteMode mode, + bool left_is_constant_smi, + Smi* value); + + void EmitConstantSmiBitOp(Expression* expr, + Token::Value op, + Expression::Context context, + OverwriteMode mode, + Smi* value); + + void EmitConstantSmiShiftOp(Expression* expr, + Token::Value op, + Expression::Context context, + OverwriteMode mode, + Smi* value); + + void EmitConstantSmiAdd(Expression* expr, + Expression::Context context, + OverwriteMode mode, + bool left_is_constant_smi, + Smi* value); + + void EmitConstantSmiSub(Expression* expr, + Expression::Context context, + OverwriteMode mode, + bool left_is_constant_smi, + Smi* value); + // Assign to the given expression as if via '='. The right-hand-side value // is expected in the accumulator. void EmitAssignment(Expression* expr); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index de772f88d3..b3d19f21e6 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -217,12 +217,28 @@ void FullCodeGenerator::EmitReturnSequence() { // Check that the size of the code used for returning matches what is // expected by the debugger. ASSERT_EQ(Assembler::kJSReturnSequenceLength, - masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); + masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); #endif } } +FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( + Token::Value op, Expression* left, Expression* right) { + ASSERT(ShouldInlineSmiCase(op)); + 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)) { + return kLeftConstant; + } else { + return kNoConstants; + } +} + + void FullCodeGenerator::Apply(Expression::Context context, Register reg) { switch (context) { case Expression::kUninitialized: @@ -1152,10 +1168,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; LhsKind assign_type = VARIABLE; - Property* prop = expr->target()->AsProperty(); - if (prop != NULL) { - assign_type = - (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; + Property* property = expr->target()->AsProperty(); + if (property != NULL) { + assign_type = (property->key()->IsPropertyName()) + ? NAMED_PROPERTY + : KEYED_PROPERTY; } // Evaluate LHS expression. @@ -1166,60 +1183,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { case NAMED_PROPERTY: if (expr->is_compound()) { // We need the receiver both on the stack and in the accumulator. - VisitForValue(prop->obj(), kAccumulator); + VisitForValue(property->obj(), kAccumulator); __ push(result_register()); } else { - VisitForValue(prop->obj(), kStack); + VisitForValue(property->obj(), kStack); } break; case KEYED_PROPERTY: if (expr->is_compound()) { - VisitForValue(prop->obj(), kStack); - VisitForValue(prop->key(), kAccumulator); + VisitForValue(property->obj(), kStack); + VisitForValue(property->key(), kAccumulator); __ mov(edx, Operand(esp, 0)); __ push(eax); } else { - VisitForValue(prop->obj(), kStack); - VisitForValue(prop->key(), kStack); + VisitForValue(property->obj(), kStack); + VisitForValue(property->key(), kStack); } break; } - // If we have a compound assignment: Get value of LHS expression and - // store in on top of the stack. if (expr->is_compound()) { Location saved_location = location_; - location_ = kStack; + location_ = kAccumulator; switch (assign_type) { case VARIABLE: EmitVariableLoad(expr->target()->AsVariableProxy()->var(), Expression::kValue); break; case NAMED_PROPERTY: - EmitNamedPropertyLoad(prop); - __ push(result_register()); + EmitNamedPropertyLoad(property); break; case KEYED_PROPERTY: - EmitKeyedPropertyLoad(prop); - __ push(result_register()); + EmitKeyedPropertyLoad(property); break; } - location_ = saved_location; - } - // Evaluate RHS expression. - Expression* rhs = expr->value(); - VisitForValue(rhs, kAccumulator); + Token::Value op = expr->binary_op(); + ConstantOperand constant = ShouldInlineSmiCase(op) + ? GetConstantOperand(op, expr->target(), expr->value()) + : kNoConstants; + ASSERT(constant == kRightConstant || constant == kNoConstants); + if (constant == kNoConstants) { + __ push(eax); // Left operand goes on the stack. + VisitForValue(expr->value(), kAccumulator); + } - // If we have a compound assignment: Apply operator. - if (expr->is_compound()) { - Location saved_location = location_; - location_ = kAccumulator; OverwriteMode mode = expr->value()->ResultOverwriteAllowed() ? OVERWRITE_RIGHT : NO_OVERWRITE; - EmitBinaryOp(expr->binary_op(), Expression::kValue, mode); + SetSourcePosition(expr->position() + 1); + if (ShouldInlineSmiCase(op)) { + EmitInlineSmiBinaryOp(expr, + op, + Expression::kValue, + mode, + expr->target(), + expr->value(), + constant); + } else { + EmitBinaryOp(op, Expression::kValue, mode); + } location_ = saved_location; + + } else { + VisitForValue(expr->value(), kAccumulator); } // Record source position before possible IC call. @@ -1260,6 +1287,313 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { } +void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr, + Expression::Context context, + OverwriteMode mode, + bool left_is_constant_smi, + Smi* value) { + Label call_stub, done; + __ add(Operand(eax), Immediate(value)); + __ j(overflow, &call_stub); + __ test(eax, Immediate(kSmiTagMask)); + __ j(zero, &done); + + // Undo the optimistic add operation and call the shared stub. + __ bind(&call_stub); + __ sub(Operand(eax), Immediate(value)); + Token::Value op = Token::ADD; + GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown()); + if (left_is_constant_smi) { + __ push(Immediate(value)); + __ push(eax); + } else { + __ push(eax); + __ push(Immediate(value)); + } + __ CallStub(&stub); + __ bind(&done); + Apply(context, eax); +} + + +void FullCodeGenerator::EmitConstantSmiSub(Expression* expr, + Expression::Context context, + OverwriteMode mode, + bool left_is_constant_smi, + Smi* value) { + Label call_stub, done; + if (left_is_constant_smi) { + __ mov(ecx, eax); + __ mov(eax, Immediate(value)); + __ sub(Operand(eax), ecx); + } else { + __ sub(Operand(eax), Immediate(value)); + } + __ j(overflow, &call_stub); + __ test(eax, Immediate(kSmiTagMask)); + __ j(zero, &done); + + __ bind(&call_stub); + if (left_is_constant_smi) { + __ push(Immediate(value)); + __ push(ecx); + } else { + // Undo the optimistic sub operation. + __ add(Operand(eax), Immediate(value)); + + __ push(eax); + __ push(Immediate(value)); + } + + Token::Value op = Token::SUB; + GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown()); + __ CallStub(&stub); + __ bind(&done); + Apply(context, eax); +} + + +void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr, + Token::Value op, + Expression::Context context, + OverwriteMode mode, + Smi* value) { + Label call_stub, smi_case, done; + int shift_value = value->value() & 0x1f; + + __ test(eax, Immediate(kSmiTagMask)); + __ j(zero, &smi_case); + + __ bind(&call_stub); + GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown()); + __ push(eax); + __ push(Immediate(value)); + __ CallStub(&stub); + __ jmp(&done); + + __ bind(&smi_case); + switch (op) { + case Token::SHL: + if (shift_value != 0) { + __ mov(edx, eax); + if (shift_value > 1) { + __ shl(edx, shift_value - 1); + } + // Convert int result to smi, checking that it is in int range. + ASSERT(kSmiTagSize == 1); // Adjust code if not the case. + __ add(edx, Operand(edx)); + __ j(overflow, &call_stub); + __ mov(eax, edx); // Put result back into eax. + } + break; + case Token::SAR: + if (shift_value != 0) { + __ sar(eax, shift_value); + __ and_(eax, ~kSmiTagMask); + } + break; + case Token::SHR: + if (shift_value < 2) { + __ mov(edx, eax); + __ SmiUntag(edx); + __ shr(edx, shift_value); + __ test(edx, Immediate(0xc0000000)); + __ j(not_zero, &call_stub); + __ SmiTag(edx); + __ mov(eax, edx); // Put result back into eax. + } else { + __ SmiUntag(eax); + __ shr(eax, shift_value); + __ SmiTag(eax); + } + break; + default: + UNREACHABLE(); + } + + __ bind(&done); + Apply(context, eax); +} + + +void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr, + Token::Value op, + Expression::Context context, + OverwriteMode mode, + Smi* value) { + Label smi_case, done; + __ test(eax, Immediate(kSmiTagMask)); + __ j(zero, &smi_case); + + GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown()); + // The order of the arguments does not matter for bit-ops with a + // constant operand. + __ push(Immediate(value)); + __ push(eax); + __ CallStub(&stub); + __ jmp(&done); + + __ bind(&smi_case); + switch (op) { + case Token::BIT_OR: + __ or_(Operand(eax), Immediate(value)); + break; + case Token::BIT_XOR: + __ xor_(Operand(eax), Immediate(value)); + break; + case Token::BIT_AND: + __ and_(Operand(eax), Immediate(value)); + break; + default: + UNREACHABLE(); + } + + __ bind(&done); + Apply(context, eax); +} + + +void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr, + Token::Value op, + Expression::Context context, + 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, context, mode, value); + break; + case Token::SHL: + case Token::SAR: + case Token::SHR: + ASSERT(!left_is_constant_smi); + EmitConstantSmiShiftOp(expr, op, context, mode, value); + break; + case Token::ADD: + EmitConstantSmiAdd(expr, context, mode, left_is_constant_smi, value); + break; + case Token::SUB: + EmitConstantSmiSub(expr, context, mode, left_is_constant_smi, value); + break; + default: + UNREACHABLE(); + } +} + + +void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, + Token::Value op, + Expression::Context context, + OverwriteMode mode, + Expression* left, + Expression* right, + ConstantOperand constant) { + if (constant == kRightConstant) { + Smi* value = Smi::cast(*right->AsLiteral()->handle()); + EmitConstantSmiBinaryOp(expr, op, context, mode, false, value); + return; + } else if (constant == kLeftConstant) { + Smi* value = Smi::cast(*left->AsLiteral()->handle()); + EmitConstantSmiBinaryOp(expr, op, context, mode, true, value); + return; + } + + // Do combined smi check of the operands. Left operand is on the + // stack. Right operand is in eax. + Label done, stub_call, smi_case; + __ pop(edx); + __ mov(ecx, eax); + __ or_(eax, Operand(edx)); + __ test(eax, Immediate(kSmiTagMask)); + __ j(zero, &smi_case); + + __ bind(&stub_call); + GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown()); + if (stub.ArgsInRegistersSupported()) { + stub.GenerateCall(masm_, edx, ecx); + } else { + __ push(edx); + __ push(ecx); + __ CallStub(&stub); + } + __ jmp(&done); + + __ bind(&smi_case); + __ mov(eax, edx); // Copy left operand in case of a stub call. + + switch (op) { + case Token::SAR: + __ SmiUntag(eax); + __ SmiUntag(ecx); + __ sar_cl(eax); // No checks of result necessary + __ SmiTag(eax); + break; + case Token::SHL: { + Label result_ok; + __ SmiUntag(eax); + __ SmiUntag(ecx); + __ shl_cl(eax); + // Check that the *signed* result fits in a smi. + __ cmp(eax, 0xc0000000); + __ j(positive, &result_ok); + __ SmiTag(ecx); + __ jmp(&stub_call); + __ bind(&result_ok); + __ SmiTag(eax); + break; + } + case Token::SHR: { + Label result_ok; + __ SmiUntag(eax); + __ SmiUntag(ecx); + __ shr_cl(eax); + __ test(eax, Immediate(0xc0000000)); + __ j(zero, &result_ok); + __ SmiTag(ecx); + __ jmp(&stub_call); + __ bind(&result_ok); + __ SmiTag(eax); + break; + } + case Token::ADD: + __ add(eax, Operand(ecx)); + __ j(overflow, &stub_call); + break; + case Token::SUB: + __ sub(eax, Operand(ecx)); + __ j(overflow, &stub_call); + break; + case Token::MUL: { + __ SmiUntag(eax); + __ imul(eax, Operand(ecx)); + __ j(overflow, &stub_call); + __ test(eax, Operand(eax)); + __ j(not_zero, &done, taken); + __ mov(ebx, edx); + __ or_(ebx, Operand(ecx)); + __ j(negative, &stub_call); + break; + } + case Token::BIT_OR: + __ or_(eax, Operand(ecx)); + break; + case Token::BIT_AND: + __ and_(eax, Operand(ecx)); + break; + case Token::BIT_XOR: + __ xor_(eax, Operand(ecx)); + break; + default: + UNREACHABLE(); + } + + __ bind(&done); + Apply(context, eax); +} + + void FullCodeGenerator::EmitBinaryOp(Token::Value op, Expression::Context context, OverwriteMode mode) { diff --git a/src/token.h b/src/token.h index 0d8960b8ee..ebc7fea1cd 100644 --- a/src/token.h +++ b/src/token.h @@ -248,6 +248,10 @@ class Token { return op == INC || op == DEC; } + static bool IsShiftOp(Value op) { + return (SHL <= op) && (op <= SHR); + } + // Returns a string corresponding to the JS token string // (.e., "<" for the token LT) or NULL if the token doesn't // have a (unique) string (e.g. an IDENTIFIER). diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 4eadac7eac..20a123e797 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -230,6 +230,13 @@ void FullCodeGenerator::EmitReturnSequence() { } +FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( + Token::Value op, Expression* left, Expression* right) { + ASSERT(ShouldInlineSmiCase(op)); + return kNoConstants; +} + + void FullCodeGenerator::Apply(Expression::Context context, Register reg) { switch (context) { case Expression::kUninitialized: @@ -1156,10 +1163,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; LhsKind assign_type = VARIABLE; - Property* prop = expr->target()->AsProperty(); - if (prop != NULL) { - assign_type = - (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; + Property* property = expr->target()->AsProperty(); + if (property != NULL) { + assign_type = (property->key()->IsPropertyName()) + ? NAMED_PROPERTY + : KEYED_PROPERTY; } // Evaluate LHS expression. @@ -1170,60 +1178,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { case NAMED_PROPERTY: if (expr->is_compound()) { // We need the receiver both on the stack and in the accumulator. - VisitForValue(prop->obj(), kAccumulator); + VisitForValue(property->obj(), kAccumulator); __ push(result_register()); } else { - VisitForValue(prop->obj(), kStack); + VisitForValue(property->obj(), kStack); } break; case KEYED_PROPERTY: if (expr->is_compound()) { - VisitForValue(prop->obj(), kStack); - VisitForValue(prop->key(), kAccumulator); + VisitForValue(property->obj(), kStack); + VisitForValue(property->key(), kAccumulator); __ movq(rdx, Operand(rsp, 0)); __ push(rax); } else { - VisitForValue(prop->obj(), kStack); - VisitForValue(prop->key(), kStack); + VisitForValue(property->obj(), kStack); + VisitForValue(property->key(), kStack); } break; } - // If we have a compound assignment: Get value of LHS expression and - // store in on top of the stack. if (expr->is_compound()) { Location saved_location = location_; - location_ = kStack; + location_ = kAccumulator; switch (assign_type) { case VARIABLE: EmitVariableLoad(expr->target()->AsVariableProxy()->var(), Expression::kValue); break; case NAMED_PROPERTY: - EmitNamedPropertyLoad(prop); - __ push(result_register()); + EmitNamedPropertyLoad(property); break; case KEYED_PROPERTY: - EmitKeyedPropertyLoad(prop); - __ push(result_register()); + EmitKeyedPropertyLoad(property); break; } - location_ = saved_location; - } - // Evaluate RHS expression. - Expression* rhs = expr->value(); - VisitForValue(rhs, kAccumulator); + Token::Value op = expr->binary_op(); + ConstantOperand constant = ShouldInlineSmiCase(op) + ? GetConstantOperand(op, expr->target(), expr->value()) + : kNoConstants; + ASSERT(constant == kRightConstant || constant == kNoConstants); + if (constant == kNoConstants) { + __ push(rax); // Left operand goes on the stack. + VisitForValue(expr->value(), kAccumulator); + } - // If we have a compound assignment: Apply operator. - if (expr->is_compound()) { - Location saved_location = location_; - location_ = kAccumulator; OverwriteMode mode = expr->value()->ResultOverwriteAllowed() ? OVERWRITE_RIGHT : NO_OVERWRITE; - EmitBinaryOp(expr->binary_op(), Expression::kValue, mode); + SetSourcePosition(expr->position() + 1); + if (ShouldInlineSmiCase(op)) { + EmitInlineSmiBinaryOp(expr, + op, + Expression::kValue, + mode, + expr->target(), + expr->value(), + constant); + } else { + EmitBinaryOp(op, Expression::kValue, mode); + } location_ = saved_location; + + } else { + VisitForValue(expr->value(), kAccumulator); } // Record source position before possible IC call. @@ -1264,6 +1282,74 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { } +void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, + Token::Value op, + Expression::Context context, + OverwriteMode mode, + Expression* left, + Expression* right, + ConstantOperand constant) { + ASSERT(constant == kNoConstants); // Only handled case. + + // Do combined smi check of the operands. Left operand is on the + // stack (popped into rdx). Right operand is in rax but moved into + // rcx to make the shifts easier. + Label done, stub_call, smi_case; + __ pop(rdx); + __ movq(rcx, rax); + Condition smi = __ CheckBothSmi(rdx, rax); + __ j(smi, &smi_case); + + __ bind(&stub_call); + GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown()); + if (stub.ArgsInRegistersSupported()) { + stub.GenerateCall(masm_, rdx, rcx); + } else { + __ push(rdx); + __ push(rcx); + __ CallStub(&stub); + } + __ jmp(&done); + + __ bind(&smi_case); + switch (op) { + case Token::SAR: + __ SmiShiftArithmeticRight(rax, rdx, rcx); + break; + case Token::SHL: + __ SmiShiftLeft(rax, rdx, rcx); + break; + case Token::SHR: + __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call); + break; + case Token::ADD: + __ SmiAdd(rax, rdx, rcx, &stub_call); + break; + case Token::SUB: + __ SmiSub(rax, rdx, rcx, &stub_call); + break; + case Token::MUL: + __ SmiMul(rax, rdx, rcx, &stub_call); + break; + case Token::BIT_OR: + __ SmiOr(rax, rdx, rcx); + break; + case Token::BIT_AND: + __ SmiAnd(rax, rdx, rcx); + break; + case Token::BIT_XOR: + __ SmiXor(rax, rdx, rcx); + break; + default: + UNREACHABLE(); + break; + } + + __ bind(&done); + Apply(context, rax); +} + + void FullCodeGenerator::EmitBinaryOp(Token::Value op, Expression::Context context, OverwriteMode mode) { @@ -1971,8 +2057,8 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList* args) { void FullCodeGenerator::EmitArguments(ZoneList* args) { ASSERT(args->length() == 1); - // ArgumentsAccessStub expects the key in edx and the formal - // parameter count in eax. + // ArgumentsAccessStub expects the key in rdx and the formal + // parameter count in rax. VisitForValue(args->at(0), kAccumulator); __ movq(rdx, rax); __ Move(rax, Smi::FromInt(scope()->num_parameters())); @@ -2176,7 +2262,7 @@ void FullCodeGenerator::EmitSetValueOf(ZoneList* args) { VisitForValue(args->at(0), kStack); // Load the object. VisitForValue(args->at(1), kAccumulator); // Load the value. - __ pop(rbx); // rax = value. ebx = object. + __ pop(rbx); // rax = value. rbx = object. Label done; // If the object is a smi, return the value.