Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/code-stubs.h" | 5 #include "src/code-stubs.h" |
| 6 | 6 |
| 7 #include "src/bailout-reason.h" | 7 #include "src/bailout-reason.h" |
| 8 #include "src/crankshaft/hydrogen.h" | 8 #include "src/crankshaft/hydrogen.h" |
| 9 #include "src/crankshaft/lithium.h" | 9 #include "src/crankshaft/lithium.h" |
| 10 #include "src/field-index.h" | 10 #include "src/field-index.h" |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 CompilationInfo* info() { return info_; } | 71 CompilationInfo* info() { return info_; } |
| 72 CodeStub* stub() { return code_stub_; } | 72 CodeStub* stub() { return code_stub_; } |
| 73 HContext* context() { return context_; } | 73 HContext* context() { return context_; } |
| 74 Isolate* isolate() { return info_->isolate(); } | 74 Isolate* isolate() { return info_->isolate(); } |
| 75 | 75 |
| 76 HLoadNamedField* BuildLoadNamedField(HValue* object, FieldIndex index); | 76 HLoadNamedField* BuildLoadNamedField(HValue* object, FieldIndex index); |
| 77 void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index, | 77 void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index, |
| 78 Representation representation, | 78 Representation representation, |
| 79 bool transition_to_field); | 79 bool transition_to_field); |
| 80 | 80 |
| 81 HValue* BuildPushElement(HValue* object, HValue* value, ElementsKind kind); | |
| 82 | |
| 81 enum ArgumentClass { | 83 enum ArgumentClass { |
| 82 NONE, | 84 NONE, |
| 83 SINGLE, | 85 SINGLE, |
| 84 MULTIPLE | 86 MULTIPLE |
| 85 }; | 87 }; |
| 86 | 88 |
| 87 HValue* UnmappedCase(HValue* elements, HValue* key, HValue* value); | 89 HValue* UnmappedCase(HValue* elements, HValue* key, HValue* value); |
| 88 HValue* EmitKeyedSloppyArguments(HValue* receiver, HValue* key, | 90 HValue* EmitKeyedSloppyArguments(HValue* receiver, HValue* key, |
| 89 HValue* value); | 91 HValue* value); |
| 90 | 92 |
| (...skipping 682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 773 HObjectAccess::ForContextSlot(slot_index), | 775 HObjectAccess::ForContextSlot(slot_index), |
| 774 GetParameter(2), STORE_TO_INITIALIZED_ENTRY); | 776 GetParameter(2), STORE_TO_INITIALIZED_ENTRY); |
| 775 return GetParameter(2); | 777 return GetParameter(2); |
| 776 } | 778 } |
| 777 | 779 |
| 778 | 780 |
| 779 Handle<Code> StoreScriptContextFieldStub::GenerateCode() { | 781 Handle<Code> StoreScriptContextFieldStub::GenerateCode() { |
| 780 return DoGenerateCode(this); | 782 return DoGenerateCode(this); |
| 781 } | 783 } |
| 782 | 784 |
| 785 HValue* CodeStubGraphBuilderBase::BuildPushElement(HValue* object, | |
| 786 HValue* value, | |
| 787 ElementsKind kind) { | |
| 788 HValue* length = Add<HLoadNamedField>(object, nullptr, | |
| 789 HObjectAccess::ForArrayLength(kind)); | |
| 790 HValue* key = length; | |
| 791 HValue* elements = Add<HLoadNamedField>(object, nullptr, | |
| 792 HObjectAccess::ForElementsPointer()); | |
| 793 elements = BuildCheckForCapacityGrow(object, elements, kind, length, key, | |
| 794 true, STORE); | |
| 795 AddElementAccess(elements, key, value, object, nullptr, kind, STORE); | |
| 796 return key; | |
| 797 } | |
| 798 | |
| 799 template <> | |
| 800 HValue* CodeStubGraphBuilder<FastArrayPushStub>::BuildCodeStub() { | |
| 801 // TODO(verwaest): Fix deoptimizer messages. | |
| 802 HValue* argc = GetArgumentsLength(); | |
| 803 IfBuilder arg_check(this); | |
| 804 arg_check.If<HCompareNumericAndBranch>(argc, graph()->GetConstant1(), | |
| 805 Token::NE); | |
| 806 arg_check.ThenDeopt(Deoptimizer::kFastArrayPushFailed); | |
| 807 arg_check.End(); | |
| 808 | |
| 809 HInstruction* argument_elements = Add<HArgumentsElements>(false, false); | |
| 810 HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc, | |
| 811 graph()->GetConstantMinus1()); | |
| 812 HInstruction* value = | |
| 813 Add<HAccessArgumentsAt>(argument_elements, argc, graph()->GetConstant0()); | |
| 814 | |
| 815 BuildCheckHeapObject(object); | |
| 816 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); | |
| 817 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_ARRAY); | |
| 818 | |
| 819 // Disallow pushing onto prototypes. It might be the JSArray prototype. | |
| 820 // Disallow pushing onto non-extensible objects. | |
| 821 { | |
| 822 HValue* bit_field2 = | |
| 823 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); | |
| 824 HValue* mask = | |
| 825 Add<HConstant>(static_cast<int>(Map::IsPrototypeMapBits::kMask) | | |
| 826 (1 << Map::kIsExtensible)); | |
| 827 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field2, mask); | |
|
Jakob Kummerow
2016/03/21 15:12:51
nit: call it "bits", could be more than one.
| |
| 828 IfBuilder check(this); | |
| 829 check.If<HCompareNumericAndBranch>( | |
| 830 bit, Add<HConstant>(1 << Map::kIsExtensible), Token::NE); | |
| 831 check.ThenDeopt(Deoptimizer::kFastArrayPushFailed); | |
| 832 check.End(); | |
| 833 } | |
| 834 | |
| 835 // Disallow pushing onto observed objects. | |
| 836 { | |
| 837 HValue* bit_field = | |
| 838 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField()); | |
| 839 HValue* mask = Add<HConstant>(1 << Map::kIsObserved); | |
| 840 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field, mask); | |
| 841 IfBuilder check(this); | |
| 842 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); | |
| 843 check.ThenDeopt(Deoptimizer::kFastArrayPushFailed); | |
| 844 check.End(); | |
| 845 } | |
| 846 | |
| 847 // Disallow pushing onto arrays in dictionary named property mode. We need to | |
| 848 // figure out whether the length property is still writable. | |
| 849 { | |
| 850 HValue* bit_field3 = | |
| 851 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3()); | |
| 852 HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask)); | |
| 853 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask); | |
| 854 IfBuilder check(this); | |
| 855 check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); | |
| 856 check.ThenDeopt(Deoptimizer::kFastArrayPushFailed); | |
| 857 check.End(); | |
| 858 } | |
| 859 | |
| 860 // Check whether the length property is writable. The length property is the | |
| 861 // only default named properties on arrays. It's nonconfigurable, hence is | |
|
Jakob Kummerow
2016/03/21 15:12:51
nit: s/properties/property/
| |
| 862 // guaranteed to stay the first property. | |
| 863 { | |
| 864 HValue* descriptors = | |
| 865 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors()); | |
| 866 HValue* details = Add<HLoadKeyed>( | |
| 867 descriptors, Add<HConstant>(DescriptorArray::ToDetailsIndex(0)), | |
| 868 nullptr, nullptr, FAST_SMI_ELEMENTS); | |
| 869 HValue* mask = | |
| 870 Add<HConstant>(READ_ONLY << PropertyDetails::AttributesField::kShift); | |
| 871 HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, details, mask); | |
| 872 IfBuilder writable(this); | |
|
Jakob Kummerow
2016/03/21 15:12:51
nit: this should be called "readonly" (to make the
| |
| 873 writable.If<HCompareNumericAndBranch>(bit, mask, Token::EQ); | |
| 874 writable.ThenDeopt(Deoptimizer::kFastArrayPushFailed); | |
| 875 writable.End(); | |
| 876 } | |
| 877 | |
| 878 environment()->Push(map); | |
| 879 LoopBuilder check_prototypes(this); | |
| 880 check_prototypes.BeginBody(1); | |
| 881 { | |
| 882 HValue* parent_map = environment()->Pop(); | |
| 883 HValue* prototype = Add<HLoadNamedField>(parent_map, nullptr, | |
| 884 HObjectAccess::ForPrototype()); | |
| 885 | |
| 886 IfBuilder is_null(this); | |
| 887 is_null.If<HCompareObjectEqAndBranch>(prototype, | |
| 888 graph()->GetConstantNull()); | |
| 889 is_null.Then(); | |
| 890 check_prototypes.Break(); | |
| 891 is_null.End(); | |
| 892 | |
| 893 HValue* prototype_map = | |
| 894 Add<HLoadNamedField>(prototype, nullptr, HObjectAccess::ForMap()); | |
| 895 HValue* instance_type = Add<HLoadNamedField>( | |
| 896 prototype_map, nullptr, HObjectAccess::ForMapInstanceType()); | |
| 897 IfBuilder check_instance_type(this); | |
| 898 check_instance_type.If<HCompareNumericAndBranch>( | |
| 899 instance_type, Add<HConstant>(JS_VALUE_TYPE), Token::LTE); | |
|
Jakob Kummerow
2016/03/21 15:12:51
This looks like a use case for the recently introd
| |
| 900 check_instance_type.ThenDeopt(Deoptimizer::kFastArrayPushFailed); | |
| 901 check_instance_type.End(); | |
| 902 | |
| 903 HValue* elements = Add<HLoadNamedField>( | |
| 904 prototype, nullptr, HObjectAccess::ForElementsPointer()); | |
| 905 IfBuilder no_elements(this); | |
| 906 no_elements.If<HCompareObjectEqAndBranch>( | |
| 907 elements, Add<HConstant>(isolate()->factory()->empty_fixed_array())); | |
| 908 no_elements.Then(); | |
| 909 no_elements.ElseDeopt(Deoptimizer::kFastArrayPushFailed); | |
|
Jakob Kummerow
2016/03/21 15:12:51
nit: you could also use IfNot/ThenDeopt. Up to you
| |
| 910 no_elements.End(); | |
| 911 | |
| 912 environment()->Push(prototype_map); | |
| 913 } | |
| 914 check_prototypes.EndBody(); | |
| 915 | |
| 916 HValue* bit_field2 = | |
| 917 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); | |
|
Jakob Kummerow
2016/03/21 15:12:51
This is duplicated from line 823. Suggestion: hois
| |
| 918 HValue* kind = BuildDecodeField<Map::ElementsKindBits>(bit_field2); | |
| 919 | |
| 920 IfBuilder is_smi(this); | |
|
Jakob Kummerow
2016/03/21 15:12:51
nit: I'd prefer the name "has_smi_elements".
| |
| 921 is_smi.If<HCompareNumericAndBranch>( | |
| 922 kind, Add<HConstant>(FAST_HOLEY_SMI_ELEMENTS), Token::LTE); | |
|
Jakob Kummerow
2016/03/21 15:12:51
nit: a comment and a check would be nice, roughly:
| |
| 923 is_smi.Then(); | |
| 924 { | |
| 925 HValue* smi_value = | |
| 926 AddUncasted<HForceRepresentation>(value, Representation::Smi()); | |
| 927 HValue* key = BuildPushElement(object, smi_value, FAST_HOLEY_SMI_ELEMENTS); | |
| 928 environment()->Push(key); | |
| 929 } | |
| 930 is_smi.Else(); | |
| 931 { | |
| 932 IfBuilder is_object(this); | |
|
Jakob Kummerow
2016/03/21 15:12:50
nit: has_object_elements
| |
| 933 is_object.If<HCompareNumericAndBranch>( | |
| 934 kind, Add<HConstant>(FAST_HOLEY_ELEMENTS), Token::LTE); | |
| 935 is_object.Then(); | |
| 936 { | |
| 937 HValue* key = BuildPushElement(object, value, FAST_HOLEY_ELEMENTS); | |
| 938 environment()->Push(key); | |
| 939 } | |
| 940 is_object.Else(); | |
| 941 { | |
| 942 IfBuilder is_double(this); | |
| 943 is_double.If<HCompareNumericAndBranch>( | |
| 944 kind, Add<HConstant>(FAST_HOLEY_DOUBLE_ELEMENTS), Token::GT); | |
| 945 is_double.ThenDeopt(Deoptimizer::kFastArrayPushFailed); | |
| 946 is_double.End(); | |
| 947 | |
| 948 HValue* double_value = | |
| 949 AddUncasted<HForceRepresentation>(value, Representation::Double()); | |
| 950 HValue* key = | |
| 951 BuildPushElement(object, double_value, FAST_HOLEY_DOUBLE_ELEMENTS); | |
| 952 environment()->Push(key); | |
| 953 } | |
| 954 is_object.End(); | |
| 955 } | |
| 956 is_smi.End(); | |
| 957 | |
| 958 HValue* key = environment()->Pop(); | |
| 959 return AddUncasted<HAdd>(key, graph()->GetConstant1()); | |
| 960 } | |
| 961 | |
| 962 Handle<Code> FastArrayPushStub::GenerateCode() { return DoGenerateCode(this); } | |
| 783 | 963 |
| 784 template <> | 964 template <> |
| 785 HValue* CodeStubGraphBuilder<GrowArrayElementsStub>::BuildCodeStub() { | 965 HValue* CodeStubGraphBuilder<GrowArrayElementsStub>::BuildCodeStub() { |
| 786 ElementsKind kind = casted_stub()->elements_kind(); | 966 ElementsKind kind = casted_stub()->elements_kind(); |
| 787 if (IsFastDoubleElementsKind(kind)) { | 967 if (IsFastDoubleElementsKind(kind)) { |
| 788 info()->MarkAsSavesCallerDoubles(); | 968 info()->MarkAsSavesCallerDoubles(); |
| 789 } | 969 } |
| 790 | 970 |
| 791 HValue* object = GetParameter(GrowArrayElementsDescriptor::kObjectIndex); | 971 HValue* object = GetParameter(GrowArrayElementsDescriptor::kObjectIndex); |
| 792 HValue* key = GetParameter(GrowArrayElementsDescriptor::kKeyIndex); | 972 HValue* key = GetParameter(GrowArrayElementsDescriptor::kKeyIndex); |
| (...skipping 1571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2364 return Pop(); | 2544 return Pop(); |
| 2365 } | 2545 } |
| 2366 | 2546 |
| 2367 | 2547 |
| 2368 Handle<Code> KeyedLoadGenericStub::GenerateCode() { | 2548 Handle<Code> KeyedLoadGenericStub::GenerateCode() { |
| 2369 return DoGenerateCode(this); | 2549 return DoGenerateCode(this); |
| 2370 } | 2550 } |
| 2371 | 2551 |
| 2372 } // namespace internal | 2552 } // namespace internal |
| 2373 } // namespace v8 | 2553 } // namespace v8 |
| OLD | NEW |