diff --git a/src/ast.cc b/src/ast.cc index 7d26cd92ce..9204a840c8 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -172,6 +172,72 @@ void TargetCollector::AddTarget(BreakTarget* target) { } +bool Expression::GuaranteedSmiResult() { + BinaryOperation* node = AsBinaryOperation(); + if (node == NULL) return false; + Token::Value op = node->op(); + switch (op) { + case Token::COMMA: + case Token::OR: + case Token::AND: + case Token::ADD: + case Token::SUB: + case Token::MUL: + case Token::DIV: + case Token::MOD: + case Token::BIT_XOR: + case Token::SHL: + return false; + break; + case Token::BIT_OR: + case Token::BIT_AND: { + Literal* left = node->left()->AsLiteral(); + Literal* right = node->right()->AsLiteral(); + if (left != NULL && left->handle()->IsSmi()) { + int value = Smi::cast(*left->handle())->value(); + if (op == Token::BIT_OR && ((value & 0xc0000000) == 0xc0000000)) { + // Result of bitwise or is always a negative Smi. + return true; + } + if (op == Token::BIT_AND && ((value & 0xc0000000) == 0)) { + // Result of bitwise and is always a positive Smi. + return true; + } + } + if (right != NULL && right->handle()->IsSmi()) { + int value = Smi::cast(*right->handle())->value(); + if (op == Token::BIT_OR && ((value & 0xc0000000) == 0xc0000000)) { + // Result of bitwise or is always a negative Smi. + return true; + } + if (op == Token::BIT_AND && ((value & 0xc0000000) == 0)) { + // Result of bitwise and is always a positive Smi. + return true; + } + } + return false; + break; + } + case Token::SAR: + case Token::SHR: { + Literal* right = node->right()->AsLiteral(); + if (right != NULL && right->handle()->IsSmi()) { + int value = Smi::cast(*right->handle())->value(); + if ((value & 0x1F) > 1 || + (op == Token::SAR && (value & 0x1F) == 1)) { + return true; + } + } + return false; + break; + } + default: + UNREACHABLE(); + break; + } + return false; +} + // ---------------------------------------------------------------------------- // Implementation of AstVisitor diff --git a/src/ast.h b/src/ast.h index d153f98a6a..fa85eee6fd 100644 --- a/src/ast.h +++ b/src/ast.h @@ -255,6 +255,10 @@ class Expression: public AstNode { LoopConditionField::encode(flag); } + // The value of the expression is guaranteed to be a smi, because the + // top operation is a bit operation with a mask, or a shift. + bool GuaranteedSmiResult(); + // AST analysis results // True if the expression rooted at this node can be compiled by the diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 1181e22b86..d88c6105fe 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -490,7 +490,11 @@ void CodeGenerator::LoadInSafeInt32Mode(Expression* expr, Load(expr); Result value = frame_->Pop(); ASSERT(frame_->HasNoUntaggedInt32Elements()); - ConvertInt32ResultToNumber(&value); + if (expr->GuaranteedSmiResult()) { + ConvertInt32ResultToSmi(&value); + } else { + ConvertInt32ResultToNumber(&value); + } set_in_safe_int32_mode(false); set_unsafe_bailout(NULL); frame_->Push(&value); @@ -504,6 +508,19 @@ void CodeGenerator::LoadWithSafeInt32ModeDisabled(Expression* expr) { } +void CodeGenerator::ConvertInt32ResultToSmi(Result* value) { + ASSERT(value->is_untagged_int32()); + if (value->is_register()) { + __ add(value->reg(), Operand(value->reg())); + } else { + ASSERT(value->is_constant()); + ASSERT(value->handle()->IsSmi()); + } + value->set_untagged_int32(false); + value->set_number_info(NumberInfo::Smi()); +} + + void CodeGenerator::ConvertInt32ResultToNumber(Result* value) { ASSERT(value->is_untagged_int32()); if (value->is_register()) { @@ -552,6 +569,7 @@ void CodeGenerator::ConvertInt32ResultToNumber(Result* value) { ASSERT(value->is_constant()); } value->set_untagged_int32(false); + value->set_number_info(NumberInfo::Integer32()); } diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h index c4a077701a..ca4a44b85e 100644 --- a/src/ia32/codegen-ia32.h +++ b/src/ia32/codegen-ia32.h @@ -373,6 +373,7 @@ class CodeGenerator: public AstVisitor { // Take the Result that is an untagged int32, and convert it to a tagged // Smi or HeapNumber. Remove the untagged_int32 flag from the result. void ConvertInt32ResultToNumber(Result* value); + void ConvertInt32ResultToSmi(Result* value); // Track loop nesting level. int loop_nesting() const { return loop_nesting_; }