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
This commit is contained in:
kasperl@chromium.org 2010-08-26 08:50:38 +00:00
parent 7672338bc9
commit 6d5451d685
7 changed files with 629 additions and 99 deletions

View File

@ -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) {

View File

@ -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; }

View File

@ -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();

View File

@ -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<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 @@ 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);

View File

@ -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) {

View File

@ -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).

View File

@ -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<Expression*>* args) {
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 @@ void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* 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.