| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 2548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2559 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); | 2559 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); |
| 2560 return Runtime::SetObjectProperty(isolate, | 2560 return Runtime::SetObjectProperty(isolate, |
| 2561 object, | 2561 object, |
| 2562 key, | 2562 key, |
| 2563 value, | 2563 value, |
| 2564 NONE, | 2564 NONE, |
| 2565 strict_mode); | 2565 strict_mode); |
| 2566 } | 2566 } |
| 2567 | 2567 |
| 2568 | 2568 |
| 2569 void BinaryOpIC::patch(Code* code) { | |
| 2570 set_target(code); | |
| 2571 } | |
| 2572 | |
| 2573 | |
| 2574 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2569 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| 2575 switch (type_info) { | 2570 switch (type_info) { |
| 2576 case UNINITIALIZED: return "Uninitialized"; | 2571 case UNINITIALIZED: return "Uninitialized"; |
| 2577 case SMI: return "Smi"; | 2572 case SMI: return "Smi"; |
| 2578 case INT32: return "Int32"; | 2573 case INT32: return "Int32"; |
| 2579 case NUMBER: return "Number"; | 2574 case NUMBER: return "Number"; |
| 2580 case ODDBALL: return "Oddball"; | 2575 case ODDBALL: return "Oddball"; |
| 2581 case STRING: return "String"; | 2576 case STRING: return "String"; |
| 2582 case GENERIC: return "Generic"; | 2577 case GENERIC: return "Generic"; |
| 2583 default: return "Invalid"; | 2578 default: return "Invalid"; |
| 2584 } | 2579 } |
| 2585 } | 2580 } |
| 2586 | 2581 |
| 2587 | 2582 |
| 2588 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { | 2583 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { |
| 2589 switch (type_info) { | 2584 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); |
| 2590 case UNINITIALIZED: | 2585 BinaryOpStub stub(extra_ic_state); |
| 2591 return ::v8::internal::UNINITIALIZED; | 2586 |
| 2592 case SMI: | 2587 bool smi_was_enabled = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2593 case INT32: | 2588 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2594 case NUMBER: | 2589 |
| 2595 case ODDBALL: | 2590 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); |
| 2596 case STRING: | 2591 |
| 2597 return MONOMORPHIC; | 2592 #ifdef DEBUG |
| 2598 case GENERIC: | 2593 if (FLAG_trace_ic) { |
| 2599 return ::v8::internal::GENERIC; | 2594 char buffer[100]; |
| 2595 NoAllocationStringAllocator allocator(buffer, |
| 2596 static_cast<unsigned>(sizeof(buffer))); |
| 2597 StringStream stream(&allocator); |
| 2598 stream.Add("["); |
| 2599 stub.PrintName(&stream); |
| 2600 |
| 2601 stub.UpdateStatus(left, right, result); |
| 2602 |
| 2603 stream.Add(" => "); |
| 2604 stub.PrintState(&stream); |
| 2605 stream.Add(" "); |
| 2606 stream.OutputToStdOut(); |
| 2607 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate()))); |
| 2608 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 2609 PrintF("]\n"); |
| 2610 } else { |
| 2611 stub.UpdateStatus(left, right, result); |
| 2600 } | 2612 } |
| 2601 UNREACHABLE(); | 2613 #else |
| 2602 return ::v8::internal::UNINITIALIZED; | 2614 stub.UpdateStatus(left, right, result); |
| 2615 #endif |
| 2616 |
| 2617 Handle<Code> code = stub.GetCode(isolate()); |
| 2618 set_target(*code); |
| 2619 |
| 2620 bool enable_smi = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2621 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2622 |
| 2623 if (!smi_was_enabled && enable_smi) { |
| 2624 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2625 } else if (smi_was_enabled && !enable_smi) { |
| 2626 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); |
| 2627 } |
| 2628 |
| 2629 return result.has_value |
| 2630 ? static_cast<MaybeObject*>(*result.value) |
| 2631 : Failure::Exception(); |
| 2603 } | 2632 } |
| 2604 | 2633 |
| 2605 | 2634 |
| 2606 Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type, | 2635 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { |
| 2607 Isolate* isolate) { | 2636 HandleScope scope(isolate); |
| 2608 switch (binary_type) { | 2637 Handle<Object> left = args.at<Object>(0); |
| 2609 case UNINITIALIZED: | 2638 Handle<Object> right = args.at<Object>(1); |
| 2610 return handle(Type::None(), isolate); | 2639 BinaryOpIC ic(isolate); |
| 2611 case SMI: | 2640 return ic.Transition(left, right); |
| 2612 return handle(Type::Smi(), isolate); | |
| 2613 case INT32: | |
| 2614 return handle(Type::Signed32(), isolate); | |
| 2615 case NUMBER: | |
| 2616 return handle(Type::Number(), isolate); | |
| 2617 case ODDBALL: | |
| 2618 return handle(Type::Optional( | |
| 2619 handle(Type::Union( | |
| 2620 handle(Type::Number(), isolate), | |
| 2621 handle(Type::String(), isolate)), isolate)), isolate); | |
| 2622 case STRING: | |
| 2623 return handle(Type::String(), isolate); | |
| 2624 case GENERIC: | |
| 2625 return handle(Type::Any(), isolate); | |
| 2626 } | |
| 2627 UNREACHABLE(); | |
| 2628 return handle(Type::Any(), isolate); | |
| 2629 } | 2641 } |
| 2630 | 2642 |
| 2631 | 2643 |
| 2632 void BinaryOpIC::StubInfoToType(int minor_key, | |
| 2633 Handle<Type>* left, | |
| 2634 Handle<Type>* right, | |
| 2635 Handle<Type>* result, | |
| 2636 Isolate* isolate) { | |
| 2637 TypeInfo left_typeinfo, right_typeinfo, result_typeinfo; | |
| 2638 BinaryOpStub::decode_types_from_minor_key( | |
| 2639 minor_key, &left_typeinfo, &right_typeinfo, &result_typeinfo); | |
| 2640 *left = TypeInfoToType(left_typeinfo, isolate); | |
| 2641 *right = TypeInfoToType(right_typeinfo, isolate); | |
| 2642 *result = TypeInfoToType(result_typeinfo, isolate); | |
| 2643 } | |
| 2644 | |
| 2645 | |
| 2646 static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, | |
| 2647 Token::Value op) { | |
| 2648 v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value); | |
| 2649 if (type.IsSmi()) return BinaryOpIC::SMI; | |
| 2650 if (type.IsInteger32()) { | |
| 2651 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
| 2652 return BinaryOpIC::INT32; | |
| 2653 } | |
| 2654 if (type.IsNumber()) return BinaryOpIC::NUMBER; | |
| 2655 if (type.IsString()) return BinaryOpIC::STRING; | |
| 2656 if (value->IsUndefined()) { | |
| 2657 if (op == Token::BIT_AND || | |
| 2658 op == Token::BIT_OR || | |
| 2659 op == Token::BIT_XOR || | |
| 2660 op == Token::SAR || | |
| 2661 op == Token::SHL || | |
| 2662 op == Token::SHR) { | |
| 2663 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
| 2664 return BinaryOpIC::INT32; | |
| 2665 } | |
| 2666 return BinaryOpIC::ODDBALL; | |
| 2667 } | |
| 2668 return BinaryOpIC::GENERIC; | |
| 2669 } | |
| 2670 | |
| 2671 | |
| 2672 static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, | |
| 2673 Handle<Object> value, | |
| 2674 Token::Value op) { | |
| 2675 BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op); | |
| 2676 if (old_type == BinaryOpIC::STRING) { | |
| 2677 if (new_type == BinaryOpIC::STRING) return new_type; | |
| 2678 return BinaryOpIC::GENERIC; | |
| 2679 } | |
| 2680 return Max(old_type, new_type); | |
| 2681 } | |
| 2682 | |
| 2683 | |
| 2684 #ifdef DEBUG | |
| 2685 static void TraceBinaryOp(BinaryOpIC::TypeInfo left, | |
| 2686 BinaryOpIC::TypeInfo right, | |
| 2687 Maybe<int32_t> fixed_right_arg, | |
| 2688 BinaryOpIC::TypeInfo result) { | |
| 2689 PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right)); | |
| 2690 if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value); | |
| 2691 PrintF("->%s", BinaryOpIC::GetName(result)); | |
| 2692 } | |
| 2693 #endif | |
| 2694 | |
| 2695 | |
| 2696 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { | |
| 2697 ASSERT(args.length() == 3); | |
| 2698 | |
| 2699 HandleScope scope(isolate); | |
| 2700 Handle<Object> left = args.at<Object>(0); | |
| 2701 Handle<Object> right = args.at<Object>(1); | |
| 2702 int key = args.smi_at(2); | |
| 2703 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); | |
| 2704 | |
| 2705 BinaryOpIC::TypeInfo previous_left, previous_right, previous_result; | |
| 2706 BinaryOpStub::decode_types_from_minor_key( | |
| 2707 key, &previous_left, &previous_right, &previous_result); | |
| 2708 | |
| 2709 BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); | |
| 2710 BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); | |
| 2711 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; | |
| 2712 | |
| 2713 // STRING is only used for ADD operations. | |
| 2714 if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && | |
| 2715 op != Token::ADD) { | |
| 2716 new_left = new_right = BinaryOpIC::GENERIC; | |
| 2717 } | |
| 2718 | |
| 2719 BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); | |
| 2720 BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); | |
| 2721 | |
| 2722 Maybe<int> previous_fixed_right_arg = | |
| 2723 BinaryOpStub::decode_fixed_right_arg_from_minor_key(key); | |
| 2724 | |
| 2725 int32_t value; | |
| 2726 bool new_has_fixed_right_arg = | |
| 2727 op == Token::MOD && | |
| 2728 right->ToInt32(&value) && | |
| 2729 BinaryOpStub::can_encode_arg_value(value) && | |
| 2730 (previous_overall == BinaryOpIC::UNINITIALIZED || | |
| 2731 (previous_fixed_right_arg.has_value && | |
| 2732 previous_fixed_right_arg.value == value)); | |
| 2733 Maybe<int32_t> new_fixed_right_arg( | |
| 2734 new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1); | |
| 2735 | |
| 2736 if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) { | |
| 2737 if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { | |
| 2738 if (op == Token::DIV || | |
| 2739 op == Token::MUL || | |
| 2740 op == Token::SHR || | |
| 2741 SmiValuesAre32Bits()) { | |
| 2742 // Arithmetic on two Smi inputs has yielded a heap number. | |
| 2743 // That is the only way to get here from the Smi stub. | |
| 2744 // With 32-bit Smis, all overflows give heap numbers, but with | |
| 2745 // 31-bit Smis, most operations overflow to int32 results. | |
| 2746 result_type = BinaryOpIC::NUMBER; | |
| 2747 } else { | |
| 2748 // Other operations on SMIs that overflow yield int32s. | |
| 2749 result_type = BinaryOpIC::INT32; | |
| 2750 } | |
| 2751 } | |
| 2752 if (new_overall == BinaryOpIC::INT32 && | |
| 2753 previous_overall == BinaryOpIC::INT32) { | |
| 2754 if (new_left == previous_left && new_right == previous_right) { | |
| 2755 result_type = BinaryOpIC::NUMBER; | |
| 2756 } | |
| 2757 } | |
| 2758 } | |
| 2759 | |
| 2760 BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg); | |
| 2761 Handle<Code> code = stub.GetCode(isolate); | |
| 2762 if (!code.is_null()) { | |
| 2763 #ifdef DEBUG | |
| 2764 if (FLAG_trace_ic) { | |
| 2765 PrintF("[BinaryOpIC in "); | |
| 2766 JavaScriptFrame::PrintTop(isolate, stdout, false, true); | |
| 2767 PrintF(" "); | |
| 2768 TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg, | |
| 2769 previous_result); | |
| 2770 PrintF(" => "); | |
| 2771 TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type); | |
| 2772 PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code)); | |
| 2773 } | |
| 2774 #endif | |
| 2775 BinaryOpIC ic(isolate); | |
| 2776 ic.patch(*code); | |
| 2777 | |
| 2778 // Activate inlined smi code. | |
| 2779 if (previous_overall == BinaryOpIC::UNINITIALIZED) { | |
| 2780 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); | |
| 2781 } | |
| 2782 } | |
| 2783 | |
| 2784 Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object()); | |
| 2785 Object* builtin = NULL; // Initialization calms down the compiler. | |
| 2786 switch (op) { | |
| 2787 case Token::ADD: | |
| 2788 builtin = builtins->javascript_builtin(Builtins::ADD); | |
| 2789 break; | |
| 2790 case Token::SUB: | |
| 2791 builtin = builtins->javascript_builtin(Builtins::SUB); | |
| 2792 break; | |
| 2793 case Token::MUL: | |
| 2794 builtin = builtins->javascript_builtin(Builtins::MUL); | |
| 2795 break; | |
| 2796 case Token::DIV: | |
| 2797 builtin = builtins->javascript_builtin(Builtins::DIV); | |
| 2798 break; | |
| 2799 case Token::MOD: | |
| 2800 builtin = builtins->javascript_builtin(Builtins::MOD); | |
| 2801 break; | |
| 2802 case Token::BIT_AND: | |
| 2803 builtin = builtins->javascript_builtin(Builtins::BIT_AND); | |
| 2804 break; | |
| 2805 case Token::BIT_OR: | |
| 2806 builtin = builtins->javascript_builtin(Builtins::BIT_OR); | |
| 2807 break; | |
| 2808 case Token::BIT_XOR: | |
| 2809 builtin = builtins->javascript_builtin(Builtins::BIT_XOR); | |
| 2810 break; | |
| 2811 case Token::SHR: | |
| 2812 builtin = builtins->javascript_builtin(Builtins::SHR); | |
| 2813 break; | |
| 2814 case Token::SAR: | |
| 2815 builtin = builtins->javascript_builtin(Builtins::SAR); | |
| 2816 break; | |
| 2817 case Token::SHL: | |
| 2818 builtin = builtins->javascript_builtin(Builtins::SHL); | |
| 2819 break; | |
| 2820 default: | |
| 2821 UNREACHABLE(); | |
| 2822 } | |
| 2823 | |
| 2824 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); | |
| 2825 | |
| 2826 bool caught_exception; | |
| 2827 Handle<Object> builtin_args[] = { right }; | |
| 2828 Handle<Object> result = Execution::Call(isolate, | |
| 2829 builtin_function, | |
| 2830 left, | |
| 2831 ARRAY_SIZE(builtin_args), | |
| 2832 builtin_args, | |
| 2833 &caught_exception); | |
| 2834 if (caught_exception) { | |
| 2835 return Failure::Exception(); | |
| 2836 } | |
| 2837 return *result; | |
| 2838 } | |
| 2839 | |
| 2840 | |
| 2841 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2644 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
| 2842 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2645 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| 2843 Code* code = NULL; | 2646 Code* code = NULL; |
| 2844 CHECK(stub.FindCodeInCache(&code, isolate)); | 2647 CHECK(stub.FindCodeInCache(&code, isolate)); |
| 2845 return code; | 2648 return code; |
| 2846 } | 2649 } |
| 2847 | 2650 |
| 2848 | 2651 |
| 2849 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2652 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
| 2850 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2653 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3128 } | 2931 } |
| 3129 | 2932 |
| 3130 | 2933 |
| 3131 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { | 2934 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { |
| 3132 UNREACHABLE(); | 2935 UNREACHABLE(); |
| 3133 CHECK(false); | 2936 CHECK(false); |
| 3134 return isolate->heap()->undefined_value(); | 2937 return isolate->heap()->undefined_value(); |
| 3135 } | 2938 } |
| 3136 | 2939 |
| 3137 | 2940 |
| 2941 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) { |
| 2942 switch (op) { |
| 2943 default: |
| 2944 UNREACHABLE(); |
| 2945 case Token::ADD: |
| 2946 return Builtins::ADD; |
| 2947 break; |
| 2948 case Token::SUB: |
| 2949 return Builtins::SUB; |
| 2950 break; |
| 2951 case Token::MUL: |
| 2952 return Builtins::MUL; |
| 2953 break; |
| 2954 case Token::DIV: |
| 2955 return Builtins::DIV; |
| 2956 break; |
| 2957 case Token::MOD: |
| 2958 return Builtins::MOD; |
| 2959 break; |
| 2960 case Token::BIT_OR: |
| 2961 return Builtins::BIT_OR; |
| 2962 break; |
| 2963 case Token::BIT_AND: |
| 2964 return Builtins::BIT_AND; |
| 2965 break; |
| 2966 case Token::BIT_XOR: |
| 2967 return Builtins::BIT_XOR; |
| 2968 break; |
| 2969 case Token::SAR: |
| 2970 return Builtins::SAR; |
| 2971 break; |
| 2972 case Token::SHR: |
| 2973 return Builtins::SHR; |
| 2974 break; |
| 2975 case Token::SHL: |
| 2976 return Builtins::SHL; |
| 2977 break; |
| 2978 } |
| 2979 } |
| 2980 |
| 2981 |
| 3138 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, | 2982 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, |
| 3139 Code::ExtraICState extra_ic_state) { | 2983 Code::ExtraICState extra_ic_state) { |
| 3140 ToBooleanStub stub(extra_ic_state); | 2984 ToBooleanStub stub(extra_ic_state); |
| 3141 bool to_boolean_value = stub.UpdateStatus(object); | 2985 bool to_boolean_value = stub.UpdateStatus(object); |
| 3142 Handle<Code> code = stub.GetCode(isolate()); | 2986 Handle<Code> code = stub.GetCode(isolate()); |
| 3143 set_target(*code); | 2987 set_target(*code); |
| 3144 return Smi::FromInt(to_boolean_value ? 1 : 0); | 2988 return Smi::FromInt(to_boolean_value ? 1 : 0); |
| 3145 } | 2989 } |
| 3146 | 2990 |
| 3147 | 2991 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3162 #undef ADDR | 3006 #undef ADDR |
| 3163 }; | 3007 }; |
| 3164 | 3008 |
| 3165 | 3009 |
| 3166 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 3010 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 3167 return IC_utilities[id]; | 3011 return IC_utilities[id]; |
| 3168 } | 3012 } |
| 3169 | 3013 |
| 3170 | 3014 |
| 3171 } } // namespace v8::internal | 3015 } } // namespace v8::internal |
| OLD | NEW |