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) { |
| 2108 Object* result; |
| 2109 |
| 2110 Map* fast = obj->map(); |
| 2111 if (!IsCacheable(obj)) { |
| 2112 result = fast->CopyNormalized(mode); |
| 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(); |
| 2145 |
| 2146 return result; |
| 2147 } |
| 2148 |
| 2149 |
| 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() { |
| 2160 int entries = length(); |
| 2161 for (int i = 0; i != entries; i++) { |
| 2162 set_undefined(i); |
| 2163 } |
| 2164 } |
| 2165 |
| 2166 |
| 2167 int NormalizedMapCache::Hash(Map* fast) { |
| 2168 // For performance reasons we only hash the 3 most variable fields of a map: |
| 2169 // constructor, prototype and bit_field2. |
| 2170 |
| 2171 // Shift away the tag. |
| 2172 int hash = (static_cast<uint32_t>( |
| 2173 reinterpret_cast<uintptr_t>(fast->constructor())) >> 2); |
| 2174 |
| 2175 // XOR-ing the prototype and constructor directly yields too many zero bits |
| 2176 // when the two pointers are close (which is fairly common). |
| 2177 // To avoid this we shift the prototype 4 bits relatively to the constructor. |
| 2178 hash ^= (static_cast<uint32_t>( |
| 2179 reinterpret_cast<uintptr_t>(fast->prototype())) << 2); |
| 2180 |
| 2181 return hash ^ (hash >> 16) ^ fast->bit_field2(); |
| 2182 } |
| 2183 |
| 2184 |
| 2185 bool NormalizedMapCache::CheckHit(Map* slow, |
| 2186 Map* fast, |
| 2187 PropertyNormalizationMode mode) { |
| 2188 #ifdef DEBUG |
| 2189 slow->NormalizedMapVerify(); |
| 2190 #endif |
| 2191 return |
| 2192 slow->constructor() == fast->constructor() && |
| 2193 slow->prototype() == fast->prototype() && |
| 2194 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? |
| 2195 0 : |
| 2196 fast->inobject_properties()) && |
| 2197 slow->instance_type() == fast->instance_type() && |
| 2198 slow->bit_field() == fast->bit_field() && |
| 2199 slow->bit_field2() == fast->bit_field2(); |
| 2200 } |
| 2201 |
| 2202 |
| 2203 Object* JSObject::UpdateMapCodeCache(String* name, Code* code) { |
| 2204 if (!HasFastProperties() && |
| 2205 NormalizedMapCache::IsCacheable(this) && |
| 2206 Top::context()->global_context()->normalized_map_cache()-> |
| 2207 Contains(map())) { |
| 2208 // Replace the map with the identical copy that can be safely modified. |
| 2209 Object* obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES); |
| 2210 if (obj->IsFailure()) return obj; |
| 2211 Counters::normalized_maps.Increment(); |
| 2212 |
| 2213 set_map(Map::cast(obj)); |
| 2214 } |
| 2215 return map()->UpdateCodeCache(name, code); |
| 2216 } |
| 2217 |
| 2218 |
2101 Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode, | 2219 Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode, |
2102 int expected_additional_properties) { | 2220 int expected_additional_properties) { |
2103 if (!HasFastProperties()) return this; | 2221 if (!HasFastProperties()) return this; |
2104 | 2222 |
2105 // The global object is always normalized. | 2223 // The global object is always normalized. |
2106 ASSERT(!IsGlobalObject()); | 2224 ASSERT(!IsGlobalObject()); |
2107 | 2225 |
2108 // Allocate new content. | 2226 // Allocate new content. |
2109 int property_count = map()->NumberOfDescribedProperties(); | 2227 int property_count = map()->NumberOfDescribedProperties(); |
2110 if (expected_additional_properties > 0) { | 2228 if (expected_additional_properties > 0) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2155 break; | 2273 break; |
2156 default: | 2274 default: |
2157 UNREACHABLE(); | 2275 UNREACHABLE(); |
2158 } | 2276 } |
2159 } | 2277 } |
2160 | 2278 |
2161 // Copy the next enumeration index from instance descriptor. | 2279 // Copy the next enumeration index from instance descriptor. |
2162 int index = map()->instance_descriptors()->NextEnumerationIndex(); | 2280 int index = map()->instance_descriptors()->NextEnumerationIndex(); |
2163 dictionary->SetNextEnumerationIndex(index); | 2281 dictionary->SetNextEnumerationIndex(index); |
2164 | 2282 |
2165 // Allocate new map. | 2283 obj = Top::context()->global_context()-> |
2166 obj = map()->CopyDropDescriptors(); | 2284 normalized_map_cache()->Get(this, mode); |
2167 if (obj->IsFailure()) return obj; | 2285 if (obj->IsFailure()) return obj; |
2168 Map* new_map = Map::cast(obj); | 2286 Map* new_map = Map::cast(obj); |
2169 | 2287 |
2170 // Clear inobject properties if needed by adjusting the instance size and | |
2171 // putting in a filler object instead of the inobject properties. | |
2172 if (mode == CLEAR_INOBJECT_PROPERTIES && map()->inobject_properties() > 0) { | |
2173 int instance_size_delta = map()->inobject_properties() * kPointerSize; | |
2174 int new_instance_size = map()->instance_size() - instance_size_delta; | |
2175 new_map->set_inobject_properties(0); | |
2176 new_map->set_instance_size(new_instance_size); | |
2177 new_map->set_visitor_id(StaticVisitorBase::GetVisitorId(new_map)); | |
2178 Heap::CreateFillerObjectAt(this->address() + new_instance_size, | |
2179 instance_size_delta); | |
2180 } | |
2181 new_map->set_unused_property_fields(0); | |
2182 | |
2183 // We have now successfully allocated all the necessary objects. | 2288 // We have now successfully allocated all the necessary objects. |
2184 // Changes can now be made with the guarantee that all of them take effect. | 2289 // Changes can now be made with the guarantee that all of them take effect. |
| 2290 |
| 2291 // Resize the object in the heap if necessary. |
| 2292 int new_instance_size = new_map->instance_size(); |
| 2293 int instance_size_delta = map()->instance_size() - new_instance_size; |
| 2294 ASSERT(instance_size_delta >= 0); |
| 2295 Heap::CreateFillerObjectAt(this->address() + new_instance_size, |
| 2296 instance_size_delta); |
| 2297 |
2185 set_map(new_map); | 2298 set_map(new_map); |
2186 map()->set_instance_descriptors(Heap::empty_descriptor_array()); | |
2187 | 2299 |
2188 set_properties(dictionary); | 2300 set_properties(dictionary); |
2189 | 2301 |
2190 Counters::props_to_dictionary.Increment(); | 2302 Counters::props_to_dictionary.Increment(); |
2191 | 2303 |
2192 #ifdef DEBUG | 2304 #ifdef DEBUG |
2193 if (FLAG_trace_normalization) { | 2305 if (FLAG_trace_normalization) { |
2194 PrintF("Object properties have been normalized:\n"); | 2306 PrintF("Object properties have been normalized:\n"); |
2195 Print(); | 2307 Print(); |
2196 } | 2308 } |
(...skipping 879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3076 Map::cast(result)->set_pre_allocated_property_fields( | 3188 Map::cast(result)->set_pre_allocated_property_fields( |
3077 pre_allocated_property_fields()); | 3189 pre_allocated_property_fields()); |
3078 } | 3190 } |
3079 Map::cast(result)->set_bit_field(bit_field()); | 3191 Map::cast(result)->set_bit_field(bit_field()); |
3080 Map::cast(result)->set_bit_field2(bit_field2()); | 3192 Map::cast(result)->set_bit_field2(bit_field2()); |
3081 Map::cast(result)->ClearCodeCache(); | 3193 Map::cast(result)->ClearCodeCache(); |
3082 return result; | 3194 return result; |
3083 } | 3195 } |
3084 | 3196 |
3085 | 3197 |
| 3198 Object* Map::CopyNormalized(PropertyNormalizationMode mode) { |
| 3199 int new_instance_size = instance_size(); |
| 3200 if (mode == CLEAR_INOBJECT_PROPERTIES) { |
| 3201 new_instance_size -= inobject_properties() * kPointerSize; |
| 3202 } |
| 3203 |
| 3204 Object* result = Heap::AllocateMap(instance_type(), new_instance_size); |
| 3205 if (result->IsFailure()) return result; |
| 3206 |
| 3207 if (mode != CLEAR_INOBJECT_PROPERTIES) { |
| 3208 Map::cast(result)->set_inobject_properties(inobject_properties()); |
| 3209 } |
| 3210 |
| 3211 Map::cast(result)->set_prototype(prototype()); |
| 3212 Map::cast(result)->set_constructor(constructor()); |
| 3213 |
| 3214 Map::cast(result)->set_bit_field(bit_field()); |
| 3215 Map::cast(result)->set_bit_field2(bit_field2()); |
| 3216 |
| 3217 #ifdef DEBUG |
| 3218 Map::cast(result)->NormalizedMapVerify(); |
| 3219 #endif |
| 3220 |
| 3221 return result; |
| 3222 } |
| 3223 |
| 3224 |
3086 Object* Map::CopyDropTransitions() { | 3225 Object* Map::CopyDropTransitions() { |
3087 Object* new_map = CopyDropDescriptors(); | 3226 Object* new_map = CopyDropDescriptors(); |
3088 if (new_map->IsFailure()) return new_map; | 3227 if (new_map->IsFailure()) return new_map; |
3089 Object* descriptors = instance_descriptors()->RemoveTransitions(); | 3228 Object* descriptors = instance_descriptors()->RemoveTransitions(); |
3090 if (descriptors->IsFailure()) return descriptors; | 3229 if (descriptors->IsFailure()) return descriptors; |
3091 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); | 3230 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); |
3092 return new_map; | 3231 return new_map; |
3093 } | 3232 } |
3094 | 3233 |
3095 | 3234 |
(...skipping 5661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8757 if (break_point_objects()->IsUndefined()) return 0; | 8896 if (break_point_objects()->IsUndefined()) return 0; |
8758 // Single beak point. | 8897 // Single beak point. |
8759 if (!break_point_objects()->IsFixedArray()) return 1; | 8898 if (!break_point_objects()->IsFixedArray()) return 1; |
8760 // Multiple break points. | 8899 // Multiple break points. |
8761 return FixedArray::cast(break_point_objects())->length(); | 8900 return FixedArray::cast(break_point_objects())->length(); |
8762 } | 8901 } |
8763 #endif | 8902 #endif |
8764 | 8903 |
8765 | 8904 |
8766 } } // namespace v8::internal | 8905 } } // namespace v8::internal |
OLD | NEW |