Chromium Code Reviews| Index: src/ia32/codegen-ia32.cc | 
| =================================================================== | 
| --- src/ia32/codegen-ia32.cc (revision 4025) | 
| +++ src/ia32/codegen-ia32.cc (working copy) | 
| @@ -733,7 +733,27 @@ | 
| Result value = frame_->Pop(); | 
| value.ToRegister(); | 
| - if (value.is_number()) { | 
| + if (value.is_integer32()) { // Also takes Smi case. | 
| + Comment cmnt(masm_, "ONLY_INTEGER_32"); | 
| + if (FLAG_debug_code) { | 
| + Label ok; | 
| + __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); | 
| + __ test(value.reg(), Immediate(kSmiTagMask)); | 
| + __ j(zero, &ok); | 
| + __ fldz(); | 
| + __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); | 
| + __ FCmp(); | 
| + __ j(not_zero, &ok); | 
| + __ Abort("Smi was wrapped in HeapNumber in output from bitop"); | 
| + __ bind(&ok); | 
| + } | 
| + // In the integer32 case there are no Smis hidden in heap numbers, so we | 
| + // need only test for Smi zero. | 
| + __ test(value.reg(), Operand(value.reg())); | 
| + dest->false_target()->Branch(zero); | 
| + value.Unuse(); | 
| + dest->Split(not_zero); | 
| + } else if (value.is_number()) { | 
| Comment cmnt(masm_, "ONLY_NUMBER"); | 
| // Fast case if NumberInfo indicates only numbers. | 
| if (FLAG_debug_code) { | 
| @@ -817,6 +837,7 @@ | 
| // Takes the operands in edx and eax and loads them as integers in eax | 
| // and ecx. | 
| static void LoadAsIntegers(MacroAssembler* masm, | 
| + NumberInfo number_info, | 
| bool use_sse3, | 
| Label* operand_conversion_failure); | 
| // Test if operands are smis or heap numbers and load them | 
| @@ -856,7 +877,7 @@ | 
| (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 
| args_in_registers_ ? "RegArgs" : "StackArgs", | 
| args_reversed_ ? "_R" : "", | 
| - NumberInfo::ToString(static_operands_type_), | 
| + static_operands_type_.ToString(), | 
| BinaryOpIC::GetName(runtime_operands_type_)); | 
| return name_; | 
| } | 
| @@ -869,8 +890,11 @@ | 
| Register dst, | 
| Register left, | 
| Register right, | 
| + NumberInfo left_info, | 
| + NumberInfo right_info, | 
| OverwriteMode mode) | 
| - : op_(op), dst_(dst), left_(left), right_(right), mode_(mode) { | 
| + : op_(op), dst_(dst), left_(left), right_(right), | 
| + left_info_(left_info), right_info_(right_info), mode_(mode) { | 
| set_comment("[ DeferredInlineBinaryOperation"); | 
| } | 
| @@ -881,6 +905,8 @@ | 
| Register dst_; | 
| Register left_; | 
| Register right_; | 
| + NumberInfo left_info_; | 
| + NumberInfo right_info_; | 
| OverwriteMode mode_; | 
| }; | 
| @@ -894,18 +920,22 @@ | 
| CpuFeatures::Scope use_sse2(SSE2); | 
| Label call_runtime, after_alloc_failure; | 
| Label left_smi, right_smi, load_right, do_op; | 
| - __ test(left_, Immediate(kSmiTagMask)); | 
| - __ j(zero, &left_smi); | 
| - __ cmp(FieldOperand(left_, HeapObject::kMapOffset), | 
| - Factory::heap_number_map()); | 
| - __ j(not_equal, &call_runtime); | 
| - __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset)); | 
| - if (mode_ == OVERWRITE_LEFT) { | 
| - __ mov(dst_, left_); | 
| + if (!left_info_.IsSmi()) { | 
| + __ test(left_, Immediate(kSmiTagMask)); | 
| + __ j(zero, &left_smi); | 
| + if (!left_info_.IsNumber()) { | 
| + __ cmp(FieldOperand(left_, HeapObject::kMapOffset), | 
| + Factory::heap_number_map()); | 
| + __ j(not_equal, &call_runtime); | 
| + } | 
| + __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset)); | 
| + if (mode_ == OVERWRITE_LEFT) { | 
| + __ mov(dst_, left_); | 
| + } | 
| + __ jmp(&load_right); | 
| + | 
| + __ bind(&left_smi); | 
| } | 
| - __ jmp(&load_right); | 
| - | 
| - __ bind(&left_smi); | 
| __ SmiUntag(left_); | 
| __ cvtsi2sd(xmm0, Operand(left_)); | 
| __ SmiTag(left_); | 
| @@ -917,23 +947,27 @@ | 
| } | 
| __ bind(&load_right); | 
| - __ test(right_, Immediate(kSmiTagMask)); | 
| - __ j(zero, &right_smi); | 
| - __ cmp(FieldOperand(right_, HeapObject::kMapOffset), | 
| - Factory::heap_number_map()); | 
| - __ j(not_equal, &call_runtime); | 
| - __ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset)); | 
| - if (mode_ == OVERWRITE_RIGHT) { | 
| - __ mov(dst_, right_); | 
| - } else if (mode_ == NO_OVERWRITE) { | 
| - Label alloc_failure; | 
| - __ push(left_); | 
| - __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 
| - __ pop(left_); | 
| + if (!right_info_.IsSmi()) { | 
| + __ test(right_, Immediate(kSmiTagMask)); | 
| + __ j(zero, &right_smi); | 
| + if (!right_info_.IsNumber()) { | 
| + __ cmp(FieldOperand(right_, HeapObject::kMapOffset), | 
| + Factory::heap_number_map()); | 
| + __ j(not_equal, &call_runtime); | 
| + } | 
| + __ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset)); | 
| + if (mode_ == OVERWRITE_RIGHT) { | 
| + __ mov(dst_, right_); | 
| + } else if (mode_ == NO_OVERWRITE) { | 
| + Label alloc_failure; | 
| + __ push(left_); | 
| + __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 
| + __ pop(left_); | 
| + } | 
| + __ jmp(&do_op); | 
| + | 
| + __ bind(&right_smi); | 
| } | 
| - __ jmp(&do_op); | 
| - | 
| - __ bind(&right_smi); | 
| __ SmiUntag(right_); | 
| __ cvtsi2sd(xmm1, Operand(right_)); | 
| __ SmiTag(right_); | 
| @@ -959,13 +993,104 @@ | 
| __ pop(left_); | 
| __ bind(&call_runtime); | 
| } | 
| - GenericBinaryOpStub stub(op_, mode_, NO_SMI_CODE_IN_STUB); | 
| + GenericBinaryOpStub stub(op_, | 
| + mode_, | 
| + NO_SMI_CODE_IN_STUB, | 
| + NumberInfo::Combine(left_info_, right_info_)); | 
| stub.GenerateCall(masm_, left_, right_); | 
| if (!dst_.is(eax)) __ mov(dst_, eax); | 
| __ bind(&done); | 
| } | 
| +static NumberInfo CalculateNumberInfo(NumberInfo operands_type, | 
| + Token::Value op, | 
| + const Result& right, | 
| + const Result& left) { | 
| + // Set NumberInfo of result according to the operation performed. | 
| + // Rely on the fact that smis have a 31 bit payload on ia32. | 
| + ASSERT(kSmiValueSize == 31); | 
| + switch (op) { | 
| + case Token::COMMA: | 
| + return right.number_info(); | 
| + case Token::OR: | 
| + case Token::AND: | 
| + // Result type can be either of the two input types. | 
| + return operands_type; | 
| + case Token::BIT_AND: { | 
| + // Anding with positive Smis will give you a Smi. | 
| + if (right.is_constant() && right.handle()->IsSmi() && | 
| + Smi::cast(*right.handle())->value() >= 0) { | 
| + return NumberInfo::Smi(); | 
| + } else if (left.is_constant() && left.handle()->IsSmi() && | 
| + Smi::cast(*left.handle())->value() >= 0) { | 
| + return NumberInfo::Smi(); | 
| + } | 
| + return (operands_type.IsSmi()) | 
| + ? NumberInfo::Smi() | 
| + : NumberInfo::Integer32(); | 
| + } | 
| + case Token::BIT_OR: { | 
| + // Oring with negative Smis will give you a Smi. | 
| + if (right.is_constant() && right.handle()->IsSmi() && | 
| + Smi::cast(*right.handle())->value() < 0) { | 
| + return NumberInfo::Smi(); | 
| + } else if (left.is_constant() && left.handle()->IsSmi() && | 
| + Smi::cast(*left.handle())->value() < 0) { | 
| + return NumberInfo::Smi(); | 
| + } | 
| + return (operands_type.IsSmi()) | 
| + ? NumberInfo::Smi() | 
| + : NumberInfo::Integer32(); | 
| + } | 
| + case Token::BIT_XOR: | 
| + // Result is always a number. Smi property of inputs is preserved. | 
| 
 
fschneider
2010/03/05 15:01:07
// Result is always a integer32.
 
 | 
| + return (operands_type.IsSmi()) | 
| + ? NumberInfo::Smi() | 
| + : NumberInfo::Integer32(); | 
| + case Token::SAR: | 
| + if (left.is_smi()) return NumberInfo::Smi(); | 
| + // Result is a smi if we shift by a constant >= 1, otherwise a number. | 
| 
 
fschneider
2010/03/05 15:01:07
number --> integer32
 
 | 
| + return (right.is_constant() && right.handle()->IsSmi() | 
| + && Smi::cast(*right.handle())->value() >= 1) | 
| + ? NumberInfo::Smi() | 
| + : NumberInfo::Integer32(); | 
| + case Token::SHR: | 
| + // Result is a smi if we shift by a constant >= 2, otherwise a number. | 
| 
 
fschneider
2010/03/05 15:01:07
number --> integer32
 
 | 
| + return (right.is_constant() && right.handle()->IsSmi() | 
| + && Smi::cast(*right.handle())->value() >= 2) | 
| + ? NumberInfo::Smi() | 
| + : NumberInfo::Integer32(); | 
| + case Token::ADD: | 
| + if (operands_type.IsSmi()) { | 
| + // The Integer32 range is big enough to take the sum of any two Smis. | 
| + return NumberInfo::Integer32(); | 
| + } else { | 
| + // Result could be a string or a number. Check types of inputs. | 
| + return operands_type.IsNumber() | 
| + ? NumberInfo::Number() | 
| + : NumberInfo::Unknown(); | 
| + } | 
| + case Token::SHL: | 
| + return NumberInfo::Integer32(); | 
| + case Token::SUB: | 
| + // The Integer32 range is big enough to take the difference of any two Smis. | 
| 
 
fschneider
2010/03/05 15:01:07
long line
 
 | 
| + return (operands_type.IsSmi()) ? | 
| + NumberInfo::Integer32() : | 
| + NumberInfo::Number(); | 
| + case Token::MUL: | 
| + case Token::DIV: | 
| + case Token::MOD: | 
| + // Result is always a number. | 
| + return NumberInfo::Number(); | 
| + default: | 
| + UNREACHABLE(); | 
| + } | 
| + UNREACHABLE(); | 
| + return NumberInfo::Unknown(); | 
| +} | 
| + | 
| + | 
| void CodeGenerator::GenericBinaryOperation(Token::Value op, | 
| StaticType* type, | 
| OverwriteMode overwrite_mode) { | 
| @@ -1021,9 +1146,11 @@ | 
| } | 
| // Get number type of left and right sub-expressions. | 
| - NumberInfo::Type operands_type = | 
| + NumberInfo operands_type = | 
| NumberInfo::Combine(left.number_info(), right.number_info()); | 
| + NumberInfo result_type = CalculateNumberInfo(operands_type, op, right, left); | 
| + | 
| Result answer; | 
| if (left_is_non_smi_constant || right_is_non_smi_constant) { | 
| // Go straight to the slow case, with no smi code. | 
| @@ -1044,7 +1171,10 @@ | 
| // generate the inline Smi check code if this operation is part of a loop. | 
| // For all other operations only inline the Smi check code for likely smis | 
| // if the operation is part of a loop. | 
| - if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) { | 
| + if (loop_nesting() > 0 && | 
| + (Token::IsBitOp(op) || | 
| + operands_type.IsInteger32() || | 
| + type->IsLikelySmi())) { | 
| answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); | 
| } else { | 
| GenericBinaryOpStub stub(op, | 
| @@ -1055,58 +1185,6 @@ | 
| } | 
| } | 
| - // Set NumberInfo of result according to the operation performed. | 
| - // Rely on the fact that smis have a 31 bit payload on ia32. | 
| - ASSERT(kSmiValueSize == 31); | 
| - NumberInfo::Type result_type = NumberInfo::kUnknown; | 
| - switch (op) { | 
| - case Token::COMMA: | 
| - result_type = right.number_info(); | 
| - break; | 
| - case Token::OR: | 
| - case Token::AND: | 
| - // Result type can be either of the two input types. | 
| - result_type = operands_type; | 
| - break; | 
| - case Token::BIT_OR: | 
| - case Token::BIT_XOR: | 
| - case Token::BIT_AND: | 
| - // Result is always a number. Smi property of inputs is preserved. | 
| - result_type = (operands_type == NumberInfo::kSmi) | 
| - ? NumberInfo::kSmi | 
| - : NumberInfo::kNumber; | 
| - break; | 
| - case Token::SAR: | 
| - // Result is a smi if we shift by a constant >= 1, otherwise a number. | 
| - result_type = (right.is_constant() && right.handle()->IsSmi() | 
| - && Smi::cast(*right.handle())->value() >= 1) | 
| - ? NumberInfo::kSmi | 
| - : NumberInfo::kNumber; | 
| - break; | 
| - case Token::SHR: | 
| - // Result is a smi if we shift by a constant >= 2, otherwise a number. | 
| - result_type = (right.is_constant() && right.handle()->IsSmi() | 
| - && Smi::cast(*right.handle())->value() >= 2) | 
| - ? NumberInfo::kSmi | 
| - : NumberInfo::kNumber; | 
| - break; | 
| - case Token::ADD: | 
| - // Result could be a string or a number. Check types of inputs. | 
| - result_type = NumberInfo::IsNumber(operands_type) | 
| - ? NumberInfo::kNumber | 
| - : NumberInfo::kUnknown; | 
| - break; | 
| - case Token::SHL: | 
| - case Token::SUB: | 
| - case Token::MUL: | 
| - case Token::DIV: | 
| - case Token::MOD: | 
| - // Result is always a number. | 
| - result_type = NumberInfo::kNumber; | 
| - break; | 
| - default: | 
| - UNREACHABLE(); | 
| - } | 
| answer.set_number_info(result_type); | 
| frame_->Push(&answer); | 
| } | 
| @@ -1193,6 +1271,12 @@ | 
| } | 
| +static void CheckTwoForSminess(MacroAssembler* masm, | 
| + Register left, Register right, Register scratch, | 
| + NumberInfo left_info, NumberInfo right_info, | 
| + DeferredInlineBinaryOperation* deferred); | 
| + | 
| + | 
| // Implements a binary operation using a deferred code object and some | 
| // inline code to operate on smis quickly. | 
| Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, | 
| @@ -1273,6 +1357,8 @@ | 
| (op == Token::DIV) ? eax : edx, | 
| left->reg(), | 
| right->reg(), | 
| + left->number_info(), | 
| + right->number_info(), | 
| overwrite_mode); | 
| if (left->reg().is(right->reg())) { | 
| __ test(left->reg(), Immediate(kSmiTagMask)); | 
| @@ -1370,11 +1456,11 @@ | 
| answer.reg(), | 
| left->reg(), | 
| ecx, | 
| + left->number_info(), | 
| + right->number_info(), | 
| overwrite_mode); | 
| - __ mov(answer.reg(), left->reg()); | 
| - __ or_(answer.reg(), Operand(ecx)); | 
| - __ test(answer.reg(), Immediate(kSmiTagMask)); | 
| - deferred->Branch(not_zero); | 
| + CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), | 
| + left->number_info(), right->number_info(), deferred); | 
| // Untag both operands. | 
| __ mov(answer.reg(), left->reg()); | 
| @@ -1444,16 +1530,12 @@ | 
| answer.reg(), | 
| left->reg(), | 
| right->reg(), | 
| + left->number_info(), | 
| + right->number_info(), | 
| overwrite_mode); | 
| - if (left->reg().is(right->reg())) { | 
| - __ test(left->reg(), Immediate(kSmiTagMask)); | 
| - } else { | 
| - __ mov(answer.reg(), left->reg()); | 
| - __ or_(answer.reg(), Operand(right->reg())); | 
| - ASSERT(kSmiTag == 0); // Adjust test if not the case. | 
| - __ test(answer.reg(), Immediate(kSmiTagMask)); | 
| - } | 
| - deferred->Branch(not_zero); | 
| + CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), | 
| + left->number_info(), right->number_info(), deferred); | 
| + | 
| __ mov(answer.reg(), left->reg()); | 
| switch (op) { | 
| case Token::ADD: | 
| @@ -1522,13 +1604,16 @@ | 
| DeferredInlineSmiOperation(Token::Value op, | 
| Register dst, | 
| Register src, | 
| + NumberInfo number_info, | 
| Smi* value, | 
| OverwriteMode overwrite_mode) | 
| : op_(op), | 
| dst_(dst), | 
| src_(src), | 
| + number_info_(number_info), | 
| value_(value), | 
| overwrite_mode_(overwrite_mode) { | 
| + if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE; | 
| set_comment("[ DeferredInlineSmiOperation"); | 
| } | 
| @@ -1538,6 +1623,7 @@ | 
| Token::Value op_; | 
| Register dst_; | 
| Register src_; | 
| + NumberInfo number_info_; | 
| Smi* value_; | 
| OverwriteMode overwrite_mode_; | 
| }; | 
| @@ -1548,7 +1634,8 @@ | 
| GenericBinaryOpStub stub( | 
| op_, | 
| overwrite_mode_, | 
| - (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB); | 
| + (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB, | 
| + NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | 
| stub.GenerateCall(masm_, src_, value_); | 
| if (!dst_.is(eax)) __ mov(dst_, eax); | 
| } | 
| @@ -1562,9 +1649,11 @@ | 
| Register dst, | 
| Smi* value, | 
| Register src, | 
| + NumberInfo number_info, | 
| OverwriteMode overwrite_mode) | 
| : op_(op), | 
| dst_(dst), | 
| + number_info_(number_info), | 
| value_(value), | 
| src_(src), | 
| overwrite_mode_(overwrite_mode) { | 
| @@ -1576,6 +1665,7 @@ | 
| private: | 
| Token::Value op_; | 
| Register dst_; | 
| + NumberInfo number_info_; | 
| Smi* value_; | 
| Register src_; | 
| OverwriteMode overwrite_mode_; | 
| @@ -1583,7 +1673,11 @@ | 
| void DeferredInlineSmiOperationReversed::Generate() { | 
| - GenericBinaryOpStub igostub(op_, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 
| + GenericBinaryOpStub igostub( | 
| + op_, | 
| + overwrite_mode_, | 
| + NO_SMI_CODE_IN_STUB, | 
| + NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | 
| igostub.GenerateCall(masm_, value_, src_); | 
| if (!dst_.is(eax)) __ mov(dst_, eax); | 
| } | 
| @@ -1595,9 +1689,14 @@ | 
| class DeferredInlineSmiAdd: public DeferredCode { | 
| public: | 
| DeferredInlineSmiAdd(Register dst, | 
| + NumberInfo number_info, | 
| Smi* value, | 
| OverwriteMode overwrite_mode) | 
| - : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { | 
| + : dst_(dst), | 
| + number_info_(number_info), | 
| + value_(value), | 
| + overwrite_mode_(overwrite_mode) { | 
| + if (number_info_.IsSmi()) overwrite_mode_ = NO_OVERWRITE; | 
| set_comment("[ DeferredInlineSmiAdd"); | 
| } | 
| @@ -1605,6 +1704,7 @@ | 
| private: | 
| Register dst_; | 
| + NumberInfo number_info_; | 
| Smi* value_; | 
| OverwriteMode overwrite_mode_; | 
| }; | 
| @@ -1613,7 +1713,11 @@ | 
| void DeferredInlineSmiAdd::Generate() { | 
| // Undo the optimistic add operation and call the shared stub. | 
| __ sub(Operand(dst_), Immediate(value_)); | 
| - GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 
| + GenericBinaryOpStub igostub( | 
| + Token::ADD, | 
| + overwrite_mode_, | 
| + NO_SMI_CODE_IN_STUB, | 
| + NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | 
| igostub.GenerateCall(masm_, dst_, value_); | 
| if (!dst_.is(eax)) __ mov(dst_, eax); | 
| } | 
| @@ -1625,9 +1729,13 @@ | 
| class DeferredInlineSmiAddReversed: public DeferredCode { | 
| public: | 
| DeferredInlineSmiAddReversed(Register dst, | 
| + NumberInfo number_info, | 
| Smi* value, | 
| OverwriteMode overwrite_mode) | 
| - : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { | 
| + : dst_(dst), | 
| + number_info_(number_info), | 
| + value_(value), | 
| + overwrite_mode_(overwrite_mode) { | 
| set_comment("[ DeferredInlineSmiAddReversed"); | 
| } | 
| @@ -1635,6 +1743,7 @@ | 
| private: | 
| Register dst_; | 
| + NumberInfo number_info_; | 
| Smi* value_; | 
| OverwriteMode overwrite_mode_; | 
| }; | 
| @@ -1643,7 +1752,10 @@ | 
| void DeferredInlineSmiAddReversed::Generate() { | 
| // Undo the optimistic add operation and call the shared stub. | 
| __ sub(Operand(dst_), Immediate(value_)); | 
| - GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 
| + GenericBinaryOpStub igostub(Token::ADD, | 
| + overwrite_mode_, | 
| + NO_SMI_CODE_IN_STUB, | 
| + NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | 
| igostub.GenerateCall(masm_, value_, dst_); | 
| if (!dst_.is(eax)) __ mov(dst_, eax); | 
| } | 
| @@ -1656,9 +1768,14 @@ | 
| class DeferredInlineSmiSub: public DeferredCode { | 
| public: | 
| DeferredInlineSmiSub(Register dst, | 
| + NumberInfo number_info, | 
| Smi* value, | 
| OverwriteMode overwrite_mode) | 
| - : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { | 
| + : dst_(dst), | 
| + number_info_(number_info), | 
| + value_(value), | 
| + overwrite_mode_(overwrite_mode) { | 
| + if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE; | 
| set_comment("[ DeferredInlineSmiSub"); | 
| } | 
| @@ -1666,6 +1783,7 @@ | 
| private: | 
| Register dst_; | 
| + NumberInfo number_info_; | 
| Smi* value_; | 
| OverwriteMode overwrite_mode_; | 
| }; | 
| @@ -1674,7 +1792,10 @@ | 
| void DeferredInlineSmiSub::Generate() { | 
| // Undo the optimistic sub operation and call the shared stub. | 
| __ add(Operand(dst_), Immediate(value_)); | 
| - GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 
| + GenericBinaryOpStub igostub(Token::SUB, | 
| + overwrite_mode_, | 
| + NO_SMI_CODE_IN_STUB, | 
| + NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | 
| igostub.GenerateCall(masm_, dst_, value_); | 
| if (!dst_.is(eax)) __ mov(dst_, eax); | 
| } | 
| @@ -1718,17 +1839,21 @@ | 
| DeferredCode* deferred = NULL; | 
| if (reversed) { | 
| deferred = new DeferredInlineSmiAddReversed(operand->reg(), | 
| + operand->number_info(), | 
| smi_value, | 
| overwrite_mode); | 
| } else { | 
| deferred = new DeferredInlineSmiAdd(operand->reg(), | 
| + operand->number_info(), | 
| smi_value, | 
| overwrite_mode); | 
| } | 
| __ add(Operand(operand->reg()), Immediate(value)); | 
| deferred->Branch(overflow); | 
| - __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| - deferred->Branch(not_zero); | 
| + if (!operand->number_info().IsSmi()) { | 
| + __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| deferred->BindExit(); | 
| answer = *operand; | 
| break; | 
| @@ -1747,6 +1872,7 @@ | 
| answer.reg(), | 
| smi_value, | 
| operand->reg(), | 
| + operand->number_info(), | 
| 
 
fschneider
2010/03/05 15:01:07
long line?
 
 | 
| overwrite_mode); | 
| __ sub(answer.reg(), Operand(operand->reg())); | 
| } else { | 
| @@ -1754,13 +1880,16 @@ | 
| frame_->Spill(operand->reg()); | 
| answer = *operand; | 
| deferred = new DeferredInlineSmiSub(operand->reg(), | 
| + operand->number_info(), | 
| smi_value, | 
| overwrite_mode); | 
| __ sub(Operand(operand->reg()), Immediate(value)); | 
| } | 
| deferred->Branch(overflow); | 
| - __ test(answer.reg(), Immediate(kSmiTagMask)); | 
| - deferred->Branch(not_zero); | 
| + if (!operand->number_info().IsSmi()) { | 
| + __ test(answer.reg(), Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| deferred->BindExit(); | 
| operand->Unuse(); | 
| break; | 
| @@ -1781,10 +1910,13 @@ | 
| new DeferredInlineSmiOperation(op, | 
| operand->reg(), | 
| operand->reg(), | 
| + operand->number_info(), | 
| 
 
fschneider
2010/03/05 15:01:07
You could avoid creating the DeferredInlineSmiOper
 
 | 
| smi_value, | 
| overwrite_mode); | 
| - __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| - deferred->Branch(not_zero); | 
| + if (!operand->number_info().IsSmi()) { | 
| + __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| if (shift_value > 0) { | 
| __ sar(operand->reg(), shift_value); | 
| __ and_(operand->reg(), ~kSmiTagMask); | 
| @@ -1810,10 +1942,13 @@ | 
| new DeferredInlineSmiOperation(op, | 
| answer.reg(), | 
| operand->reg(), | 
| + operand->number_info(), | 
| smi_value, | 
| overwrite_mode); | 
| - __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| - deferred->Branch(not_zero); | 
| + if (!operand->number_info().IsSmi()) { | 
| + __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| __ mov(answer.reg(), operand->reg()); | 
| __ SmiUntag(answer.reg()); | 
| __ shr(answer.reg(), shift_value); | 
| @@ -1855,10 +1990,13 @@ | 
| answer.reg(), | 
| smi_value, | 
| right.reg(), | 
| + right.number_info(), | 
| overwrite_mode); | 
| __ mov(answer.reg(), Immediate(int_value)); | 
| __ sar(ecx, kSmiTagSize); | 
| - deferred->Branch(carry); | 
| + if (!right.number_info().IsSmi()) { | 
| + deferred->Branch(carry); | 
| + } | 
| __ shl_cl(answer.reg()); | 
| __ cmp(answer.reg(), 0xc0000000); | 
| deferred->Branch(sign); | 
| @@ -1877,10 +2015,13 @@ | 
| new DeferredInlineSmiOperation(op, | 
| operand->reg(), | 
| operand->reg(), | 
| + operand->number_info(), | 
| smi_value, | 
| overwrite_mode); | 
| - __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| - deferred->Branch(not_zero); | 
| + if (!operand->number_info().IsSmi()) { | 
| 
 
fschneider
2010/03/05 15:01:07
Also here only instantiate DeferredInlineSmiOperat
 
 | 
| + __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| deferred->BindExit(); | 
| answer = *operand; | 
| } else { | 
| @@ -1891,10 +2032,13 @@ | 
| new DeferredInlineSmiOperation(op, | 
| answer.reg(), | 
| operand->reg(), | 
| + operand->number_info(), | 
| smi_value, | 
| overwrite_mode); | 
| - __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| - deferred->Branch(not_zero); | 
| + if (!operand->number_info().IsSmi()) { | 
| + __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| __ mov(answer.reg(), operand->reg()); | 
| ASSERT(kSmiTag == 0); // adjust code if not the case | 
| // We do no shifts, only the Smi conversion, if shift_value is 1. | 
| @@ -1922,16 +2066,20 @@ | 
| operand->reg(), | 
| smi_value, | 
| operand->reg(), | 
| + operand->number_info(), | 
| 
 
fschneider
2010/03/05 15:01:07
long line.
 
 | 
| overwrite_mode); | 
| } else { | 
| deferred = new DeferredInlineSmiOperation(op, | 
| operand->reg(), | 
| operand->reg(), | 
| + operand->number_info(), | 
| smi_value, | 
| overwrite_mode); | 
| } | 
| - __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| - deferred->Branch(not_zero); | 
| + if (!operand->number_info().IsSmi()) { | 
| 
 
fschneider
2010/03/05 15:01:07
Also here only instantiate DeferredInlineSmiOperat
 
Erik Corry
2010/03/05 20:20:15
Actually instead I will remove the 'if' since shif
 
 | 
| + __ test(operand->reg(), Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| if (op == Token::BIT_AND) { | 
| __ and_(Operand(operand->reg()), Immediate(value)); | 
| } else if (op == Token::BIT_XOR) { | 
| @@ -1958,6 +2106,7 @@ | 
| new DeferredInlineSmiOperation(op, | 
| operand->reg(), | 
| operand->reg(), | 
| + operand->number_info(), | 
| smi_value, | 
| overwrite_mode); | 
| // Check that lowest log2(value) bits of operand are zero, and test | 
| @@ -1992,6 +2141,7 @@ | 
| DeferredCode* deferred = new DeferredInlineSmiOperation(op, | 
| operand->reg(), | 
| operand->reg(), | 
| + operand->number_info(), | 
| 
 
fschneider
2010/03/05 15:01:07
Long line.
 
 | 
| smi_value, | 
| overwrite_mode); | 
| // Check for negative or non-Smi left hand side. | 
| @@ -2027,6 +2177,8 @@ | 
| static bool CouldBeNaN(const Result& result) { | 
| + if (result.number_info().IsSmi()) return false; | 
| + if (result.number_info().IsInteger32()) return false; | 
| if (!result.is_constant()) return true; | 
| if (!result.handle()->IsHeapNumber()) return false; | 
| return isnan(HeapNumber::cast(*result.handle())->value()); | 
| @@ -7130,8 +7282,10 @@ | 
| deferred->Branch(not_equal); | 
| // Check that the key is a smi. | 
| - __ test(key.reg(), Immediate(kSmiTagMask)); | 
| - deferred->Branch(not_zero); | 
| + if (!key.is_smi()) { | 
| + __ test(key.reg(), Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| // Get the elements array from the receiver and check that it | 
| // is not a dictionary. | 
| @@ -7276,6 +7430,34 @@ | 
| #define __ ACCESS_MASM(masm) | 
| +static void CheckTwoForSminess(MacroAssembler* masm, | 
| + Register left, Register right, Register scratch, | 
| + NumberInfo left_info, NumberInfo right_info, | 
| + DeferredInlineBinaryOperation* deferred) { | 
| + if (left.is(right)) { | 
| + if (!left_info.IsSmi()) { | 
| + __ test(left, Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| + } else if (!left_info.IsSmi()) { | 
| + if (!right_info.IsSmi()) { | 
| + __ mov(scratch, left); | 
| + __ or_(scratch, Operand(right)); | 
| + __ test(scratch, Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } else { | 
| + __ test (left, Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| + } else { | 
| + if (!right_info.IsSmi()) { | 
| + __ test(right, Immediate(kSmiTagMask)); | 
| + deferred->Branch(not_zero); | 
| + } | 
| + } | 
| +} | 
| + | 
| + | 
| Handle<String> Reference::GetName() { | 
| ASSERT(type_ == NAMED); | 
| Property* property = expression_->AsProperty(); | 
| @@ -7776,6 +7958,22 @@ | 
| __ mov(left, Operand(esp, 2 * kPointerSize)); | 
| } | 
| + if (static_operands_type_.IsSmi()) { | 
| + if (op_ == Token::BIT_OR) { | 
| + __ or_(right, Operand(left)); | 
| + GenerateReturn(masm); | 
| + return; | 
| + } else if (op_ == Token::BIT_AND) { | 
| + __ and_(right, Operand(left)); | 
| + GenerateReturn(masm); | 
| + return; | 
| + } else if (op_ == Token::BIT_XOR) { | 
| + __ xor_(right, Operand(left)); | 
| + GenerateReturn(masm); | 
| + return; | 
| + } | 
| + } | 
| + | 
| // 2. Prepare the smi check of both operands by oring them together. | 
| Comment smi_check_comment(masm, "-- Smi check arguments"); | 
| Label not_smis; | 
| @@ -8112,7 +8310,7 @@ | 
| Label not_floats; | 
| if (CpuFeatures::IsSupported(SSE2)) { | 
| CpuFeatures::Scope use_sse2(SSE2); | 
| - if (NumberInfo::IsNumber(static_operands_type_)) { | 
| + if (static_operands_type_.IsNumber()) { | 
| if (FLAG_debug_code) { | 
| // Assert at runtime that inputs are only numbers. | 
| __ AbortIfNotNumber(edx, | 
| @@ -8120,7 +8318,11 @@ | 
| __ AbortIfNotNumber(eax, | 
| "GenericBinaryOpStub operand not a number."); | 
| } | 
| - FloatingPointHelper::LoadSSE2Operands(masm); | 
| + if (static_operands_type_.IsSmi()) { | 
| + FloatingPointHelper::LoadSSE2Smis(masm, ecx); | 
| + } else { | 
| + FloatingPointHelper::LoadSSE2Operands(masm); | 
| + } | 
| } else { | 
| FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); | 
| } | 
| @@ -8136,7 +8338,7 @@ | 
| __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 
| GenerateReturn(masm); | 
| } else { // SSE2 not available, use FPU. | 
| - if (NumberInfo::IsNumber(static_operands_type_)) { | 
| + if (static_operands_type_.IsNumber()) { | 
| if (FLAG_debug_code) { | 
| // Assert at runtime that inputs are only numbers. | 
| __ AbortIfNotNumber(edx, | 
| @@ -8190,7 +8392,10 @@ | 
| case Token::SHL: | 
| case Token::SHR: { | 
| Label non_smi_result; | 
| - FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); | 
| + FloatingPointHelper::LoadAsIntegers(masm, | 
| + static_operands_type_, | 
| + use_sse3_, | 
| + &call_runtime); | 
| switch (op_) { | 
| case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; | 
| case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; | 
| @@ -8719,24 +8924,29 @@ | 
| // trashed registers. | 
| void IntegerConvert(MacroAssembler* masm, | 
| Register source, | 
| + NumberInfo number_info, | 
| bool use_sse3, | 
| Label* conversion_failure) { | 
| ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); | 
| Label done, right_exponent, normal_exponent; | 
| Register scratch = ebx; | 
| Register scratch2 = edi; | 
| - // Get exponent word. | 
| - __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); | 
| - // Get exponent alone in scratch2. | 
| - __ mov(scratch2, scratch); | 
| - __ and_(scratch2, HeapNumber::kExponentMask); | 
| + if (!number_info.IsInteger32() || !use_sse3) { | 
| + // Get exponent word. | 
| + __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); | 
| + // Get exponent alone in scratch2. | 
| + __ mov(scratch2, scratch); | 
| + __ and_(scratch2, HeapNumber::kExponentMask); | 
| + } | 
| if (use_sse3) { | 
| CpuFeatures::Scope scope(SSE3); | 
| - // Check whether the exponent is too big for a 64 bit signed integer. | 
| - static const uint32_t kTooBigExponent = | 
| - (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; | 
| - __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); | 
| - __ j(greater_equal, conversion_failure); | 
| + if (!number_info.IsInteger32()) { | 
| + // Check whether the exponent is too big for a 64 bit signed integer. | 
| + static const uint32_t kTooBigExponent = | 
| + (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; | 
| + __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); | 
| + __ j(greater_equal, conversion_failure); | 
| + } | 
| // Load x87 register with heap number. | 
| __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); | 
| // Reserve space for 64 bit answer. | 
| @@ -8851,6 +9061,7 @@ | 
| // Input: edx, eax are the left and right objects of a bit op. | 
| // Output: eax, ecx are left and right integers for a bit op. | 
| void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, | 
| + NumberInfo number_info, | 
| bool use_sse3, | 
| Label* conversion_failure) { | 
| // Check float operands. | 
| @@ -8858,48 +9069,68 @@ | 
| Label arg2_is_object, check_undefined_arg2; | 
| Label load_arg2, done; | 
| - __ test(edx, Immediate(kSmiTagMask)); | 
| - __ j(not_zero, &arg1_is_object); | 
| - __ SmiUntag(edx); | 
| - __ jmp(&load_arg2); | 
| + if (number_info.IsHeapNumber()) { | 
| 
 
fschneider
2010/03/05 15:01:07
This function is getting quite messy with all the
 
 | 
| + __ jmp (&arg1_is_object); | 
| 
 
fschneider
2010/03/05 15:01:07
Remove extra space.
 
 | 
| + } else { | 
| + if (!number_info.IsSmi()) { | 
| + __ test(edx, Immediate(kSmiTagMask)); | 
| + __ j(not_zero, &arg1_is_object); | 
| + } | 
| + __ SmiUntag(edx); | 
| + __ jmp(&load_arg2); | 
| + } | 
| // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 
| - __ bind(&check_undefined_arg1); | 
| - __ cmp(edx, Factory::undefined_value()); | 
| - __ j(not_equal, conversion_failure); | 
| - __ mov(edx, Immediate(0)); | 
| - __ jmp(&load_arg2); | 
| + if (!number_info.IsNumber()) { | 
| + __ bind(&check_undefined_arg1); | 
| + __ cmp(edx, Factory::undefined_value()); | 
| + __ j(not_equal, conversion_failure); | 
| + __ mov(edx, Immediate(0)); | 
| + __ jmp(&load_arg2); | 
| + } | 
| __ bind(&arg1_is_object); | 
| - __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 
| - __ cmp(ebx, Factory::heap_number_map()); | 
| - __ j(not_equal, &check_undefined_arg1); | 
| + if (!number_info.IsNumber()) { | 
| + __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 
| + __ cmp(ebx, Factory::heap_number_map()); | 
| + __ j(not_equal, &check_undefined_arg1); | 
| + } | 
| // Get the untagged integer version of the edx heap number in ecx. | 
| - IntegerConvert(masm, edx, use_sse3, conversion_failure); | 
| + IntegerConvert(masm, edx, number_info, use_sse3, conversion_failure); | 
| __ mov(edx, ecx); | 
| // Here edx has the untagged integer, eax has a Smi or a heap number. | 
| __ bind(&load_arg2); | 
| - // Test if arg2 is a Smi. | 
| - __ test(eax, Immediate(kSmiTagMask)); | 
| - __ j(not_zero, &arg2_is_object); | 
| - __ SmiUntag(eax); | 
| - __ mov(ecx, eax); | 
| - __ jmp(&done); | 
| + if (number_info.IsHeapNumber()) { | 
| + __ jmp(&arg2_is_object); | 
| + } else { | 
| + // Test if arg2 is a Smi. | 
| + if (!number_info.IsSmi()) { | 
| + __ test(eax, Immediate(kSmiTagMask)); | 
| + __ j(not_zero, &arg2_is_object); | 
| + } | 
| + __ SmiUntag(eax); | 
| + __ mov(ecx, eax); | 
| + __ jmp(&done); | 
| + } | 
| // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 
| - __ bind(&check_undefined_arg2); | 
| - __ cmp(eax, Factory::undefined_value()); | 
| - __ j(not_equal, conversion_failure); | 
| - __ mov(ecx, Immediate(0)); | 
| - __ jmp(&done); | 
| + if (!number_info.IsNumber()) { | 
| + __ bind(&check_undefined_arg2); | 
| + __ cmp(eax, Factory::undefined_value()); | 
| + __ j(not_equal, conversion_failure); | 
| + __ mov(ecx, Immediate(0)); | 
| + __ jmp(&done); | 
| + } | 
| __ bind(&arg2_is_object); | 
| - __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 
| - __ cmp(ebx, Factory::heap_number_map()); | 
| - __ j(not_equal, &check_undefined_arg2); | 
| + if (!number_info.IsNumber()) { | 
| + __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 
| + __ cmp(ebx, Factory::heap_number_map()); | 
| + __ j(not_equal, &check_undefined_arg2); | 
| + } | 
| // Get the untagged integer version of the eax heap number in ecx. | 
| - IntegerConvert(masm, eax, use_sse3, conversion_failure); | 
| + IntegerConvert(masm, eax, number_info, use_sse3, conversion_failure); | 
| __ bind(&done); | 
| __ mov(eax, edx); | 
| } | 
| @@ -9141,7 +9372,11 @@ | 
| __ j(not_equal, &slow, not_taken); | 
| // Convert the heap number in eax to an untagged integer in ecx. | 
| - IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), &slow); | 
| + IntegerConvert(masm, | 
| + eax, | 
| + NumberInfo::Unknown(), | 
| + CpuFeatures::IsSupported(SSE3), | 
| + &slow); | 
| // Do the bitwise operation and check if the result fits in a smi. | 
| Label try_float; |