From: svenpanne@chromium.org Date: Tue, 4 Jun 2013 07:49:45 +0000 (+0000) Subject: Collect type feedback for power-of-2 right operands in BinaryOps. X-Git-Tag: upstream/4.7.83~14027 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b9e025a8dcdebb2e30bc8a32f8fbd0ceb4cbdfb9;p=platform%2Fupstream%2Fv8.git Collect type feedback for power-of-2 right operands in BinaryOps. Improved --trace-ic output for unary/binary ops a bit on the way. Moved int32_t/uint32_t conversion helpers around. R=jkummerow@chromium.org Review URL: https://codereview.chromium.org/15735005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14928 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index c15ecb245..08c366c92 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -2029,7 +2029,14 @@ void BinaryOpStub_GenerateSmiCode( void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { - Label not_smis, call_runtime; + Label right_arg_changed, call_runtime; + + if (op_ == Token::MOD && has_fixed_right_arg_) { + // It is guaranteed that the value will fit into a Smi, because if it + // didn't, we wouldn't be here, see BinaryOp_Patch. + __ cmp(r0, Operand(Smi::FromInt(fixed_right_arg_value()))); + __ b(ne, &right_arg_changed); + } if (result_type_ == BinaryOpIC::UNINITIALIZED || result_type_ == BinaryOpIC::SMI) { @@ -2046,6 +2053,7 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { // Code falls through if the result is not returned as either a smi or heap // number. + __ bind(&right_arg_changed); GenerateTypeTransition(masm); __ bind(&call_runtime); @@ -2217,6 +2225,12 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { // to type transition. } else { + if (has_fixed_right_arg_) { + __ Vmov(d8, fixed_right_arg_value(), scratch1); + __ VFPCompareAndSetFlags(d1, d8); + __ b(ne, &transition); + } + // We preserved r0 and r1 to be able to call runtime. // Save the left value on the stack. __ Push(r5, r4); diff --git a/src/ast.cc b/src/ast.cc index e27feec1a..60cc3cd32 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -682,7 +682,8 @@ void UnaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) { void BinaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) { - oracle->BinaryType(this, &left_type_, &right_type_, &result_type_); + oracle->BinaryType(this, &left_type_, &right_type_, &result_type_, + &has_fixed_right_arg_, &fixed_right_arg_value_); } diff --git a/src/ast.h b/src/ast.h index 4e851f217..373adf953 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1799,6 +1799,8 @@ class BinaryOperation: public Expression { TypeInfo left_type() const { return left_type_; } TypeInfo right_type() const { return right_type_; } TypeInfo result_type() const { return result_type_; } + bool has_fixed_right_arg() const { return has_fixed_right_arg_; } + int fixed_right_arg_value() const { return fixed_right_arg_value_; } protected: BinaryOperation(Isolate* isolate, @@ -1824,6 +1826,8 @@ class BinaryOperation: public Expression { TypeInfo left_type_; TypeInfo right_type_; TypeInfo result_type_; + bool has_fixed_right_arg_; + int fixed_right_arg_value_; // The short-circuit logical operations need an AST ID for their // right-hand subexpression. diff --git a/src/code-stubs.h b/src/code-stubs.h index 513ad9a7c..75c1295dd 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -885,7 +885,9 @@ class BinaryOpStub: public PlatformCodeStub { platform_specific_bit_(false), left_type_(BinaryOpIC::UNINITIALIZED), right_type_(BinaryOpIC::UNINITIALIZED), - result_type_(BinaryOpIC::UNINITIALIZED) { + result_type_(BinaryOpIC::UNINITIALIZED), + has_fixed_right_arg_(false), + encoded_right_arg_(encode_arg_value(1)) { Initialize(); ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); } @@ -894,13 +896,17 @@ class BinaryOpStub: public PlatformCodeStub { int key, BinaryOpIC::TypeInfo left_type, BinaryOpIC::TypeInfo right_type, - BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED) + BinaryOpIC::TypeInfo result_type, + bool has_fixed_right_arg, + int32_t fixed_right_arg_value) : op_(OpBits::decode(key)), mode_(ModeBits::decode(key)), platform_specific_bit_(PlatformSpecificBits::decode(key)), left_type_(left_type), right_type_(right_type), - result_type_(result_type) { } + result_type_(result_type), + has_fixed_right_arg_(has_fixed_right_arg), + encoded_right_arg_(encode_arg_value(fixed_right_arg_value)) { } static void decode_types_from_minor_key(int minor_key, BinaryOpIC::TypeInfo* left_type, @@ -918,6 +924,24 @@ class BinaryOpStub: public PlatformCodeStub { return static_cast(OpBits::decode(minor_key)); } + static bool decode_has_fixed_right_arg_from_minor_key(int minor_key) { + return HasFixedRightArgBits::decode(minor_key); + } + + static int decode_fixed_right_arg_value_from_minor_key(int minor_key) { + return decode_arg_value(FixedRightArgValueBits::decode(minor_key)); + } + + int fixed_right_arg_value() const { + return decode_arg_value(encoded_right_arg_); + } + + static bool can_encode_arg_value(int32_t value) { + return value > 0 && + IsPowerOf2(value) && + FixedRightArgValueBits::is_valid(WhichPowerOf2(value)); + } + enum SmiCodeGenerateHeapNumberResults { ALLOW_HEAPNUMBER_RESULTS, NO_HEAPNUMBER_RESULTS @@ -933,15 +957,31 @@ class BinaryOpStub: public PlatformCodeStub { BinaryOpIC::TypeInfo right_type_; BinaryOpIC::TypeInfo result_type_; + bool has_fixed_right_arg_; + int encoded_right_arg_; + + static int encode_arg_value(int32_t value) { + ASSERT(can_encode_arg_value(value)); + return WhichPowerOf2(value); + } + + static int32_t decode_arg_value(int value) { + return 1 << value; + } + virtual void PrintName(StringStream* stream); - // Minor key encoding in 19 bits TTTRRRLLLSOOOOOOOMM. + // Minor key encoding in all 25 bits FFFFFHTTTRRRLLLPOOOOOOOMM. + // Note: We actually do not need 7 bits for the operation, just 4 bits to + // encode ADD, SUB, MUL, DIV, MOD, BIT_OR, BIT_AND, BIT_XOR, SAR, SHL, SHR. class ModeBits: public BitField {}; class OpBits: public BitField {}; class PlatformSpecificBits: public BitField {}; class LeftTypeBits: public BitField {}; class RightTypeBits: public BitField {}; class ResultTypeBits: public BitField {}; + class HasFixedRightArgBits: public BitField {}; + class FixedRightArgValueBits: public BitField {}; Major MajorKey() { return BinaryOp; } int MinorKey() { @@ -950,7 +990,9 @@ class BinaryOpStub: public PlatformCodeStub { | PlatformSpecificBits::encode(platform_specific_bit_) | LeftTypeBits::encode(left_type_) | RightTypeBits::encode(right_type_) - | ResultTypeBits::encode(result_type_); + | ResultTypeBits::encode(result_type_) + | HasFixedRightArgBits::encode(has_fixed_right_arg_) + | FixedRightArgValueBits::encode(encoded_right_arg_); } diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc index 0f894a8f2..723d3f692 100644 --- a/src/deoptimizer.cc +++ b/src/deoptimizer.cc @@ -1986,56 +1986,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, } -static bool ObjectToInt32(Object* obj, int32_t* value) { - if (obj->IsSmi()) { - *value = Smi::cast(obj)->value(); - return true; - } - - if (obj->IsHeapNumber()) { - double num = HeapNumber::cast(obj)->value(); - if (FastI2D(FastD2I(num)) != num) { - if (FLAG_trace_osr) { - PrintF("**** %g could not be converted to int32 ****\n", - HeapNumber::cast(obj)->value()); - } - return false; - } - - *value = FastD2I(num); - return true; - } - - return false; -} - - -static bool ObjectToUint32(Object* obj, uint32_t* value) { - if (obj->IsSmi()) { - if (Smi::cast(obj)->value() < 0) return false; - - *value = static_cast(Smi::cast(obj)->value()); - return true; - } - - if (obj->IsHeapNumber()) { - double num = HeapNumber::cast(obj)->value(); - if ((num < 0) || (FastUI2D(FastD2UI(num)) != num)) { - if (FLAG_trace_osr) { - PrintF("**** %g could not be converted to uint32 ****\n", - HeapNumber::cast(obj)->value()); - } - return false; - } - - *value = FastD2UI(num); - return true; - } - - return false; -} - - bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, int* input_offset) { disasm::NameConverter converter; @@ -2079,7 +2029,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, case Translation::INT32_REGISTER: { int32_t int32_value = 0; - if (!ObjectToInt32(input_object, &int32_value)) return false; + if (!input_object->ToInt32(&int32_value)) return false; int output_reg = iterator->Next(); if (FLAG_trace_osr) { @@ -2094,7 +2044,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, case Translation::UINT32_REGISTER: { uint32_t uint32_value = 0; - if (!ObjectToUint32(input_object, &uint32_value)) return false; + if (!input_object->ToUint32(&uint32_value)) return false; int output_reg = iterator->Next(); if (FLAG_trace_osr) { @@ -2141,7 +2091,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, case Translation::INT32_STACK_SLOT: { int32_t int32_value = 0; - if (!ObjectToInt32(input_object, &int32_value)) return false; + if (!input_object->ToInt32(&int32_value)) return false; int output_index = iterator->Next(); unsigned output_offset = @@ -2158,7 +2108,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, case Translation::UINT32_STACK_SLOT: { uint32_t uint32_value = 0; - if (!ObjectToUint32(input_object, &uint32_value)) return false; + if (!input_object->ToUint32(&uint32_value)) return false; int output_index = iterator->Next(); unsigned output_offset = diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index ef3f1cdce..8b3cd52df 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -3369,8 +3369,12 @@ HInstruction* HMathMinMax::New( } -HInstruction* HMod::New( - Zone* zone, HValue* context, HValue* left, HValue* right) { +HInstruction* HMod::New(Zone* zone, + HValue* context, + HValue* left, + HValue* right, + bool has_fixed_right_arg, + int fixed_right_arg_value) { if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { HConstant* c_left = HConstant::cast(left); HConstant* c_right = HConstant::cast(right); @@ -3389,7 +3393,11 @@ HInstruction* HMod::New( } } } - return new(zone) HMod(context, left, right); + return new(zone) HMod(context, + left, + right, + has_fixed_right_arg, + fixed_right_arg_value); } diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index e464ac45e..f79d995d9 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -4340,7 +4340,12 @@ class HMod: public HArithmeticBinaryOperation { static HInstruction* New(Zone* zone, HValue* context, HValue* left, - HValue* right); + HValue* right, + bool has_fixed_right_arg, + int fixed_right_arg_value); + + bool has_fixed_right_arg() const { return has_fixed_right_arg_; } + int fixed_right_arg_value() const { return fixed_right_arg_value_; } bool HasPowerOf2Divisor() { if (right()->IsConstant() && @@ -4364,11 +4369,20 @@ class HMod: public HArithmeticBinaryOperation { virtual Range* InferRange(Zone* zone); private: - HMod(HValue* context, HValue* left, HValue* right) - : HArithmeticBinaryOperation(context, left, right) { + HMod(HValue* context, + HValue* left, + HValue* right, + bool has_fixed_right_arg, + int fixed_right_arg_value) + : HArithmeticBinaryOperation(context, left, right), + has_fixed_right_arg_(has_fixed_right_arg), + fixed_right_arg_value_(fixed_right_arg_value) { SetFlag(kCanBeDivByZero); SetFlag(kCanOverflow); } + + const bool has_fixed_right_arg_; + const int fixed_right_arg_value_; }; diff --git a/src/hydrogen.cc b/src/hydrogen.cc index b166e138c..bfe7cbc17 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -9334,7 +9334,8 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( TypeInfo left_info = expr->left_type(); TypeInfo right_info = expr->right_type(); TypeInfo result_info = expr->result_type(); - TypeInfo combined_info; + bool has_fixed_right_arg = expr->has_fixed_right_arg(); + int fixed_right_arg_value = expr->fixed_right_arg_value(); Representation left_rep = ToRepresentation(left_info); Representation right_rep = ToRepresentation(right_info); Representation result_rep = ToRepresentation(result_info); @@ -9364,7 +9365,12 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( instr = HMul::New(zone(), context, left, right); break; case Token::MOD: - instr = HMod::New(zone(), context, left, right); + instr = HMod::New(zone(), + context, + left, + right, + has_fixed_right_arg, + fixed_right_arg_value); break; case Token::DIV: instr = HDiv::New(zone(), context, left, right); diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index aa533bf83..56f2eb797 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -566,12 +566,6 @@ class FloatingPointHelper : public AllStatic { // Expects operands in edx, eax. static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); - // Checks that the two floating point numbers loaded into xmm0 and xmm1 - // have int32 values. - static void CheckSSE2OperandsAreInt32(MacroAssembler* masm, - Label* non_int32, - Register scratch); - // Checks that |operand| has an int32 value. If |int32_result| is different // from |scratch|, it will contain that int32 value. static void CheckSSE2OperandIsInt32(MacroAssembler* masm, @@ -1470,7 +1464,7 @@ static void BinaryOpStub_GenerateSmiCode( void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { - Label call_runtime; + Label right_arg_changed, call_runtime; switch (op_) { case Token::ADD: @@ -1491,6 +1485,13 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { UNREACHABLE(); } + if (op_ == Token::MOD && has_fixed_right_arg_) { + // It is guaranteed that the value will fit into a Smi, because if it + // didn't, we wouldn't be here, see BinaryOp_Patch. + __ cmp(eax, Immediate(Smi::FromInt(fixed_right_arg_value()))); + __ j(not_equal, &right_arg_changed); + } + if (result_type_ == BinaryOpIC::UNINITIALIZED || result_type_ == BinaryOpIC::SMI) { BinaryOpStub_GenerateSmiCode( @@ -1502,6 +1503,7 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { // Code falls through if the result is not returned as either a smi or heap // number. + __ bind(&right_arg_changed); switch (op_) { case Token::ADD: case Token::SUB: @@ -1604,8 +1606,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { case Token::MUL: case Token::DIV: case Token::MOD: { - Label not_floats; - Label not_int32; + Label not_floats, not_int32, right_arg_changed; if (CpuFeatures::IsSupported(SSE2)) { CpuFeatureScope use_sse2(masm, SSE2); // It could be that only SMIs have been seen at either the left @@ -1621,8 +1622,15 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { __ JumpIfNotSmi(eax, ¬_int32); } FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); - FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); + FloatingPointHelper::CheckSSE2OperandIsInt32( + masm, ¬_int32, xmm0, ebx, ecx, xmm2); + FloatingPointHelper::CheckSSE2OperandIsInt32( + masm, ¬_int32, xmm1, edi, ecx, xmm2); if (op_ == Token::MOD) { + if (has_fixed_right_arg_) { + __ cmp(edi, Immediate(fixed_right_arg_value())); + __ j(not_equal, &right_arg_changed); + } GenerateRegisterArgsPush(masm); __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); } else { @@ -1675,6 +1683,7 @@ void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { __ bind(¬_floats); __ bind(¬_int32); + __ bind(&right_arg_changed); GenerateTypeTransition(masm); break; } @@ -2766,14 +2775,6 @@ void FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm, } -void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, - Label* non_int32, - Register scratch) { - CheckSSE2OperandIsInt32(masm, non_int32, xmm0, scratch, scratch, xmm2); - CheckSSE2OperandIsInt32(masm, non_int32, xmm1, scratch, scratch, xmm2); -} - - void FloatingPointHelper::CheckSSE2OperandIsInt32(MacroAssembler* masm, Label* non_int32, XMMRegister operand, diff --git a/src/ic.cc b/src/ic.cc index f4aca225d..148e06976 100644 --- a/src/ic.cc +++ b/src/ic.cc @@ -2498,7 +2498,7 @@ RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) { if (FLAG_trace_ic) { PrintF("[UnaryOpIC in "); JavaScriptFrame::PrintTop(isolate, stdout, false, true); - PrintF(" (%s->%s)#%s @ %p]\n", + PrintF(" %s => %s #%s @ %p]\n", UnaryOpIC::GetName(previous_type), UnaryOpIC::GetName(type), Token::Name(op), @@ -2572,6 +2572,19 @@ static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, } +#ifdef DEBUG +static void TraceBinaryOp(BinaryOpIC::TypeInfo left, + BinaryOpIC::TypeInfo right, + bool has_fixed_right_arg, + int32_t fixed_right_arg_value, + BinaryOpIC::TypeInfo result) { + PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right)); + if (has_fixed_right_arg) PrintF("{%d}", fixed_right_arg_value); + PrintF("->%s", BinaryOpIC::GetName(result)); +} +#endif + + RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { ASSERT(args.length() == 3); @@ -2580,9 +2593,10 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { Handle right = args.at(1); int key = args.smi_at(2); Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); - BinaryOpIC::TypeInfo previous_left, previous_right, unused_previous_result; + + BinaryOpIC::TypeInfo previous_left, previous_right, previous_result; BinaryOpStub::decode_types_from_minor_key( - key, &previous_left, &previous_right, &unused_previous_result); + key, &previous_left, &previous_right, &previous_result); BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); @@ -2597,43 +2611,60 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); - if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { - if (op == Token::DIV || - op == Token::MUL || - op == Token::SHR || - kSmiValueSize == 32) { - // Arithmetic on two Smi inputs has yielded a heap number. - // That is the only way to get here from the Smi stub. - // With 32-bit Smis, all overflows give heap numbers, but with - // 31-bit Smis, most operations overflow to int32 results. - result_type = BinaryOpIC::NUMBER; - } else { - // Other operations on SMIs that overflow yield int32s. - result_type = BinaryOpIC::INT32; + bool previous_has_fixed_right_arg = + BinaryOpStub::decode_has_fixed_right_arg_from_minor_key(key); + int previous_fixed_right_arg_value = + BinaryOpStub::decode_fixed_right_arg_value_from_minor_key(key); + + int32_t value; + bool new_has_fixed_right_arg = + op == Token::MOD && + right->ToInt32(&value) && + BinaryOpStub::can_encode_arg_value(value) && + (previous_overall == BinaryOpIC::UNINITIALIZED || + (previous_has_fixed_right_arg && + previous_fixed_right_arg_value == value)); + int32_t new_fixed_right_arg_value = new_has_fixed_right_arg ? value : 1; + + if (previous_has_fixed_right_arg == new_has_fixed_right_arg) { + if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { + if (op == Token::DIV || + op == Token::MUL || + op == Token::SHR || + kSmiValueSize == 32) { + // Arithmetic on two Smi inputs has yielded a heap number. + // That is the only way to get here from the Smi stub. + // With 32-bit Smis, all overflows give heap numbers, but with + // 31-bit Smis, most operations overflow to int32 results. + result_type = BinaryOpIC::NUMBER; + } else { + // Other operations on SMIs that overflow yield int32s. + result_type = BinaryOpIC::INT32; + } } - } - if (new_overall == BinaryOpIC::INT32 && - previous_overall == BinaryOpIC::INT32) { - if (new_left == previous_left && new_right == previous_right) { - result_type = BinaryOpIC::NUMBER; + if (new_overall == BinaryOpIC::INT32 && + previous_overall == BinaryOpIC::INT32) { + if (new_left == previous_left && new_right == previous_right) { + result_type = BinaryOpIC::NUMBER; + } } } - BinaryOpStub stub(key, new_left, new_right, result_type); + BinaryOpStub stub(key, new_left, new_right, result_type, + new_has_fixed_right_arg, new_fixed_right_arg_value); Handle code = stub.GetCode(isolate); if (!code.is_null()) { #ifdef DEBUG if (FLAG_trace_ic) { PrintF("[BinaryOpIC in "); JavaScriptFrame::PrintTop(isolate, stdout, false, true); - PrintF(" ((%s+%s)->((%s+%s)->%s))#%s @ %p]\n", - BinaryOpIC::GetName(previous_left), - BinaryOpIC::GetName(previous_right), - BinaryOpIC::GetName(new_left), - BinaryOpIC::GetName(new_right), - BinaryOpIC::GetName(result_type), - Token::Name(op), - static_cast(*code)); + PrintF(" "); + TraceBinaryOp(previous_left, previous_right, previous_has_fixed_right_arg, + previous_fixed_right_arg_value, previous_result); + PrintF(" => "); + TraceBinaryOp(new_left, new_right, new_has_fixed_right_arg, + new_fixed_right_arg_value, result_type); + PrintF(" #%s @ %p]\n", Token::Name(op), static_cast(*code)); } #endif BinaryOpIC ic(isolate); diff --git a/src/objects.cc b/src/objects.cc index edb9120c7..9d35cbc31 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -155,6 +155,41 @@ MaybeObject* Object::GetPropertyWithReceiver(Object* receiver, } +bool Object::ToInt32(int32_t* value) { + if (IsSmi()) { + *value = Smi::cast(this)->value(); + return true; + } + if (IsHeapNumber()) { + double num = HeapNumber::cast(this)->value(); + if (FastI2D(FastD2I(num)) == num) { + *value = FastD2I(num); + return true; + } + } + return false; +} + + +bool Object::ToUint32(uint32_t* value) { + if (IsSmi()) { + int num = Smi::cast(this)->value(); + if (num >= 0) { + *value = static_cast(num); + return true; + } + } + if (IsHeapNumber()) { + double num = HeapNumber::cast(this)->value(); + if (num >= 0 && FastUI2D(FastD2UI(num)) == num) { + *value = FastD2UI(num); + return true; + } + } + return false; +} + + template static inline To* CheckedCast(void *from) { uintptr_t temp = reinterpret_cast(from); diff --git a/src/objects.h b/src/objects.h index 0fa8ffa9e..ac748eefc 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1057,6 +1057,8 @@ class Object : public MaybeObject { // Extract the number. inline double Number(); inline bool IsNaN(); + bool ToInt32(int32_t* value); + bool ToUint32(uint32_t* value); inline Representation OptimalRepresentation() { if (FLAG_track_fields && IsSmi()) { diff --git a/src/type-info.cc b/src/type-info.cc index 0fa46e757..53a43b422 100644 --- a/src/type-info.cc +++ b/src/type-info.cc @@ -456,7 +456,9 @@ static TypeInfo TypeFromBinaryOpType(BinaryOpIC::TypeInfo binary_type) { void TypeFeedbackOracle::BinaryType(BinaryOperation* expr, TypeInfo* left, TypeInfo* right, - TypeInfo* result) { + TypeInfo* result, + bool* has_fixed_right_arg, + int* fixed_right_arg_value) { Handle object = GetInfo(expr->BinaryOperationFeedbackId()); TypeInfo unknown = TypeInfo::Unknown(); if (!object->IsCode()) { @@ -465,12 +467,17 @@ void TypeFeedbackOracle::BinaryType(BinaryOperation* expr, } Handle code = Handle::cast(object); if (code->is_binary_op_stub()) { + int minor_key = code->stub_info(); BinaryOpIC::TypeInfo left_type, right_type, result_type; - BinaryOpStub::decode_types_from_minor_key(code->stub_info(), &left_type, - &right_type, &result_type); + BinaryOpStub::decode_types_from_minor_key( + minor_key, &left_type, &right_type, &result_type); *left = TypeFromBinaryOpType(left_type); *right = TypeFromBinaryOpType(right_type); *result = TypeFromBinaryOpType(result_type); + *has_fixed_right_arg = + BinaryOpStub::decode_has_fixed_right_arg_from_minor_key(minor_key); + *fixed_right_arg_value = + BinaryOpStub::decode_fixed_right_arg_value_from_minor_key(minor_key); return; } // Not a binary op stub. diff --git a/src/type-info.h b/src/type-info.h index 6c7e31acd..15a0b81aa 100644 --- a/src/type-info.h +++ b/src/type-info.h @@ -305,7 +305,9 @@ class TypeFeedbackOracle: public ZoneObject { void BinaryType(BinaryOperation* expr, TypeInfo* left, TypeInfo* right, - TypeInfo* result); + TypeInfo* result, + bool* has_fixed_right_arg, + int* fixed_right_arg_value); void CompareType(CompareOperation* expr, TypeInfo* left_type, TypeInfo* right_type, diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 5da099088..1e3ef212c 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -1188,7 +1188,15 @@ void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { - Label call_runtime; + Label right_arg_changed, call_runtime; + + if (op_ == Token::MOD && has_fixed_right_arg_) { + // It is guaranteed that the value will fit into a Smi, because if it + // didn't, we wouldn't be here, see BinaryOp_Patch. + __ Cmp(rax, Smi::FromInt(fixed_right_arg_value())); + __ j(not_equal, &right_arg_changed); + } + if (result_type_ == BinaryOpIC::UNINITIALIZED || result_type_ == BinaryOpIC::SMI) { // Only allow smi results. @@ -1202,6 +1210,7 @@ void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { // Code falls through if the result is not returned as either a smi or heap // number. + __ bind(&right_arg_changed); GenerateTypeTransition(masm); if (call_runtime.is_linked()) {