| 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 2799 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2810 void HLoadNamedField::PrintDataTo(StringStream* stream) { | 2810 void HLoadNamedField::PrintDataTo(StringStream* stream) { |
| 2811 object()->PrintNameTo(stream); | 2811 object()->PrintNameTo(stream); |
| 2812 access_.PrintTo(stream); | 2812 access_.PrintTo(stream); |
| 2813 if (HasTypeCheck()) { | 2813 if (HasTypeCheck()) { |
| 2814 stream->Add(" "); | 2814 stream->Add(" "); |
| 2815 typecheck()->PrintNameTo(stream); | 2815 typecheck()->PrintNameTo(stream); |
| 2816 } | 2816 } |
| 2817 } | 2817 } |
| 2818 | 2818 |
| 2819 | 2819 |
| 2820 // Returns true if an instance of this map can never find a property with this | |
| 2821 // name in its prototype chain. This means all prototypes up to the top are | |
| 2822 // fast and don't have the name in them. It would be good if we could optimize | |
| 2823 // polymorphic loads where the property is sometimes found in the prototype | |
| 2824 // chain. | |
| 2825 static bool PrototypeChainCanNeverResolve( | |
| 2826 Handle<Map> map, Handle<String> name) { | |
| 2827 Isolate* isolate = map->GetIsolate(); | |
| 2828 Object* current = map->prototype(); | |
| 2829 while (current != isolate->heap()->null_value()) { | |
| 2830 if (current->IsJSGlobalProxy() || | |
| 2831 current->IsGlobalObject() || | |
| 2832 !current->IsJSObject() || | |
| 2833 JSObject::cast(current)->map()->has_named_interceptor() || | |
| 2834 JSObject::cast(current)->IsAccessCheckNeeded() || | |
| 2835 !JSObject::cast(current)->HasFastProperties()) { | |
| 2836 return false; | |
| 2837 } | |
| 2838 | |
| 2839 LookupResult lookup(isolate); | |
| 2840 Map* map = JSObject::cast(current)->map(); | |
| 2841 map->LookupDescriptor(NULL, *name, &lookup); | |
| 2842 if (lookup.IsFound()) return false; | |
| 2843 if (!lookup.IsCacheable()) return false; | |
| 2844 current = JSObject::cast(current)->GetPrototype(); | |
| 2845 } | |
| 2846 return true; | |
| 2847 } | |
| 2848 | |
| 2849 | |
| 2850 HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context, | |
| 2851 HValue* object, | |
| 2852 SmallMapList* types, | |
| 2853 Handle<String> name, | |
| 2854 Zone* zone) | |
| 2855 : types_(Min(types->length(), kMaxLoadPolymorphism), zone), | |
| 2856 name_(name), | |
| 2857 types_unique_ids_(0, zone), | |
| 2858 name_unique_id_(), | |
| 2859 need_generic_(false) { | |
| 2860 SetOperandAt(0, context); | |
| 2861 SetOperandAt(1, object); | |
| 2862 set_representation(Representation::Tagged()); | |
| 2863 SetGVNFlag(kDependsOnMaps); | |
| 2864 SmallMapList negative_lookups; | |
| 2865 for (int i = 0; | |
| 2866 i < types->length() && types_.length() < kMaxLoadPolymorphism; | |
| 2867 ++i) { | |
| 2868 Handle<Map> map = types->at(i); | |
| 2869 // Deprecated maps are updated to the current map in the type oracle. | |
| 2870 ASSERT(!map->is_deprecated()); | |
| 2871 LookupResult lookup(map->GetIsolate()); | |
| 2872 map->LookupDescriptor(NULL, *name, &lookup); | |
| 2873 if (lookup.IsFound()) { | |
| 2874 switch (lookup.type()) { | |
| 2875 case FIELD: { | |
| 2876 int index = lookup.GetLocalFieldIndexFromMap(*map); | |
| 2877 if (index < 0) { | |
| 2878 SetGVNFlag(kDependsOnInobjectFields); | |
| 2879 } else { | |
| 2880 SetGVNFlag(kDependsOnBackingStoreFields); | |
| 2881 } | |
| 2882 if (FLAG_track_double_fields && | |
| 2883 lookup.representation().IsDouble()) { | |
| 2884 // Since the value needs to be boxed, use a generic handler for | |
| 2885 // loading doubles. | |
| 2886 continue; | |
| 2887 } | |
| 2888 types_.Add(types->at(i), zone); | |
| 2889 break; | |
| 2890 } | |
| 2891 case CONSTANT: | |
| 2892 types_.Add(types->at(i), zone); | |
| 2893 break; | |
| 2894 case CALLBACKS: | |
| 2895 break; | |
| 2896 case TRANSITION: | |
| 2897 case INTERCEPTOR: | |
| 2898 case NONEXISTENT: | |
| 2899 case NORMAL: | |
| 2900 case HANDLER: | |
| 2901 UNREACHABLE(); | |
| 2902 break; | |
| 2903 } | |
| 2904 } else if (lookup.IsCacheable() && | |
| 2905 // For dicts the lookup on the map will fail, but the object may | |
| 2906 // contain the property so we cannot generate a negative lookup | |
| 2907 // (which would just be a map check and return undefined). | |
| 2908 !map->is_dictionary_map() && | |
| 2909 !map->has_named_interceptor() && | |
| 2910 PrototypeChainCanNeverResolve(map, name)) { | |
| 2911 negative_lookups.Add(types->at(i), zone); | |
| 2912 } | |
| 2913 } | |
| 2914 | |
| 2915 bool need_generic = | |
| 2916 (types->length() != negative_lookups.length() + types_.length()); | |
| 2917 if (!need_generic && FLAG_deoptimize_uncommon_cases) { | |
| 2918 SetFlag(kUseGVN); | |
| 2919 for (int i = 0; i < negative_lookups.length(); i++) { | |
| 2920 types_.Add(negative_lookups.at(i), zone); | |
| 2921 } | |
| 2922 } else { | |
| 2923 // We don't have an easy way to handle both a call (to the generic stub) and | |
| 2924 // a deopt in the same hydrogen instruction, so in this case we don't add | |
| 2925 // the negative lookups which can deopt - just let the generic stub handle | |
| 2926 // them. | |
| 2927 SetAllSideEffects(); | |
| 2928 need_generic_ = true; | |
| 2929 } | |
| 2930 } | |
| 2931 | |
| 2932 | |
| 2933 HCheckMaps* HCheckMaps::New(Zone* zone, | 2820 HCheckMaps* HCheckMaps::New(Zone* zone, |
| 2934 HValue* context, | 2821 HValue* context, |
| 2935 HValue* value, | 2822 HValue* value, |
| 2936 Handle<Map> map, | 2823 Handle<Map> map, |
| 2937 CompilationInfo* info, | 2824 CompilationInfo* info, |
| 2938 HValue* typecheck) { | 2825 HValue* typecheck) { |
| 2939 HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck); | 2826 HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck); |
| 2940 check_map->map_set_.Add(map, zone); | 2827 check_map->map_set_.Add(map, zone); |
| 2941 check_map->has_migration_target_ = map->is_migration_target(); | 2828 check_map->has_migration_target_ = map->is_migration_target(); |
| 2942 if (map->CanOmitMapChecks() && | 2829 if (map->CanOmitMapChecks() && |
| 2943 value->IsConstant() && | 2830 value->IsConstant() && |
| 2944 HConstant::cast(value)->InstanceOf(map)) { | 2831 HConstant::cast(value)->InstanceOf(map)) { |
| 2945 check_map->omit(info); | 2832 check_map->omit(info); |
| 2946 } | 2833 } |
| 2947 return check_map; | 2834 return check_map; |
| 2948 } | 2835 } |
| 2949 | 2836 |
| 2950 | 2837 |
| 2951 void HCheckMaps::FinalizeUniqueValueId() { | 2838 void HCheckMaps::FinalizeUniqueValueId() { |
| 2952 if (!map_unique_ids_.is_empty()) return; | 2839 if (!map_unique_ids_.is_empty()) return; |
| 2953 Zone* zone = block()->zone(); | 2840 Zone* zone = block()->zone(); |
| 2954 map_unique_ids_.Initialize(map_set_.length(), zone); | 2841 map_unique_ids_.Initialize(map_set_.length(), zone); |
| 2955 for (int i = 0; i < map_set_.length(); i++) { | 2842 for (int i = 0; i < map_set_.length(); i++) { |
| 2956 map_unique_ids_.Add(UniqueValueId(map_set_.at(i)), zone); | 2843 map_unique_ids_.Add(UniqueValueId(map_set_.at(i)), zone); |
| 2957 } | 2844 } |
| 2958 } | 2845 } |
| 2959 | 2846 |
| 2960 | 2847 |
| 2961 void HLoadNamedFieldPolymorphic::FinalizeUniqueValueId() { | |
| 2962 if (!types_unique_ids_.is_empty()) return; | |
| 2963 Zone* zone = block()->zone(); | |
| 2964 types_unique_ids_.Initialize(types_.length(), zone); | |
| 2965 for (int i = 0; i < types_.length(); i++) { | |
| 2966 types_unique_ids_.Add(UniqueValueId(types_.at(i)), zone); | |
| 2967 } | |
| 2968 name_unique_id_ = UniqueValueId(name_); | |
| 2969 } | |
| 2970 | |
| 2971 | |
| 2972 bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) { | |
| 2973 ASSERT_EQ(types_.length(), types_unique_ids_.length()); | |
| 2974 HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value); | |
| 2975 if (name_unique_id_ != other->name_unique_id_) return false; | |
| 2976 if (types_unique_ids_.length() != other->types_unique_ids_.length()) { | |
| 2977 return false; | |
| 2978 } | |
| 2979 if (need_generic_ != other->need_generic_) return false; | |
| 2980 for (int i = 0; i < types_unique_ids_.length(); i++) { | |
| 2981 bool found = false; | |
| 2982 for (int j = 0; j < types_unique_ids_.length(); j++) { | |
| 2983 if (types_unique_ids_.at(j) == other->types_unique_ids_.at(i)) { | |
| 2984 found = true; | |
| 2985 break; | |
| 2986 } | |
| 2987 } | |
| 2988 if (!found) return false; | |
| 2989 } | |
| 2990 return true; | |
| 2991 } | |
| 2992 | |
| 2993 | |
| 2994 void HLoadNamedFieldPolymorphic::PrintDataTo(StringStream* stream) { | |
| 2995 object()->PrintNameTo(stream); | |
| 2996 stream->Add("."); | |
| 2997 stream->Add(*String::cast(*name())->ToCString()); | |
| 2998 } | |
| 2999 | |
| 3000 | |
| 3001 void HLoadNamedGeneric::PrintDataTo(StringStream* stream) { | 2848 void HLoadNamedGeneric::PrintDataTo(StringStream* stream) { |
| 3002 object()->PrintNameTo(stream); | 2849 object()->PrintNameTo(stream); |
| 3003 stream->Add("."); | 2850 stream->Add("."); |
| 3004 stream->Add(*String::cast(*name())->ToCString()); | 2851 stream->Add(*String::cast(*name())->ToCString()); |
| 3005 } | 2852 } |
| 3006 | 2853 |
| 3007 | 2854 |
| 3008 void HLoadKeyed::PrintDataTo(StringStream* stream) { | 2855 void HLoadKeyed::PrintDataTo(StringStream* stream) { |
| 3009 if (!is_external()) { | 2856 if (!is_external()) { |
| 3010 elements()->PrintNameTo(stream); | 2857 elements()->PrintNameTo(stream); |
| (...skipping 1109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4120 break; | 3967 break; |
| 4121 case kExternalMemory: | 3968 case kExternalMemory: |
| 4122 stream->Add("[external-memory]"); | 3969 stream->Add("[external-memory]"); |
| 4123 break; | 3970 break; |
| 4124 } | 3971 } |
| 4125 | 3972 |
| 4126 stream->Add("@%d", offset()); | 3973 stream->Add("@%d", offset()); |
| 4127 } | 3974 } |
| 4128 | 3975 |
| 4129 } } // namespace v8::internal | 3976 } } // namespace v8::internal |
| OLD | NEW |