| 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 2519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2530 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); | 2530 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); |
| 2531 return Runtime::SetObjectProperty(isolate, | 2531 return Runtime::SetObjectProperty(isolate, |
| 2532 object, | 2532 object, |
| 2533 key, | 2533 key, |
| 2534 value, | 2534 value, |
| 2535 NONE, | 2535 NONE, |
| 2536 strict_mode); | 2536 strict_mode); |
| 2537 } | 2537 } |
| 2538 | 2538 |
| 2539 | 2539 |
| 2540 void BinaryOpIC::patch(Code* code) { | |
| 2541 set_target(code); | |
| 2542 } | |
| 2543 | |
| 2544 | |
| 2545 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 2540 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| 2546 switch (type_info) { | 2541 switch (type_info) { |
| 2547 case UNINITIALIZED: return "Uninitialized"; | 2542 case UNINITIALIZED: return "Uninitialized"; |
| 2548 case SMI: return "Smi"; | 2543 case SMI: return "Smi"; |
| 2549 case INT32: return "Int32"; | 2544 case INT32: return "Int32"; |
| 2550 case NUMBER: return "Number"; | 2545 case NUMBER: return "Number"; |
| 2551 case ODDBALL: return "Oddball"; | 2546 case ODDBALL: return "Oddball"; |
| 2552 case STRING: return "String"; | 2547 case STRING: return "String"; |
| 2553 case GENERIC: return "Generic"; | 2548 case GENERIC: return "Generic"; |
| 2554 default: return "Invalid"; | 2549 default: return "Invalid"; |
| 2555 } | 2550 } |
| 2556 } | 2551 } |
| 2557 | 2552 |
| 2558 | 2553 |
| 2559 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { | 2554 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { |
| 2560 switch (type_info) { | 2555 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); |
| 2561 case UNINITIALIZED: | 2556 BinaryOpStub stub(extra_ic_state); |
| 2562 return ::v8::internal::UNINITIALIZED; | 2557 |
| 2563 case SMI: | 2558 bool smi_was_enabled = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2564 case INT32: | 2559 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2565 case NUMBER: | 2560 |
| 2566 case ODDBALL: | 2561 Maybe<Handle<Object> > result = stub.Result(left, right, isolate()); |
| 2567 case STRING: | 2562 |
| 2568 return MONOMORPHIC; | 2563 #ifdef DEBUG |
| 2569 case GENERIC: | 2564 if (FLAG_trace_ic) { |
| 2570 return ::v8::internal::GENERIC; | 2565 char buffer[100]; |
| 2566 NoAllocationStringAllocator allocator(buffer, |
| 2567 static_cast<unsigned>(sizeof(buffer))); |
| 2568 StringStream stream(&allocator); |
| 2569 stream.Add("["); |
| 2570 stub.PrintName(&stream); |
| 2571 |
| 2572 stub.UpdateStatus(left, right, result); |
| 2573 |
| 2574 stream.Add(" => "); |
| 2575 stub.PrintState(&stream); |
| 2576 stream.Add(" "); |
| 2577 stream.OutputToStdOut(); |
| 2578 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate()))); |
| 2579 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 2580 PrintF("]\n"); |
| 2581 } else { |
| 2582 stub.UpdateStatus(left, right, result); |
| 2571 } | 2583 } |
| 2572 UNREACHABLE(); | 2584 #else |
| 2573 return ::v8::internal::UNINITIALIZED; | 2585 stub.UpdateStatus(left, right, result); |
| 2586 #endif |
| 2587 |
| 2588 Handle<Code> code = stub.GetCode(isolate()); |
| 2589 set_target(*code); |
| 2590 |
| 2591 bool enable_smi = stub.GetLeftType(isolate())->Maybe(Type::Smi()) && |
| 2592 stub.GetRightType(isolate())->Maybe(Type::Smi()); |
| 2593 |
| 2594 if (!smi_was_enabled && enable_smi) { |
| 2595 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
| 2596 } else if (smi_was_enabled && !enable_smi) { |
| 2597 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); |
| 2598 } |
| 2599 |
| 2600 return result.has_value |
| 2601 ? static_cast<MaybeObject*>(*result.value) |
| 2602 : Failure::Exception(); |
| 2574 } | 2603 } |
| 2575 | 2604 |
| 2576 | 2605 |
| 2577 Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type, | 2606 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { |
| 2578 Isolate* isolate) { | 2607 HandleScope scope(isolate); |
| 2579 switch (binary_type) { | 2608 Handle<Object> left = args.at<Object>(0); |
| 2580 case UNINITIALIZED: | 2609 Handle<Object> right = args.at<Object>(1); |
| 2581 return handle(Type::None(), isolate); | 2610 BinaryOpIC ic(isolate); |
| 2582 case SMI: | 2611 return ic.Transition(left, right); |
| 2583 return handle(Type::Smi(), isolate); | |
| 2584 case INT32: | |
| 2585 return handle(Type::Signed32(), isolate); | |
| 2586 case NUMBER: | |
| 2587 return handle(Type::Number(), isolate); | |
| 2588 case ODDBALL: | |
| 2589 return handle(Type::Optional( | |
| 2590 handle(Type::Union( | |
| 2591 handle(Type::Number(), isolate), | |
| 2592 handle(Type::String(), isolate)), isolate)), isolate); | |
| 2593 case STRING: | |
| 2594 return handle(Type::String(), isolate); | |
| 2595 case GENERIC: | |
| 2596 return handle(Type::Any(), isolate); | |
| 2597 } | |
| 2598 UNREACHABLE(); | |
| 2599 return handle(Type::Any(), isolate); | |
| 2600 } | 2612 } |
| 2601 | 2613 |
| 2602 | 2614 |
| 2603 void BinaryOpIC::StubInfoToType(int minor_key, | |
| 2604 Handle<Type>* left, | |
| 2605 Handle<Type>* right, | |
| 2606 Handle<Type>* result, | |
| 2607 Isolate* isolate) { | |
| 2608 TypeInfo left_typeinfo, right_typeinfo, result_typeinfo; | |
| 2609 BinaryOpStub::decode_types_from_minor_key( | |
| 2610 minor_key, &left_typeinfo, &right_typeinfo, &result_typeinfo); | |
| 2611 *left = TypeInfoToType(left_typeinfo, isolate); | |
| 2612 *right = TypeInfoToType(right_typeinfo, isolate); | |
| 2613 *result = TypeInfoToType(result_typeinfo, isolate); | |
| 2614 } | |
| 2615 | |
| 2616 | |
| 2617 static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, | |
| 2618 Token::Value op) { | |
| 2619 v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value); | |
| 2620 if (type.IsSmi()) return BinaryOpIC::SMI; | |
| 2621 if (type.IsInteger32()) { | |
| 2622 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
| 2623 return BinaryOpIC::INT32; | |
| 2624 } | |
| 2625 if (type.IsNumber()) return BinaryOpIC::NUMBER; | |
| 2626 if (type.IsString()) return BinaryOpIC::STRING; | |
| 2627 if (value->IsUndefined()) { | |
| 2628 if (op == Token::BIT_AND || | |
| 2629 op == Token::BIT_OR || | |
| 2630 op == Token::BIT_XOR || | |
| 2631 op == Token::SAR || | |
| 2632 op == Token::SHL || | |
| 2633 op == Token::SHR) { | |
| 2634 if (SmiValuesAre32Bits()) return BinaryOpIC::SMI; | |
| 2635 return BinaryOpIC::INT32; | |
| 2636 } | |
| 2637 return BinaryOpIC::ODDBALL; | |
| 2638 } | |
| 2639 return BinaryOpIC::GENERIC; | |
| 2640 } | |
| 2641 | |
| 2642 | |
| 2643 static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, | |
| 2644 Handle<Object> value, | |
| 2645 Token::Value op) { | |
| 2646 BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op); | |
| 2647 if (old_type == BinaryOpIC::STRING) { | |
| 2648 if (new_type == BinaryOpIC::STRING) return new_type; | |
| 2649 return BinaryOpIC::GENERIC; | |
| 2650 } | |
| 2651 return Max(old_type, new_type); | |
| 2652 } | |
| 2653 | |
| 2654 | |
| 2655 #ifdef DEBUG | |
| 2656 static void TraceBinaryOp(BinaryOpIC::TypeInfo left, | |
| 2657 BinaryOpIC::TypeInfo right, | |
| 2658 Maybe<int32_t> fixed_right_arg, | |
| 2659 BinaryOpIC::TypeInfo result) { | |
| 2660 PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right)); | |
| 2661 if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value); | |
| 2662 PrintF("->%s", BinaryOpIC::GetName(result)); | |
| 2663 } | |
| 2664 #endif | |
| 2665 | |
| 2666 | |
| 2667 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { | |
| 2668 ASSERT(args.length() == 3); | |
| 2669 | |
| 2670 HandleScope scope(isolate); | |
| 2671 Handle<Object> left = args.at<Object>(0); | |
| 2672 Handle<Object> right = args.at<Object>(1); | |
| 2673 int key = args.smi_at(2); | |
| 2674 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); | |
| 2675 | |
| 2676 BinaryOpIC::TypeInfo previous_left, previous_right, previous_result; | |
| 2677 BinaryOpStub::decode_types_from_minor_key( | |
| 2678 key, &previous_left, &previous_right, &previous_result); | |
| 2679 | |
| 2680 BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); | |
| 2681 BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); | |
| 2682 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; | |
| 2683 | |
| 2684 // STRING is only used for ADD operations. | |
| 2685 if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && | |
| 2686 op != Token::ADD) { | |
| 2687 new_left = new_right = BinaryOpIC::GENERIC; | |
| 2688 } | |
| 2689 | |
| 2690 BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); | |
| 2691 BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); | |
| 2692 | |
| 2693 Maybe<int> previous_fixed_right_arg = | |
| 2694 BinaryOpStub::decode_fixed_right_arg_from_minor_key(key); | |
| 2695 | |
| 2696 int32_t value; | |
| 2697 bool new_has_fixed_right_arg = | |
| 2698 op == Token::MOD && | |
| 2699 right->ToInt32(&value) && | |
| 2700 BinaryOpStub::can_encode_arg_value(value) && | |
| 2701 (previous_overall == BinaryOpIC::UNINITIALIZED || | |
| 2702 (previous_fixed_right_arg.has_value && | |
| 2703 previous_fixed_right_arg.value == value)); | |
| 2704 Maybe<int32_t> new_fixed_right_arg( | |
| 2705 new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1); | |
| 2706 | |
| 2707 if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) { | |
| 2708 if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { | |
| 2709 if (op == Token::DIV || | |
| 2710 op == Token::MUL || | |
| 2711 op == Token::SHR || | |
| 2712 SmiValuesAre32Bits()) { | |
| 2713 // Arithmetic on two Smi inputs has yielded a heap number. | |
| 2714 // That is the only way to get here from the Smi stub. | |
| 2715 // With 32-bit Smis, all overflows give heap numbers, but with | |
| 2716 // 31-bit Smis, most operations overflow to int32 results. | |
| 2717 result_type = BinaryOpIC::NUMBER; | |
| 2718 } else { | |
| 2719 // Other operations on SMIs that overflow yield int32s. | |
| 2720 result_type = BinaryOpIC::INT32; | |
| 2721 } | |
| 2722 } | |
| 2723 if (new_overall == BinaryOpIC::INT32 && | |
| 2724 previous_overall == BinaryOpIC::INT32) { | |
| 2725 if (new_left == previous_left && new_right == previous_right) { | |
| 2726 result_type = BinaryOpIC::NUMBER; | |
| 2727 } | |
| 2728 } | |
| 2729 } | |
| 2730 | |
| 2731 BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg); | |
| 2732 Handle<Code> code = stub.GetCode(isolate); | |
| 2733 if (!code.is_null()) { | |
| 2734 #ifdef DEBUG | |
| 2735 if (FLAG_trace_ic) { | |
| 2736 PrintF("[BinaryOpIC in "); | |
| 2737 JavaScriptFrame::PrintTop(isolate, stdout, false, true); | |
| 2738 PrintF(" "); | |
| 2739 TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg, | |
| 2740 previous_result); | |
| 2741 PrintF(" => "); | |
| 2742 TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type); | |
| 2743 PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code)); | |
| 2744 } | |
| 2745 #endif | |
| 2746 BinaryOpIC ic(isolate); | |
| 2747 ic.patch(*code); | |
| 2748 | |
| 2749 // Activate inlined smi code. | |
| 2750 if (previous_overall == BinaryOpIC::UNINITIALIZED) { | |
| 2751 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); | |
| 2752 } | |
| 2753 } | |
| 2754 | |
| 2755 Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object()); | |
| 2756 Object* builtin = NULL; // Initialization calms down the compiler. | |
| 2757 switch (op) { | |
| 2758 case Token::ADD: | |
| 2759 builtin = builtins->javascript_builtin(Builtins::ADD); | |
| 2760 break; | |
| 2761 case Token::SUB: | |
| 2762 builtin = builtins->javascript_builtin(Builtins::SUB); | |
| 2763 break; | |
| 2764 case Token::MUL: | |
| 2765 builtin = builtins->javascript_builtin(Builtins::MUL); | |
| 2766 break; | |
| 2767 case Token::DIV: | |
| 2768 builtin = builtins->javascript_builtin(Builtins::DIV); | |
| 2769 break; | |
| 2770 case Token::MOD: | |
| 2771 builtin = builtins->javascript_builtin(Builtins::MOD); | |
| 2772 break; | |
| 2773 case Token::BIT_AND: | |
| 2774 builtin = builtins->javascript_builtin(Builtins::BIT_AND); | |
| 2775 break; | |
| 2776 case Token::BIT_OR: | |
| 2777 builtin = builtins->javascript_builtin(Builtins::BIT_OR); | |
| 2778 break; | |
| 2779 case Token::BIT_XOR: | |
| 2780 builtin = builtins->javascript_builtin(Builtins::BIT_XOR); | |
| 2781 break; | |
| 2782 case Token::SHR: | |
| 2783 builtin = builtins->javascript_builtin(Builtins::SHR); | |
| 2784 break; | |
| 2785 case Token::SAR: | |
| 2786 builtin = builtins->javascript_builtin(Builtins::SAR); | |
| 2787 break; | |
| 2788 case Token::SHL: | |
| 2789 builtin = builtins->javascript_builtin(Builtins::SHL); | |
| 2790 break; | |
| 2791 default: | |
| 2792 UNREACHABLE(); | |
| 2793 } | |
| 2794 | |
| 2795 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); | |
| 2796 | |
| 2797 bool caught_exception; | |
| 2798 Handle<Object> builtin_args[] = { right }; | |
| 2799 Handle<Object> result = Execution::Call(isolate, | |
| 2800 builtin_function, | |
| 2801 left, | |
| 2802 ARRAY_SIZE(builtin_args), | |
| 2803 builtin_args, | |
| 2804 &caught_exception); | |
| 2805 if (caught_exception) { | |
| 2806 return Failure::Exception(); | |
| 2807 } | |
| 2808 return *result; | |
| 2809 } | |
| 2810 | |
| 2811 | |
| 2812 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2615 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
| 2813 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2616 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| 2814 Code* code = NULL; | 2617 Code* code = NULL; |
| 2815 CHECK(stub.FindCodeInCache(&code, isolate)); | 2618 CHECK(stub.FindCodeInCache(&code, isolate)); |
| 2816 return code; | 2619 return code; |
| 2817 } | 2620 } |
| 2818 | 2621 |
| 2819 | 2622 |
| 2820 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2623 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
| 2821 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2624 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3099 } | 2902 } |
| 3100 | 2903 |
| 3101 | 2904 |
| 3102 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { | 2905 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { |
| 3103 UNREACHABLE(); | 2906 UNREACHABLE(); |
| 3104 CHECK(false); | 2907 CHECK(false); |
| 3105 return isolate->heap()->undefined_value(); | 2908 return isolate->heap()->undefined_value(); |
| 3106 } | 2909 } |
| 3107 | 2910 |
| 3108 | 2911 |
| 2912 Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) { |
| 2913 switch (op) { |
| 2914 default: |
| 2915 UNREACHABLE(); |
| 2916 case Token::ADD: |
| 2917 return Builtins::ADD; |
| 2918 break; |
| 2919 case Token::SUB: |
| 2920 return Builtins::SUB; |
| 2921 break; |
| 2922 case Token::MUL: |
| 2923 return Builtins::MUL; |
| 2924 break; |
| 2925 case Token::DIV: |
| 2926 return Builtins::DIV; |
| 2927 break; |
| 2928 case Token::MOD: |
| 2929 return Builtins::MOD; |
| 2930 break; |
| 2931 case Token::BIT_OR: |
| 2932 return Builtins::BIT_OR; |
| 2933 break; |
| 2934 case Token::BIT_AND: |
| 2935 return Builtins::BIT_AND; |
| 2936 break; |
| 2937 case Token::BIT_XOR: |
| 2938 return Builtins::BIT_XOR; |
| 2939 break; |
| 2940 case Token::SAR: |
| 2941 return Builtins::SAR; |
| 2942 break; |
| 2943 case Token::SHR: |
| 2944 return Builtins::SHR; |
| 2945 break; |
| 2946 case Token::SHL: |
| 2947 return Builtins::SHL; |
| 2948 break; |
| 2949 } |
| 2950 } |
| 2951 |
| 2952 |
| 3109 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, | 2953 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, |
| 3110 Code::ExtraICState extra_ic_state) { | 2954 Code::ExtraICState extra_ic_state) { |
| 3111 ToBooleanStub stub(extra_ic_state); | 2955 ToBooleanStub stub(extra_ic_state); |
| 3112 bool to_boolean_value = stub.UpdateStatus(object); | 2956 bool to_boolean_value = stub.UpdateStatus(object); |
| 3113 Handle<Code> code = stub.GetCode(isolate()); | 2957 Handle<Code> code = stub.GetCode(isolate()); |
| 3114 set_target(*code); | 2958 set_target(*code); |
| 3115 return Smi::FromInt(to_boolean_value ? 1 : 0); | 2959 return Smi::FromInt(to_boolean_value ? 1 : 0); |
| 3116 } | 2960 } |
| 3117 | 2961 |
| 3118 | 2962 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3133 #undef ADDR | 2977 #undef ADDR |
| 3134 }; | 2978 }; |
| 3135 | 2979 |
| 3136 | 2980 |
| 3137 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2981 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 3138 return IC_utilities[id]; | 2982 return IC_utilities[id]; |
| 3139 } | 2983 } |
| 3140 | 2984 |
| 3141 | 2985 |
| 3142 } } // namespace v8::internal | 2986 } } // namespace v8::internal |
| OLD | NEW |