| Index: src/x64/codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/codegen-x64.cc (revision 3859)
|
| +++ src/x64/codegen-x64.cc (working copy)
|
| @@ -4261,34 +4261,52 @@
|
| // The value to convert should be popped from the frame.
|
| Result value = frame_->Pop();
|
| value.ToRegister();
|
| - // Fast case checks.
|
|
|
| - // 'false' => false.
|
| - __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex);
|
| - 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.
|
| + __ SmiCompare(value.reg(), Smi::FromInt(0));
|
| + dest->false_target()->Branch(equal);
|
| + Condition is_smi = masm_->CheckSmi(value.reg());
|
| + dest->true_target()->Branch(is_smi);
|
| + __ fldz();
|
| + __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset));
|
| + __ FCmp();
|
| + value.Unuse();
|
| + dest->Split(not_zero);
|
| + } else {
|
| + // Fast case checks.
|
| + // 'false' => false.
|
| + __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex);
|
| + dest->false_target()->Branch(equal);
|
|
|
| - // 'true' => true.
|
| - __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex);
|
| - dest->true_target()->Branch(equal);
|
| + // 'true' => true.
|
| + __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex);
|
| + dest->true_target()->Branch(equal);
|
|
|
| - // 'undefined' => false.
|
| - __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex);
|
| - dest->false_target()->Branch(equal);
|
| + // 'undefined' => false.
|
| + __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex);
|
| + dest->false_target()->Branch(equal);
|
|
|
| - // Smi => false iff zero.
|
| - __ SmiCompare(value.reg(), Smi::FromInt(0));
|
| - dest->false_target()->Branch(equal);
|
| - Condition is_smi = masm_->CheckSmi(value.reg());
|
| - dest->true_target()->Branch(is_smi);
|
| + // Smi => false iff zero.
|
| + __ SmiCompare(value.reg(), Smi::FromInt(0));
|
| + dest->false_target()->Branch(equal);
|
| + Condition is_smi = masm_->CheckSmi(value.reg());
|
| + dest->true_target()->Branch(is_smi);
|
|
|
| - // 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.
|
| - __ testq(temp.reg(), 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.
|
| + __ testq(temp.reg(), temp.reg());
|
| + temp.Unuse();
|
| + dest->Split(not_equal);
|
| + }
|
| }
|
|
|
|
|
| @@ -5155,26 +5173,34 @@
|
| // 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) {
|
| - GenericBinaryOpStub stub(op, overwrite_mode, NO_SMI_CODE_IN_STUB);
|
| + if (left_is_non_smi_constant || right_is_non_smi_constant) {
|
| + 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 {
|
| @@ -5186,10 +5212,53 @@
|
| 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();
|
| + break;
|
| + 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:
|
| + // TODO(fsc): Make use of the fact that smis are 32 bits on x64.
|
| + 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);
|
| }
|
|
|
| @@ -8078,13 +8147,14 @@
|
| }
|
|
|
| OS::SNPrintF(Vector<char>(name_, len),
|
| - "GenericBinaryOpStub_%s_%s%s_%s%s_%s",
|
| + "GenericBinaryOpStub_%s_%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" : "",
|
| - use_sse3_ ? "SSE3" : "SSE2");
|
| + use_sse3_ ? "SSE3" : "SSE2",
|
| + only_numbers_in_stub_ ? "_OnlyNumbers" : "");
|
| return name_;
|
| }
|
|
|
| @@ -8408,7 +8478,15 @@
|
| case Token::DIV: {
|
| // rax: y
|
| // rdx: x
|
| - FloatingPointHelper::CheckNumberOperands(masm, &call_runtime);
|
| + if (only_numbers_in_stub_) {
|
| + if (FLAG_debug_code) {
|
| + // Assert at runtime that inputs are only numbers.
|
| + __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number.");
|
| + __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number.");
|
| + }
|
| + } else {
|
| + FloatingPointHelper::CheckNumberOperands(masm, &call_runtime);
|
| + }
|
| // Fast-case: Both operands are numbers.
|
| // xmm4 and xmm5 are volatile XMM registers.
|
| FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5);
|
|
|