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 |