OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 2081 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2092 if (HasLocalElement(index)) return NONE; | 2092 if (HasLocalElement(index)) return NONE; |
2093 return ABSENT; | 2093 return ABSENT; |
2094 } | 2094 } |
2095 // Named property. | 2095 // Named property. |
2096 LookupResult result; | 2096 LookupResult result; |
2097 LocalLookup(name, &result); | 2097 LocalLookup(name, &result); |
2098 return GetPropertyAttribute(this, &result, name, false); | 2098 return GetPropertyAttribute(this, &result, name, false); |
2099 } | 2099 } |
2100 | 2100 |
2101 | 2101 |
2102 bool NormalizedMapCache::IsCacheable(JSObject* object) { | |
2103 // Caching for global objects is not worth it (there are too few of them). | |
2104 return !object->IsGlobalObject(); | |
2105 } | |
2106 | |
2107 | |
2108 Object* NormalizedMapCache::Get(JSObject* obj, PropertyNormalizationMode mode) { | 2102 Object* NormalizedMapCache::Get(JSObject* obj, PropertyNormalizationMode mode) { |
2109 Object* result; | 2103 Map* fast = obj->map(); |
| 2104 int index = Hash(fast) % kEntries; |
| 2105 Object* result = get(index); |
| 2106 if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) { |
| 2107 #ifdef DEBUG |
| 2108 if (FLAG_enable_slow_asserts) { |
| 2109 // The cached map should match newly created normalized map bit-by-bit. |
| 2110 Object* fresh = fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); |
| 2111 if (!fresh->IsFailure()) { |
| 2112 ASSERT(memcmp(Map::cast(fresh)->address(), |
| 2113 Map::cast(result)->address(), |
| 2114 Map::kSize) == 0); |
| 2115 } |
| 2116 } |
| 2117 #endif |
| 2118 return result; |
| 2119 } |
2110 | 2120 |
2111 Map* fast = obj->map(); | 2121 result = fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); |
2112 if (!IsCacheable(obj)) { | 2122 if (result->IsFailure()) return result; |
2113 result = fast->CopyNormalized(mode); | 2123 set(index, result); |
2114 if (result->IsFailure()) return result; | |
2115 } else { | |
2116 int index = Hash(fast) % kEntries; | |
2117 result = get(index); | |
2118 | |
2119 if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) { | |
2120 #ifdef DEBUG | |
2121 if (FLAG_enable_slow_asserts) { | |
2122 // Make sure that the new slow map has exactly the same hash as the | |
2123 // original fast map. This way we can use hash to check if a slow map | |
2124 // is already in the hash (see Contains method). | |
2125 ASSERT(Hash(fast) == Hash(Map::cast(result))); | |
2126 // The cached map should match newly created normalized map bit-by-bit. | |
2127 Object* fresh = fast->CopyNormalized(mode); | |
2128 if (!fresh->IsFailure()) { | |
2129 ASSERT(memcmp(Map::cast(fresh)->address(), | |
2130 Map::cast(result)->address(), | |
2131 Map::kSize) == 0); | |
2132 } | |
2133 } | |
2134 #endif | |
2135 return result; | |
2136 } | |
2137 | |
2138 result = fast->CopyNormalized(mode); | |
2139 if (result->IsFailure()) return result; | |
2140 set(index, result); | |
2141 } | |
2142 Counters::normalized_maps.Increment(); | 2124 Counters::normalized_maps.Increment(); |
2143 | 2125 |
2144 return result; | 2126 return result; |
2145 } | 2127 } |
2146 | 2128 |
2147 | 2129 |
2148 bool NormalizedMapCache::Contains(Map* map) { | |
2149 // If the map is present in the cache it can only be at one place: | |
2150 // at the index calculated from the hash. We assume that a slow map has the | |
2151 // same hash as a fast map it has been generated from. | |
2152 int index = Hash(map) % kEntries; | |
2153 return get(index) == map; | |
2154 } | |
2155 | |
2156 | |
2157 void NormalizedMapCache::Clear() { | 2130 void NormalizedMapCache::Clear() { |
2158 int entries = length(); | 2131 int entries = length(); |
2159 for (int i = 0; i != entries; i++) { | 2132 for (int i = 0; i != entries; i++) { |
2160 set_undefined(i); | 2133 set_undefined(i); |
2161 } | 2134 } |
2162 } | 2135 } |
2163 | 2136 |
2164 | 2137 |
2165 int NormalizedMapCache::Hash(Map* fast) { | 2138 int NormalizedMapCache::Hash(Map* fast) { |
2166 // For performance reasons we only hash the 3 most variable fields of a map: | 2139 // For performance reasons we only hash the 3 most variable fields of a map: |
(...skipping 10 matching lines...) Expand all Loading... |
2177 reinterpret_cast<uintptr_t>(fast->prototype())) << 2); | 2150 reinterpret_cast<uintptr_t>(fast->prototype())) << 2); |
2178 | 2151 |
2179 return hash ^ (hash >> 16) ^ fast->bit_field2(); | 2152 return hash ^ (hash >> 16) ^ fast->bit_field2(); |
2180 } | 2153 } |
2181 | 2154 |
2182 | 2155 |
2183 bool NormalizedMapCache::CheckHit(Map* slow, | 2156 bool NormalizedMapCache::CheckHit(Map* slow, |
2184 Map* fast, | 2157 Map* fast, |
2185 PropertyNormalizationMode mode) { | 2158 PropertyNormalizationMode mode) { |
2186 #ifdef DEBUG | 2159 #ifdef DEBUG |
2187 slow->NormalizedMapVerify(); | 2160 slow->SharedMapVerify(); |
2188 #endif | 2161 #endif |
2189 return | 2162 return |
2190 slow->constructor() == fast->constructor() && | 2163 slow->constructor() == fast->constructor() && |
2191 slow->prototype() == fast->prototype() && | 2164 slow->prototype() == fast->prototype() && |
2192 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? | 2165 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? |
2193 0 : | 2166 0 : |
2194 fast->inobject_properties()) && | 2167 fast->inobject_properties()) && |
2195 slow->instance_type() == fast->instance_type() && | 2168 slow->instance_type() == fast->instance_type() && |
2196 slow->bit_field() == fast->bit_field() && | 2169 slow->bit_field() == fast->bit_field() && |
2197 slow->bit_field2() == fast->bit_field2(); | 2170 (slow->bit_field2() & ~(1<<Map::kIsShared)) == fast->bit_field2(); |
2198 } | 2171 } |
2199 | 2172 |
2200 | 2173 |
2201 Object* JSObject::UpdateMapCodeCache(String* name, Code* code) { | 2174 Object* JSObject::UpdateMapCodeCache(String* name, Code* code) { |
2202 if (!HasFastProperties() && | 2175 if (map()->is_shared()) { |
2203 NormalizedMapCache::IsCacheable(this) && | 2176 // Fast case maps are never marked as shared. |
2204 Top::context()->global_context()->normalized_map_cache()-> | 2177 ASSERT(!HasFastProperties()); |
2205 Contains(map())) { | 2178 // Replace the map with an identical copy that can be safely modified. |
2206 // Replace the map with the identical copy that can be safely modified. | 2179 Object* obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, |
2207 Object* obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES); | 2180 UNIQUE_NORMALIZED_MAP); |
2208 if (obj->IsFailure()) return obj; | 2181 if (obj->IsFailure()) return obj; |
2209 Counters::normalized_maps.Increment(); | 2182 Counters::normalized_maps.Increment(); |
2210 | 2183 |
2211 set_map(Map::cast(obj)); | 2184 set_map(Map::cast(obj)); |
2212 } | 2185 } |
2213 return map()->UpdateCodeCache(name, code); | 2186 return map()->UpdateCodeCache(name, code); |
2214 } | 2187 } |
2215 | 2188 |
2216 | 2189 |
2217 Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode, | 2190 Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode, |
(...skipping 964 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3182 Object* descriptors = | 3155 Object* descriptors = |
3183 ctor->initial_map()->instance_descriptors()->RemoveTransitions(); | 3156 ctor->initial_map()->instance_descriptors()->RemoveTransitions(); |
3184 if (descriptors->IsFailure()) return descriptors; | 3157 if (descriptors->IsFailure()) return descriptors; |
3185 Map::cast(result)->set_instance_descriptors( | 3158 Map::cast(result)->set_instance_descriptors( |
3186 DescriptorArray::cast(descriptors)); | 3159 DescriptorArray::cast(descriptors)); |
3187 Map::cast(result)->set_pre_allocated_property_fields( | 3160 Map::cast(result)->set_pre_allocated_property_fields( |
3188 pre_allocated_property_fields()); | 3161 pre_allocated_property_fields()); |
3189 } | 3162 } |
3190 Map::cast(result)->set_bit_field(bit_field()); | 3163 Map::cast(result)->set_bit_field(bit_field()); |
3191 Map::cast(result)->set_bit_field2(bit_field2()); | 3164 Map::cast(result)->set_bit_field2(bit_field2()); |
| 3165 Map::cast(result)->set_is_shared(false); |
3192 Map::cast(result)->ClearCodeCache(); | 3166 Map::cast(result)->ClearCodeCache(); |
3193 return result; | 3167 return result; |
3194 } | 3168 } |
3195 | 3169 |
3196 | 3170 |
3197 Object* Map::CopyNormalized(PropertyNormalizationMode mode) { | 3171 Object* Map::CopyNormalized(PropertyNormalizationMode mode, |
| 3172 NormalizedMapSharingMode sharing) { |
3198 int new_instance_size = instance_size(); | 3173 int new_instance_size = instance_size(); |
3199 if (mode == CLEAR_INOBJECT_PROPERTIES) { | 3174 if (mode == CLEAR_INOBJECT_PROPERTIES) { |
3200 new_instance_size -= inobject_properties() * kPointerSize; | 3175 new_instance_size -= inobject_properties() * kPointerSize; |
3201 } | 3176 } |
3202 | 3177 |
3203 Object* result = Heap::AllocateMap(instance_type(), new_instance_size); | 3178 Object* result = Heap::AllocateMap(instance_type(), new_instance_size); |
3204 if (result->IsFailure()) return result; | 3179 if (result->IsFailure()) return result; |
3205 | 3180 |
3206 if (mode != CLEAR_INOBJECT_PROPERTIES) { | 3181 if (mode != CLEAR_INOBJECT_PROPERTIES) { |
3207 Map::cast(result)->set_inobject_properties(inobject_properties()); | 3182 Map::cast(result)->set_inobject_properties(inobject_properties()); |
3208 } | 3183 } |
3209 | 3184 |
3210 Map::cast(result)->set_prototype(prototype()); | 3185 Map::cast(result)->set_prototype(prototype()); |
3211 Map::cast(result)->set_constructor(constructor()); | 3186 Map::cast(result)->set_constructor(constructor()); |
3212 | 3187 |
3213 Map::cast(result)->set_bit_field(bit_field()); | 3188 Map::cast(result)->set_bit_field(bit_field()); |
3214 Map::cast(result)->set_bit_field2(bit_field2()); | 3189 Map::cast(result)->set_bit_field2(bit_field2()); |
3215 | 3190 |
| 3191 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP); |
| 3192 |
3216 #ifdef DEBUG | 3193 #ifdef DEBUG |
3217 Map::cast(result)->NormalizedMapVerify(); | 3194 if (Map::cast(result)->is_shared()) { |
| 3195 Map::cast(result)->SharedMapVerify(); |
| 3196 } |
3218 #endif | 3197 #endif |
3219 | 3198 |
3220 return result; | 3199 return result; |
3221 } | 3200 } |
3222 | 3201 |
3223 | 3202 |
3224 Object* Map::CopyDropTransitions() { | 3203 Object* Map::CopyDropTransitions() { |
3225 Object* new_map = CopyDropDescriptors(); | 3204 Object* new_map = CopyDropDescriptors(); |
3226 if (new_map->IsFailure()) return new_map; | 3205 if (new_map->IsFailure()) return new_map; |
3227 Object* descriptors = instance_descriptors()->RemoveTransitions(); | 3206 Object* descriptors = instance_descriptors()->RemoveTransitions(); |
(...skipping 5825 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9053 if (break_point_objects()->IsUndefined()) return 0; | 9032 if (break_point_objects()->IsUndefined()) return 0; |
9054 // Single beak point. | 9033 // Single beak point. |
9055 if (!break_point_objects()->IsFixedArray()) return 1; | 9034 if (!break_point_objects()->IsFixedArray()) return 1; |
9056 // Multiple break points. | 9035 // Multiple break points. |
9057 return FixedArray::cast(break_point_objects())->length(); | 9036 return FixedArray::cast(break_point_objects())->length(); |
9058 } | 9037 } |
9059 #endif | 9038 #endif |
9060 | 9039 |
9061 | 9040 |
9062 } } // namespace v8::internal | 9041 } } // namespace v8::internal |
OLD | NEW |