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 |