Commit 6d5451d6 authored by kasperl@chromium.org's avatar kasperl@chromium.org

Add inlining of binary smi operations in the full codegens on IA32

and x64 (on IA32 we even fold constants into the instructions for
a more compact representation) and prepare the ARM full codegen for
the doing the same there.
Review URL: http://codereview.chromium.org/3195028

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5351 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 7672338b
...@@ -246,6 +246,13 @@ void FullCodeGenerator::EmitReturnSequence() { ...@@ -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) { void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
switch (context) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
...@@ -1144,10 +1151,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1144,10 +1151,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
LhsKind assign_type = VARIABLE; LhsKind assign_type = VARIABLE;
Property* prop = expr->target()->AsProperty(); Property* property = expr->target()->AsProperty();
if (prop != NULL) { if (property != NULL) {
assign_type = assign_type = (property->key()->IsPropertyName())
(prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; ? NAMED_PROPERTY
: KEYED_PROPERTY;
} }
// Evaluate LHS expression. // Evaluate LHS expression.
...@@ -1158,61 +1166,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1158,61 +1166,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
case NAMED_PROPERTY: case NAMED_PROPERTY:
if (expr->is_compound()) { if (expr->is_compound()) {
// We need the receiver both on the stack and in the accumulator. // We need the receiver both on the stack and in the accumulator.
VisitForValue(prop->obj(), kAccumulator); VisitForValue(property->obj(), kAccumulator);
__ push(result_register()); __ push(result_register());
} else { } else {
VisitForValue(prop->obj(), kStack); VisitForValue(property->obj(), kStack);
} }
break; break;
case KEYED_PROPERTY: case KEYED_PROPERTY:
// We need the key and receiver on both the stack and in r0 and r1.
if (expr->is_compound()) { if (expr->is_compound()) {
VisitForValue(prop->obj(), kStack); VisitForValue(property->obj(), kStack);
VisitForValue(prop->key(), kAccumulator); VisitForValue(property->key(), kAccumulator);
__ ldr(r1, MemOperand(sp, 0)); __ ldr(r1, MemOperand(sp, 0));
__ push(r0); __ push(r0);
} else { } else {
VisitForValue(prop->obj(), kStack); VisitForValue(property->obj(), kStack);
VisitForValue(prop->key(), kStack); VisitForValue(property->key(), kStack);
} }
break; break;
} }
// If we have a compound assignment: Get value of LHS expression and
// store in on top of the stack.
if (expr->is_compound()) { if (expr->is_compound()) {
Location saved_location = location_; Location saved_location = location_;
location_ = kStack; location_ = kAccumulator;
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var(), EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
Expression::kValue); Expression::kValue);
break; break;
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyLoad(prop); EmitNamedPropertyLoad(property);
__ push(result_register());
break; break;
case KEYED_PROPERTY: case KEYED_PROPERTY:
EmitKeyedPropertyLoad(prop); EmitKeyedPropertyLoad(property);
__ push(result_register());
break; break;
} }
location_ = saved_location;
}
// Evaluate RHS expression. Token::Value op = expr->binary_op();
Expression* rhs = expr->value(); ConstantOperand constant = ShouldInlineSmiCase(op)
VisitForValue(rhs, kAccumulator); ? 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() OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
? OVERWRITE_RIGHT ? OVERWRITE_RIGHT
: NO_OVERWRITE; : 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; location_ = saved_location;
} else {
VisitForValue(expr->value(), kAccumulator);
} }
// Record source position before possible IC call. // Record source position before possible IC call.
...@@ -1253,6 +1270,18 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { ...@@ -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, void FullCodeGenerator::EmitBinaryOp(Token::Value op,
Expression::Context context, Expression::Context context,
OverwriteMode mode) { OverwriteMode mode) {
......
...@@ -205,6 +205,9 @@ class Expression: public AstNode { ...@@ -205,6 +205,9 @@ class Expression: public AstNode {
// False for operations that can return one of their operands. // False for operations that can return one of their operands.
virtual bool ResultOverwriteAllowed() { return false; } 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. // Static type information for this expression.
StaticType* type() { return &type_; } StaticType* type() { return &type_; }
...@@ -775,6 +778,7 @@ class Literal: public Expression { ...@@ -775,6 +778,7 @@ class Literal: public Expression {
virtual void Accept(AstVisitor* v); virtual void Accept(AstVisitor* v);
virtual bool IsTrivial() { return true; } virtual bool IsTrivial() { return true; }
virtual bool IsSmiLiteral() { return handle_->IsSmi(); }
// Type testing & conversion. // Type testing & conversion.
virtual Literal* AsLiteral() { return this; } virtual Literal* AsLiteral() { return this; }
......
...@@ -516,18 +516,21 @@ void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) { ...@@ -516,18 +516,21 @@ void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation"); Comment cmnt(masm_, "[ BinaryOperation");
Token::Value op = expr->op();
OverwriteMode overwrite_mode = NO_OVERWRITE; Expression* left = expr->left();
if (expr->left()->ResultOverwriteAllowed()) { Expression* right = expr->right();
overwrite_mode = OVERWRITE_LEFT;
} else if (expr->right()->ResultOverwriteAllowed()) { OverwriteMode mode = NO_OVERWRITE;
overwrite_mode = OVERWRITE_RIGHT; if (left->ResultOverwriteAllowed()) {
mode = OVERWRITE_LEFT;
} else if (right->ResultOverwriteAllowed()) {
mode = OVERWRITE_RIGHT;
} }
switch (expr->op()) { switch (op) {
case Token::COMMA: case Token::COMMA:
VisitForEffect(expr->left()); VisitForEffect(left);
Visit(expr->right()); Visit(right);
break; break;
case Token::OR: case Token::OR:
...@@ -545,12 +548,31 @@ void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { ...@@ -545,12 +548,31 @@ void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
case Token::BIT_XOR: case Token::BIT_XOR:
case Token::SHL: case Token::SHL:
case Token::SHR: case Token::SHR:
case Token::SAR: case Token::SAR: {
VisitForValue(expr->left(), kStack); // Figure out if either of the operands is a constant.
VisitForValue(expr->right(), kAccumulator); 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()); 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; break;
}
default: default:
UNREACHABLE(); UNREACHABLE();
......
...@@ -237,6 +237,12 @@ class FullCodeGenerator: public AstVisitor { ...@@ -237,6 +237,12 @@ class FullCodeGenerator: public AstVisitor {
kStack kStack
}; };
enum ConstantOperand {
kNoConstants,
kLeftConstant,
kRightConstant
};
// Compute the frame pointer relative offset for a given local or // Compute the frame pointer relative offset for a given local or
// parameter slot. // parameter slot.
int SlotOffset(Slot* slot); int SlotOffset(Slot* slot);
...@@ -245,6 +251,11 @@ class FullCodeGenerator: public AstVisitor { ...@@ -245,6 +251,11 @@ class FullCodeGenerator: public AstVisitor {
// operation. // operation.
bool ShouldInlineSmiCase(Token::Value op); 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, // 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 // or on top of the stack) into the result expected according to an
// expression context. // expression context.
...@@ -361,7 +372,6 @@ class FullCodeGenerator: public AstVisitor { ...@@ -361,7 +372,6 @@ class FullCodeGenerator: public AstVisitor {
void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode); void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode);
void EmitKeyedCallWithIC(Call* expr, Expression* key, RelocInfo::Mode mode); void EmitKeyedCallWithIC(Call* expr, Expression* key, RelocInfo::Mode mode);
// Platform-specific code for inline runtime calls. // Platform-specific code for inline runtime calls.
void EmitInlineRuntimeCall(CallRuntime* expr); void EmitInlineRuntimeCall(CallRuntime* expr);
...@@ -393,6 +403,47 @@ class FullCodeGenerator: public AstVisitor { ...@@ -393,6 +403,47 @@ class FullCodeGenerator: public AstVisitor {
Expression::Context context, Expression::Context context,
OverwriteMode mode); 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 // Assign to the given expression as if via '='. The right-hand-side value
// is expected in the accumulator. // is expected in the accumulator.
void EmitAssignment(Expression* expr); void EmitAssignment(Expression* expr);
......
...@@ -223,6 +223,22 @@ void FullCodeGenerator::EmitReturnSequence() { ...@@ -223,6 +223,22 @@ void FullCodeGenerator::EmitReturnSequence() {
} }
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) { void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
switch (context) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
...@@ -1152,10 +1168,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1152,10 +1168,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
LhsKind assign_type = VARIABLE; LhsKind assign_type = VARIABLE;
Property* prop = expr->target()->AsProperty(); Property* property = expr->target()->AsProperty();
if (prop != NULL) { if (property != NULL) {
assign_type = assign_type = (property->key()->IsPropertyName())
(prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; ? NAMED_PROPERTY
: KEYED_PROPERTY;
} }
// Evaluate LHS expression. // Evaluate LHS expression.
...@@ -1166,60 +1183,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1166,60 +1183,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
case NAMED_PROPERTY: case NAMED_PROPERTY:
if (expr->is_compound()) { if (expr->is_compound()) {
// We need the receiver both on the stack and in the accumulator. // We need the receiver both on the stack and in the accumulator.
VisitForValue(prop->obj(), kAccumulator); VisitForValue(property->obj(), kAccumulator);
__ push(result_register()); __ push(result_register());
} else { } else {
VisitForValue(prop->obj(), kStack); VisitForValue(property->obj(), kStack);
} }
break; break;
case KEYED_PROPERTY: case KEYED_PROPERTY:
if (expr->is_compound()) { if (expr->is_compound()) {
VisitForValue(prop->obj(), kStack); VisitForValue(property->obj(), kStack);
VisitForValue(prop->key(), kAccumulator); VisitForValue(property->key(), kAccumulator);
__ mov(edx, Operand(esp, 0)); __ mov(edx, Operand(esp, 0));
__ push(eax); __ push(eax);
} else { } else {
VisitForValue(prop->obj(), kStack); VisitForValue(property->obj(), kStack);
VisitForValue(prop->key(), kStack); VisitForValue(property->key(), kStack);
} }
break; break;
} }
// If we have a compound assignment: Get value of LHS expression and
// store in on top of the stack.
if (expr->is_compound()) { if (expr->is_compound()) {
Location saved_location = location_; Location saved_location = location_;
location_ = kStack; location_ = kAccumulator;
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var(), EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
Expression::kValue); Expression::kValue);
break; break;
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyLoad(prop); EmitNamedPropertyLoad(property);
__ push(result_register());
break; break;
case KEYED_PROPERTY: case KEYED_PROPERTY:
EmitKeyedPropertyLoad(prop); EmitKeyedPropertyLoad(property);
__ push(result_register());
break; break;
} }
location_ = saved_location;
}
// Evaluate RHS expression. Token::Value op = expr->binary_op();
Expression* rhs = expr->value(); ConstantOperand constant = ShouldInlineSmiCase(op)
VisitForValue(rhs, kAccumulator); ? 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() OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
? OVERWRITE_RIGHT ? OVERWRITE_RIGHT
: NO_OVERWRITE; : 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; location_ = saved_location;
} else {
VisitForValue(expr->value(), kAccumulator);
} }
// Record source position before possible IC call. // Record source position before possible IC call.
...@@ -1260,6 +1287,313 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { ...@@ -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, void FullCodeGenerator::EmitBinaryOp(Token::Value op,
Expression::Context context, Expression::Context context,
OverwriteMode mode) { OverwriteMode mode) {
......
...@@ -248,6 +248,10 @@ class Token { ...@@ -248,6 +248,10 @@ class Token {
return op == INC || op == DEC; return op == INC || op == DEC;
} }
static bool IsShiftOp(Value op) {
return (SHL <= op) && (op <= SHR);
}
// Returns a string corresponding to the JS token string // Returns a string corresponding to the JS token string
// (.e., "<" for the token LT) or NULL if the token doesn't // (.e., "<" for the token LT) or NULL if the token doesn't
// have a (unique) string (e.g. an IDENTIFIER). // have a (unique) string (e.g. an IDENTIFIER).
......
...@@ -230,6 +230,13 @@ void FullCodeGenerator::EmitReturnSequence() { ...@@ -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) { void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
switch (context) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
...@@ -1156,10 +1163,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1156,10 +1163,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
LhsKind assign_type = VARIABLE; LhsKind assign_type = VARIABLE;
Property* prop = expr->target()->AsProperty(); Property* property = expr->target()->AsProperty();
if (prop != NULL) { if (property != NULL) {
assign_type = assign_type = (property->key()->IsPropertyName())
(prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; ? NAMED_PROPERTY
: KEYED_PROPERTY;
} }
// Evaluate LHS expression. // Evaluate LHS expression.
...@@ -1170,60 +1178,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1170,60 +1178,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
case NAMED_PROPERTY: case NAMED_PROPERTY:
if (expr->is_compound()) { if (expr->is_compound()) {
// We need the receiver both on the stack and in the accumulator. // We need the receiver both on the stack and in the accumulator.
VisitForValue(prop->obj(), kAccumulator); VisitForValue(property->obj(), kAccumulator);
__ push(result_register()); __ push(result_register());
} else { } else {
VisitForValue(prop->obj(), kStack); VisitForValue(property->obj(), kStack);
} }
break; break;
case KEYED_PROPERTY: case KEYED_PROPERTY:
if (expr->is_compound()) { if (expr->is_compound()) {
VisitForValue(prop->obj(), kStack); VisitForValue(property->obj(), kStack);
VisitForValue(prop->key(), kAccumulator); VisitForValue(property->key(), kAccumulator);
__ movq(rdx, Operand(rsp, 0)); __ movq(rdx, Operand(rsp, 0));
__ push(rax); __ push(rax);
} else { } else {
VisitForValue(prop->obj(), kStack); VisitForValue(property->obj(), kStack);
VisitForValue(prop->key(), kStack); VisitForValue(property->key(), kStack);
} }
break; break;
} }
// If we have a compound assignment: Get value of LHS expression and
// store in on top of the stack.
if (expr->is_compound()) { if (expr->is_compound()) {
Location saved_location = location_; Location saved_location = location_;
location_ = kStack; location_ = kAccumulator;
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var(), EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
Expression::kValue); Expression::kValue);
break; break;
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyLoad(prop); EmitNamedPropertyLoad(property);
__ push(result_register());
break; break;
case KEYED_PROPERTY: case KEYED_PROPERTY:
EmitKeyedPropertyLoad(prop); EmitKeyedPropertyLoad(property);
__ push(result_register());
break; break;
} }
location_ = saved_location;
}
// Evaluate RHS expression. Token::Value op = expr->binary_op();
Expression* rhs = expr->value(); ConstantOperand constant = ShouldInlineSmiCase(op)
VisitForValue(rhs, kAccumulator); ? 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() OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
? OVERWRITE_RIGHT ? OVERWRITE_RIGHT
: NO_OVERWRITE; : 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; location_ = saved_location;
} else {
VisitForValue(expr->value(), kAccumulator);
} }
// Record source position before possible IC call. // Record source position before possible IC call.
...@@ -1264,6 +1282,74 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { ...@@ -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, void FullCodeGenerator::EmitBinaryOp(Token::Value op,
Expression::Context context, Expression::Context context,
OverwriteMode mode) { OverwriteMode mode) {
...@@ -1971,8 +2057,8 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { ...@@ -1971,8 +2057,8 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1); ASSERT(args->length() == 1);
// ArgumentsAccessStub expects the key in edx and the formal // ArgumentsAccessStub expects the key in rdx and the formal
// parameter count in eax. // parameter count in rax.
VisitForValue(args->at(0), kAccumulator); VisitForValue(args->at(0), kAccumulator);
__ movq(rdx, rax); __ movq(rdx, rax);
__ Move(rax, Smi::FromInt(scope()->num_parameters())); __ Move(rax, Smi::FromInt(scope()->num_parameters()));
...@@ -2176,7 +2262,7 @@ void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { ...@@ -2176,7 +2262,7 @@ void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
VisitForValue(args->at(0), kStack); // Load the object. VisitForValue(args->at(0), kStack); // Load the object.
VisitForValue(args->at(1), kAccumulator); // Load the value. VisitForValue(args->at(1), kAccumulator); // Load the value.
__ pop(rbx); // rax = value. ebx = object. __ pop(rbx); // rax = value. rbx = object.
Label done; Label done;
// If the object is a smi, return the value. // If the object is a smi, return the value.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment