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