Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: src/ic.cc

Issue 24072013: Hydrogenisation of binops (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: fix overwrite mode & better result typefeedback Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698