Revision: 5351
Author: [email protected]
Date: Thu Aug 26 01:50:38 2010
Log: 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
http://code.google.com/p/v8/source/detail?r=5351
Modified:
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/ast.h
/branches/bleeding_edge/src/full-codegen.cc
/branches/bleeding_edge/src/full-codegen.h
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/token.h
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Wed Aug 25 07:22:03
2010
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Thu Aug 26 01:50:38
2010
@@ -244,6 +244,13 @@
#endif
}
}
+
+
+FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
+ Token::Value op, Expression* left, Expression* right) {
+ ASSERT(ShouldInlineSmiCase(op));
+ return kNoConstants;
+}
void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
@@ -1144,10 +1151,11 @@
// 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 @@
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);
-
- // If we have a compound assignment: Apply operator.
- if (expr->is_compound()) {
- Location saved_location = location_;
- location_ = 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);
+ }
+
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.
@@ -1251,6 +1268,18 @@
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
}
+
+
+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,
=======================================
--- /branches/bleeding_edge/src/ast.h Wed Aug 25 04:10:05 2010
+++ /branches/bleeding_edge/src/ast.h Thu Aug 26 01:50:38 2010
@@ -204,6 +204,9 @@
// True iff the result can be safely overwritten (to avoid allocation).
// 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 @@
virtual void Accept(AstVisitor* v);
virtual bool IsTrivial() { return true; }
+ virtual bool IsSmiLiteral() { return handle_->IsSmi(); }
// Type testing & conversion.
virtual Literal* AsLiteral() { return this; }
=======================================
--- /branches/bleeding_edge/src/full-codegen.cc Wed Aug 25 07:22:03 2010
+++ /branches/bleeding_edge/src/full-codegen.cc Thu Aug 26 01:50:38 2010
@@ -516,18 +516,21 @@
void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation");
-
- OverwriteMode overwrite_mode = NO_OVERWRITE;
- if (expr->left()->ResultOverwriteAllowed()) {
- overwrite_mode = OVERWRITE_LEFT;
- } else if (expr->right()->ResultOverwriteAllowed()) {
- overwrite_mode = OVERWRITE_RIGHT;
+ Token::Value op = expr->op();
+ Expression* left = expr->left();
+ Expression* right = expr->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 @@
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();
=======================================
--- /branches/bleeding_edge/src/full-codegen.h Wed Aug 25 04:10:05 2010
+++ /branches/bleeding_edge/src/full-codegen.h Thu Aug 26 01:50:38 2010
@@ -237,6 +237,12 @@
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 @@
// 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 @@
void EmitCallWithIC(Call* expr, Handle<Object> 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 @@
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);
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Wed Aug 25
07:22:03 2010
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Thu Aug 26
01:50:38 2010
@@ -217,10 +217,26 @@
// 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) {
@@ -1152,10 +1168,11 @@
// 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 @@
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);
-
- // If we have a compound assignment: Apply operator.
- if (expr->is_compound()) {
- Location saved_location = location_;
- location_ = 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);
+ }
+
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.
@@ -1258,6 +1285,313 @@
__ call(ic, RelocInfo::CODE_TARGET);
__ nop();
}
+
+
+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,
=======================================
--- /branches/bleeding_edge/src/token.h Fri Aug 6 01:03:44 2010
+++ /branches/bleeding_edge/src/token.h Thu Aug 26 01:50:38 2010
@@ -247,6 +247,10 @@
static bool IsCountOp(Value op) {
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
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Wed Aug 25 07:22:03
2010
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Thu Aug 26 01:50:38
2010
@@ -228,6 +228,13 @@
#endif
}
}
+
+
+FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
+ Token::Value op, Expression* left, Expression* right) {
+ ASSERT(ShouldInlineSmiCase(op));
+ return kNoConstants;
+}
void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
@@ -1156,10 +1163,11 @@
// 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 @@
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);
-
- // If we have a compound assignment: Apply operator.
- if (expr->is_compound()) {
- Location saved_location = location_;
- location_ = 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);
+ }
+
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.
@@ -1262,6 +1280,74 @@
__ Call(ic, RelocInfo::CODE_TARGET);
__ nop();
}
+
+
+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,
@@ -1971,8 +2057,8 @@
void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* 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 @@
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.
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev