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:
parent
7672338bc9
commit
6d5451d685
@ -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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
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) {
|
||||
|
@ -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; }
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
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) {
|
||||
|
@ -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).
|
||||
|
@ -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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user