| Index: src/ia32/codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/codegen-ia32.cc (revision 3859)
|
| +++ src/ia32/codegen-ia32.cc (working copy)
|
| @@ -722,35 +722,54 @@
|
| // The value to convert should be popped from the frame.
|
| Result value = frame_->Pop();
|
| value.ToRegister();
|
| - // Fast case checks.
|
|
|
| - // 'false' => false.
|
| - __ cmp(value.reg(), Factory::false_value());
|
| - dest->false_target()->Branch(equal);
|
| + if (value.is_number()) {
|
| + Comment cmnt(masm_, "ONLY_NUMBER");
|
| + // Fast case if NumberInfo indicates only numbers.
|
| + if (FLAG_debug_code) {
|
| + __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number.");
|
| + }
|
| + // Smi => false iff zero.
|
| + ASSERT(kSmiTag == 0);
|
| + __ test(value.reg(), Operand(value.reg()));
|
| + dest->false_target()->Branch(zero);
|
| + __ test(value.reg(), Immediate(kSmiTagMask));
|
| + dest->true_target()->Branch(zero);
|
| + __ fldz();
|
| + __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset));
|
| + __ FCmp();
|
| + value.Unuse();
|
| + dest->Split(not_zero);
|
| + } else {
|
| + // Fast case checks.
|
| + // 'false' => false.
|
| + __ cmp(value.reg(), Factory::false_value());
|
| + dest->false_target()->Branch(equal);
|
|
|
| - // 'true' => true.
|
| - __ cmp(value.reg(), Factory::true_value());
|
| - dest->true_target()->Branch(equal);
|
| + // 'true' => true.
|
| + __ cmp(value.reg(), Factory::true_value());
|
| + dest->true_target()->Branch(equal);
|
|
|
| - // 'undefined' => false.
|
| - __ cmp(value.reg(), Factory::undefined_value());
|
| - dest->false_target()->Branch(equal);
|
| + // 'undefined' => false.
|
| + __ cmp(value.reg(), Factory::undefined_value());
|
| + dest->false_target()->Branch(equal);
|
|
|
| - // Smi => false iff zero.
|
| - ASSERT(kSmiTag == 0);
|
| - __ test(value.reg(), Operand(value.reg()));
|
| - dest->false_target()->Branch(zero);
|
| - __ test(value.reg(), Immediate(kSmiTagMask));
|
| - dest->true_target()->Branch(zero);
|
| + // Smi => false iff zero.
|
| + ASSERT(kSmiTag == 0);
|
| + __ test(value.reg(), Operand(value.reg()));
|
| + dest->false_target()->Branch(zero);
|
| + __ test(value.reg(), Immediate(kSmiTagMask));
|
| + dest->true_target()->Branch(zero);
|
|
|
| - // Call the stub for all other cases.
|
| - frame_->Push(&value); // Undo the Pop() from above.
|
| - ToBooleanStub stub;
|
| - Result temp = frame_->CallStub(&stub, 1);
|
| - // Convert the result to a condition code.
|
| - __ test(temp.reg(), Operand(temp.reg()));
|
| - temp.Unuse();
|
| - dest->Split(not_equal);
|
| + // Call the stub for all other cases.
|
| + frame_->Push(&value); // Undo the Pop() from above.
|
| + ToBooleanStub stub;
|
| + Result temp = frame_->CallStub(&stub, 1);
|
| + // Convert the result to a condition code.
|
| + __ test(temp.reg(), Operand(temp.reg()));
|
| + temp.Unuse();
|
| + dest->Split(not_equal);
|
| + }
|
| }
|
|
|
|
|
| @@ -790,6 +809,10 @@
|
| static void LoadAsIntegers(MacroAssembler* masm,
|
| bool use_sse3,
|
| Label* operand_conversion_failure);
|
| + // Test if operands are smis or heap numbers and load them
|
| + // into xmm0 and xmm1 if they are. Operands are in edx and eax.
|
| + // Leaves operands unchanged.
|
| + static void LoadSSE2Operands(MacroAssembler* masm);
|
| // Test if operands are numbers (smi or HeapNumber objects), and load
|
| // them into xmm0 and xmm1 if they are. Jump to label not_numbers if
|
| // either operand is not a number. Operands are in edx and eax.
|
| @@ -817,12 +840,13 @@
|
| }
|
|
|
| OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
|
| - "GenericBinaryOpStub_%s_%s%s_%s%s",
|
| + "GenericBinaryOpStub_%s_%s%s_%s%s%s",
|
| op_name,
|
| overwrite_name,
|
| (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "",
|
| args_in_registers_ ? "RegArgs" : "StackArgs",
|
| - args_reversed_ ? "_R" : "");
|
| + args_reversed_ ? "_R" : "",
|
| + only_numbers_in_stub_ ? "_OnlyNumbers" : "");
|
| return name_;
|
| }
|
|
|
| @@ -972,27 +996,35 @@
|
| // Neither operand is known to be a string.
|
| }
|
|
|
| - bool left_is_smi = left.is_constant() && left.handle()->IsSmi();
|
| - bool left_is_non_smi = left.is_constant() && !left.handle()->IsSmi();
|
| - bool right_is_smi = right.is_constant() && right.handle()->IsSmi();
|
| - bool right_is_non_smi = right.is_constant() && !right.handle()->IsSmi();
|
| + bool left_is_smi_constant = left.is_constant() && left.handle()->IsSmi();
|
| + bool left_is_non_smi_constant = left.is_constant() && !left.handle()->IsSmi();
|
| + bool right_is_smi_constant = right.is_constant() && right.handle()->IsSmi();
|
| + bool right_is_non_smi_constant =
|
| + right.is_constant() && !right.handle()->IsSmi();
|
|
|
| - if (left_is_smi && right_is_smi) {
|
| + if (left_is_smi_constant && right_is_smi_constant) {
|
| // Compute the constant result at compile time, and leave it on the frame.
|
| int left_int = Smi::cast(*left.handle())->value();
|
| int right_int = Smi::cast(*right.handle())->value();
|
| if (FoldConstantSmis(op, left_int, right_int)) return;
|
| }
|
|
|
| + // Get number type of left and right sub-expressions.
|
| + bool only_numbers = left.is_number() && right.is_number();
|
| + bool only_smis = left.is_smi() && right.is_smi();
|
| +
|
| Result answer;
|
| - if (left_is_non_smi || right_is_non_smi) {
|
| + if (left_is_non_smi_constant || right_is_non_smi_constant) {
|
| // Go straight to the slow case, with no smi code.
|
| - GenericBinaryOpStub stub(op, overwrite_mode, NO_SMI_CODE_IN_STUB);
|
| + GenericBinaryOpStub stub(op,
|
| + overwrite_mode,
|
| + NO_SMI_CODE_IN_STUB,
|
| + only_numbers);
|
| answer = stub.GenerateCall(masm_, frame_, &left, &right);
|
| - } else if (right_is_smi) {
|
| + } else if (right_is_smi_constant) {
|
| answer = ConstantSmiBinaryOperation(op, &left, right.handle(),
|
| type, false, overwrite_mode);
|
| - } else if (left_is_smi) {
|
| + } else if (left_is_smi_constant) {
|
| answer = ConstantSmiBinaryOperation(op, &right, left.handle(),
|
| type, true, overwrite_mode);
|
| } else {
|
| @@ -1004,10 +1036,49 @@
|
| if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) {
|
| answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode);
|
| } else {
|
| - GenericBinaryOpStub stub(op, overwrite_mode, NO_GENERIC_BINARY_FLAGS);
|
| + GenericBinaryOpStub stub(op,
|
| + overwrite_mode,
|
| + NO_GENERIC_BINARY_FLAGS,
|
| + only_numbers);
|
| answer = stub.GenerateCall(masm_, frame_, &left, &right);
|
| }
|
| }
|
| +
|
| + // Set NumberInfo of result according to the operation performed.
|
| + NumberInfo::Type info = NumberInfo::kUnknown;
|
| + switch (op) {
|
| + case Token::COMMA:
|
| + info = right.number_info();
|
| + case Token::OR:
|
| + case Token::AND:
|
| + // Could be anything. Check inputs.
|
| + if (only_numbers)
|
| + info = NumberInfo::kNumber;
|
| + break;
|
| + case Token::BIT_OR:
|
| + case Token::BIT_XOR:
|
| + case Token::BIT_AND:
|
| + case Token::SAR:
|
| + case Token::SHR:
|
| + info = only_smis ? NumberInfo::kSmi : NumberInfo::kNumber;
|
| + break;
|
| + case Token::SHL:
|
| + info = NumberInfo::kNumber;
|
| + break;
|
| + case Token::ADD:
|
| + // Could be strings or numbers. Check types of inputs.
|
| + if (only_numbers) info = NumberInfo::kNumber;
|
| + break;
|
| + case Token::SUB:
|
| + case Token::MUL:
|
| + case Token::DIV:
|
| + case Token::MOD:
|
| + info = NumberInfo::kNumber;
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + answer.set_number_info(info);
|
| frame_->Push(&answer);
|
| }
|
|
|
| @@ -7545,7 +7616,18 @@
|
| case Token::DIV: {
|
| if (CpuFeatures::IsSupported(SSE2)) {
|
| CpuFeatures::Scope use_sse2(SSE2);
|
| - FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime);
|
| + if (only_numbers_in_stub_) {
|
| + if (FLAG_debug_code) {
|
| + // Assert at runtime that inputs are only numbers.
|
| + __ AbortIfNotNumber(edx,
|
| + "GenericBinaryOpStub operand not a number.");
|
| + __ AbortIfNotNumber(eax,
|
| + "GenericBinaryOpStub operand not a number.");
|
| + }
|
| + FloatingPointHelper::LoadSSE2Operands(masm);
|
| + } else {
|
| + FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime);
|
| + }
|
|
|
| switch (op_) {
|
| case Token::ADD: __ addsd(xmm0, xmm1); break;
|
| @@ -7558,7 +7640,17 @@
|
| __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
|
| GenerateReturn(masm);
|
| } else { // SSE2 not available, use FPU.
|
| - FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
|
| + if (only_numbers_in_stub_) {
|
| + if (FLAG_debug_code) {
|
| + // Assert at runtime that inputs are only numbers.
|
| + __ AbortIfNotNumber(edx,
|
| + "GenericBinaryOpStub operand not a number.");
|
| + __ AbortIfNotNumber(eax,
|
| + "GenericBinaryOpStub operand not a number.");
|
| + }
|
| + } else {
|
| + FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
|
| + }
|
| FloatingPointHelper::LoadFloatOperands(
|
| masm,
|
| ecx,
|
| @@ -8070,6 +8162,35 @@
|
| }
|
|
|
|
|
| +void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm) {
|
| + Label load_smi_edx, load_eax, load_smi_eax, done;
|
| + // Load operand in edx into xmm0.
|
| + __ test(edx, Immediate(kSmiTagMask));
|
| + __ j(zero, &load_smi_edx, not_taken); // Argument in edx is a smi.
|
| + __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset));
|
| +
|
| + __ bind(&load_eax);
|
| + // Load operand in eax into xmm1.
|
| + __ test(eax, Immediate(kSmiTagMask));
|
| + __ j(zero, &load_smi_eax, not_taken); // Argument in eax is a smi.
|
| + __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
|
| + __ jmp(&done);
|
| +
|
| + __ bind(&load_smi_edx);
|
| + __ SmiUntag(edx); // Untag smi before converting to float.
|
| + __ cvtsi2sd(xmm0, Operand(edx));
|
| + __ SmiTag(edx); // Retag smi for heap number overwriting test.
|
| + __ jmp(&load_eax);
|
| +
|
| + __ bind(&load_smi_eax);
|
| + __ SmiUntag(eax); // Untag smi before converting to float.
|
| + __ cvtsi2sd(xmm1, Operand(eax));
|
| + __ SmiTag(eax); // Retag smi for heap number overwriting test.
|
| +
|
| + __ bind(&done);
|
| +}
|
| +
|
| +
|
| void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm,
|
| Label* not_numbers) {
|
| Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done;
|
|
|