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 2379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2390 GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); | 2390 GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); |
2391 GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT); | 2391 GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT); |
2392 GENERATE(Token::ADD, SMI, INT32, INT32, NO_OVERWRITE); | 2392 GENERATE(Token::ADD, SMI, INT32, INT32, NO_OVERWRITE); |
2393 GENERATE(Token::ADD, SMI, INT32, INT32, OVERWRITE_LEFT); | 2393 GENERATE(Token::ADD, SMI, INT32, INT32, OVERWRITE_LEFT); |
2394 GENERATE(Token::ADD, SMI, INT32, NUMBER, NO_OVERWRITE); | 2394 GENERATE(Token::ADD, SMI, INT32, NUMBER, NO_OVERWRITE); |
2395 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, NO_OVERWRITE); | 2395 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, NO_OVERWRITE); |
2396 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_LEFT); | 2396 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_LEFT); |
2397 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT); | 2397 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT); |
2398 GENERATE(Token::ADD, SMI, SMI, INT32, OVERWRITE_LEFT); | 2398 GENERATE(Token::ADD, SMI, SMI, INT32, OVERWRITE_LEFT); |
2399 GENERATE(Token::ADD, SMI, SMI, SMI, OVERWRITE_RIGHT); | 2399 GENERATE(Token::ADD, SMI, SMI, SMI, OVERWRITE_RIGHT); |
| 2400 GENERATE(Token::ADD, STRING, SMI, STRING, NO_OVERWRITE); |
| 2401 GENERATE(Token::ADD, SMI, STRING, STRING, NO_OVERWRITE); |
| 2402 GENERATE(Token::ADD, STRING, NUMBER, STRING, NO_OVERWRITE); |
| 2403 GENERATE(Token::ADD, NUMBER, STRING, STRING, NO_OVERWRITE); |
| 2404 GENERATE(Token::ADD, STRING, STRING, STRING, NO_OVERWRITE); |
2400 GENERATE(Token::BIT_AND, INT32, INT32, INT32, NO_OVERWRITE); | 2405 GENERATE(Token::BIT_AND, INT32, INT32, INT32, NO_OVERWRITE); |
2401 GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_LEFT); | 2406 GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_LEFT); |
2402 GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_RIGHT); | 2407 GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_RIGHT); |
2403 GENERATE(Token::BIT_AND, INT32, INT32, SMI, NO_OVERWRITE); | 2408 GENERATE(Token::BIT_AND, INT32, INT32, SMI, NO_OVERWRITE); |
2404 GENERATE(Token::BIT_AND, INT32, INT32, SMI, OVERWRITE_RIGHT); | 2409 GENERATE(Token::BIT_AND, INT32, INT32, SMI, OVERWRITE_RIGHT); |
2405 GENERATE(Token::BIT_AND, INT32, SMI, INT32, NO_OVERWRITE); | 2410 GENERATE(Token::BIT_AND, INT32, SMI, INT32, NO_OVERWRITE); |
2406 GENERATE(Token::BIT_AND, INT32, SMI, INT32, OVERWRITE_RIGHT); | 2411 GENERATE(Token::BIT_AND, INT32, SMI, INT32, OVERWRITE_RIGHT); |
2407 GENERATE(Token::BIT_AND, INT32, SMI, SMI, NO_OVERWRITE); | 2412 GENERATE(Token::BIT_AND, INT32, SMI, SMI, NO_OVERWRITE); |
2408 GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_LEFT); | 2413 GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_LEFT); |
2409 GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_RIGHT); | 2414 GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_RIGHT); |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2589 } | 2594 } |
2590 ASSERT_NE(GENERIC, result_kind); | 2595 ASSERT_NE(GENERIC, result_kind); |
2591 return KindToType(result_kind, isolate); | 2596 return KindToType(result_kind, isolate); |
2592 } | 2597 } |
2593 | 2598 |
2594 | 2599 |
2595 void BinaryOpIC::State::Print(StringStream* stream) const { | 2600 void BinaryOpIC::State::Print(StringStream* stream) const { |
2596 stream->Add("(%s", Token::Name(op_)); | 2601 stream->Add("(%s", Token::Name(op_)); |
2597 if (mode_ == OVERWRITE_LEFT) stream->Add("_ReuseLeft"); | 2602 if (mode_ == OVERWRITE_LEFT) stream->Add("_ReuseLeft"); |
2598 else if (mode_ == OVERWRITE_RIGHT) stream->Add("_ReuseRight"); | 2603 else if (mode_ == OVERWRITE_RIGHT) stream->Add("_ReuseRight"); |
| 2604 if (CanCreateAllocationMementos()) stream->Add("_CreateAllocationMementos"); |
2599 stream->Add(":%s*", KindToString(left_kind_)); | 2605 stream->Add(":%s*", KindToString(left_kind_)); |
2600 if (fixed_right_arg_.has_value) { | 2606 if (fixed_right_arg_.has_value) { |
2601 stream->Add("%d", fixed_right_arg_.value); | 2607 stream->Add("%d", fixed_right_arg_.value); |
2602 } else { | 2608 } else { |
2603 stream->Add("%s", KindToString(right_kind_)); | 2609 stream->Add("%s", KindToString(right_kind_)); |
2604 } | 2610 } |
2605 stream->Add("->%s)", KindToString(result_kind_)); | 2611 stream->Add("->%s)", KindToString(result_kind_)); |
2606 } | 2612 } |
2607 | 2613 |
2608 | 2614 |
(...skipping 19 matching lines...) Expand all Loading... |
2628 | 2634 |
2629 result_kind_ = UpdateKind(result, result_kind_); | 2635 result_kind_ = UpdateKind(result, result_kind_); |
2630 | 2636 |
2631 if (!Token::IsTruncatingBinaryOp(op_)) { | 2637 if (!Token::IsTruncatingBinaryOp(op_)) { |
2632 Kind input_kind = Max(left_kind_, right_kind_); | 2638 Kind input_kind = Max(left_kind_, right_kind_); |
2633 if (result_kind_ < input_kind && input_kind <= NUMBER) { | 2639 if (result_kind_ < input_kind && input_kind <= NUMBER) { |
2634 result_kind_ = input_kind; | 2640 result_kind_ = input_kind; |
2635 } | 2641 } |
2636 } | 2642 } |
2637 | 2643 |
| 2644 // We don't want to distinguish INT32 and NUMBER for string add (because |
| 2645 // NumberToString can't make use of this anyway). |
| 2646 if (left_kind_ == STRING && right_kind_ == INT32) { |
| 2647 ASSERT_EQ(STRING, result_kind_); |
| 2648 ASSERT_EQ(Token::ADD, op_); |
| 2649 right_kind_ = NUMBER; |
| 2650 } else if (right_kind_ == STRING && left_kind_ == INT32) { |
| 2651 ASSERT_EQ(STRING, result_kind_); |
| 2652 ASSERT_EQ(Token::ADD, op_); |
| 2653 left_kind_ = NUMBER; |
| 2654 } |
| 2655 |
2638 // Reset overwrite mode unless we can actually make use of it, or may be able | 2656 // Reset overwrite mode unless we can actually make use of it, or may be able |
2639 // to make use of it at some point in the future. | 2657 // to make use of it at some point in the future. |
2640 if ((mode_ == OVERWRITE_LEFT && left_kind_ > NUMBER) || | 2658 if ((mode_ == OVERWRITE_LEFT && left_kind_ > NUMBER) || |
2641 (mode_ == OVERWRITE_RIGHT && right_kind_ > NUMBER) || | 2659 (mode_ == OVERWRITE_RIGHT && right_kind_ > NUMBER) || |
2642 result_kind_ > NUMBER) { | 2660 result_kind_ > NUMBER) { |
2643 mode_ = NO_OVERWRITE; | 2661 mode_ = NO_OVERWRITE; |
2644 } | 2662 } |
2645 | 2663 |
2646 if (old_extra_ic_state == GetExtraICState()) { | 2664 if (old_extra_ic_state == GetExtraICState()) { |
2647 // Tagged operations can lead to non-truncating HChanges | 2665 // Tagged operations can lead to non-truncating HChanges |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2713 case SMI: type = Type::Smi(); break; | 2731 case SMI: type = Type::Smi(); break; |
2714 case INT32: type = Type::Signed32(); break; | 2732 case INT32: type = Type::Signed32(); break; |
2715 case NUMBER: type = Type::Number(); break; | 2733 case NUMBER: type = Type::Number(); break; |
2716 case STRING: type = Type::String(); break; | 2734 case STRING: type = Type::String(); break; |
2717 case GENERIC: type = Type::Any(); break; | 2735 case GENERIC: type = Type::Any(); break; |
2718 } | 2736 } |
2719 return handle(type, isolate); | 2737 return handle(type, isolate); |
2720 } | 2738 } |
2721 | 2739 |
2722 | 2740 |
2723 MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) { | 2741 MaybeObject* BinaryOpIC::Transition(Handle<AllocationSite> allocation_site, |
| 2742 Handle<Object> left, |
| 2743 Handle<Object> right) { |
2724 State state(target()->extended_extra_ic_state()); | 2744 State state(target()->extended_extra_ic_state()); |
2725 | 2745 |
2726 // Compute the actual result using the builtin for the binary operation. | 2746 // Compute the actual result using the builtin for the binary operation. |
2727 Object* builtin = isolate()->js_builtins_object()->javascript_builtin( | 2747 Object* builtin = isolate()->js_builtins_object()->javascript_builtin( |
2728 TokenToJSBuiltin(state.op())); | 2748 TokenToJSBuiltin(state.op())); |
2729 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate()); | 2749 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate()); |
2730 bool caught_exception; | 2750 bool caught_exception; |
2731 Handle<Object> result = Execution::Call( | 2751 Handle<Object> result = Execution::Call( |
2732 isolate(), function, left, 1, &right, &caught_exception); | 2752 isolate(), function, left, 1, &right, &caught_exception); |
2733 if (caught_exception) return Failure::Exception(); | 2753 if (caught_exception) return Failure::Exception(); |
2734 | 2754 |
2735 // Compute the new state. | 2755 // Compute the new state. |
2736 State old_state = state; | 2756 State old_state = state; |
2737 state.Update(left, right, result); | 2757 state.Update(left, right, result); |
2738 | 2758 |
2739 // Install the new stub. | 2759 // Check if we have a string operation here. |
2740 BinaryOpICStub stub(state); | 2760 Handle<Code> target; |
2741 set_target(*stub.GetCode(isolate())); | 2761 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) { |
| 2762 // Setup the allocation site on-demand. |
| 2763 if (allocation_site.is_null()) { |
| 2764 allocation_site = isolate()->factory()->NewAllocationSite(); |
| 2765 } |
| 2766 |
| 2767 // Install the stub with an allocation site. |
| 2768 BinaryOpICWithAllocationSiteStub stub(state); |
| 2769 target = stub.GetCodeCopyFromTemplate(isolate(), allocation_site); |
| 2770 |
| 2771 // Sanity check the trampoline stub. |
| 2772 ASSERT_EQ(*allocation_site, target->FindFirstAllocationSite()); |
| 2773 } else { |
| 2774 // Install the generic stub. |
| 2775 BinaryOpICStub stub(state); |
| 2776 target = stub.GetCode(isolate()); |
| 2777 |
| 2778 // Sanity check the generic stub. |
| 2779 ASSERT_EQ(NULL, target->FindFirstAllocationSite()); |
| 2780 } |
| 2781 set_target(*target); |
2742 | 2782 |
2743 if (FLAG_trace_ic) { | 2783 if (FLAG_trace_ic) { |
2744 char buffer[150]; | 2784 char buffer[150]; |
2745 NoAllocationStringAllocator allocator( | 2785 NoAllocationStringAllocator allocator( |
2746 buffer, static_cast<unsigned>(sizeof(buffer))); | 2786 buffer, static_cast<unsigned>(sizeof(buffer))); |
2747 StringStream stream(&allocator); | 2787 StringStream stream(&allocator); |
2748 stream.Add("[BinaryOpIC"); | 2788 stream.Add("[BinaryOpIC"); |
2749 old_state.Print(&stream); | 2789 old_state.Print(&stream); |
2750 stream.Add(" => "); | 2790 stream.Add(" => "); |
2751 state.Print(&stream); | 2791 state.Print(&stream); |
2752 stream.Add(" @ %p <- ", static_cast<void*>(*target())); | 2792 stream.Add(" @ %p <- ", static_cast<void*>(*target)); |
2753 stream.OutputToStdOut(); | 2793 stream.OutputToStdOut(); |
2754 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); | 2794 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| 2795 if (!allocation_site.is_null()) { |
| 2796 PrintF(" using allocation site %p", static_cast<void*>(*allocation_site)); |
| 2797 } |
2755 PrintF("]\n"); | 2798 PrintF("]\n"); |
2756 } | 2799 } |
2757 | 2800 |
2758 // Patch the inlined smi code as necessary. | 2801 // Patch the inlined smi code as necessary. |
2759 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) { | 2802 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) { |
2760 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); | 2803 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
2761 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) { | 2804 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) { |
2762 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); | 2805 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK); |
2763 } | 2806 } |
2764 | 2807 |
2765 return *result; | 2808 return *result; |
2766 } | 2809 } |
2767 | 2810 |
2768 | 2811 |
2769 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { | 2812 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) { |
2770 HandleScope scope(isolate); | 2813 HandleScope scope(isolate); |
2771 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft); | 2814 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft); |
2772 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight); | 2815 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight); |
2773 BinaryOpIC ic(isolate); | 2816 BinaryOpIC ic(isolate); |
2774 return ic.Transition(left, right); | 2817 return ic.Transition(Handle<AllocationSite>::null(), left, right); |
2775 } | 2818 } |
2776 | 2819 |
2777 | 2820 |
| 2821 RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_MissWithAllocationSite) { |
| 2822 HandleScope scope(isolate); |
| 2823 Handle<AllocationSite> allocation_site = args.at<AllocationSite>( |
| 2824 BinaryOpWithAllocationSiteStub::kAllocationSite); |
| 2825 Handle<Object> left = args.at<Object>( |
| 2826 BinaryOpWithAllocationSiteStub::kLeft); |
| 2827 Handle<Object> right = args.at<Object>( |
| 2828 BinaryOpWithAllocationSiteStub::kRight); |
| 2829 BinaryOpIC ic(isolate); |
| 2830 return ic.Transition(allocation_site, left, right); |
| 2831 } |
| 2832 |
| 2833 |
2778 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2834 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
2779 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2835 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
2780 Code* code = NULL; | 2836 Code* code = NULL; |
2781 CHECK(stub.FindCodeInCache(&code, isolate)); | 2837 CHECK(stub.FindCodeInCache(&code, isolate)); |
2782 return code; | 2838 return code; |
2783 } | 2839 } |
2784 | 2840 |
2785 | 2841 |
2786 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2842 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
2787 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2843 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3138 #undef ADDR | 3194 #undef ADDR |
3139 }; | 3195 }; |
3140 | 3196 |
3141 | 3197 |
3142 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 3198 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
3143 return IC_utilities[id]; | 3199 return IC_utilities[id]; |
3144 } | 3200 } |
3145 | 3201 |
3146 | 3202 |
3147 } } // namespace v8::internal | 3203 } } // namespace v8::internal |
OLD | NEW |