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 2202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2213 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) { | 2213 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) { |
2214 if (trim_mode == FROM_GC) { | 2214 if (trim_mode == FROM_GC) { |
2215 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta); | 2215 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta); |
2216 } else { | 2216 } else { |
2217 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); | 2217 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); |
2218 } | 2218 } |
2219 } | 2219 } |
2220 } | 2220 } |
2221 | 2221 |
2222 | 2222 |
2223 void Map::CopyAppendCallbackDescriptors(Handle<Map> map, | 2223 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { |
2224 Handle<Object> descriptors) { | 2224 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
| 2225 if (slack <= descriptors->NumberOfSlackDescriptors()) return; |
| 2226 int number_of_descriptors = descriptors->number_of_descriptors(); |
| 2227 Isolate* isolate = map->GetIsolate(); |
| 2228 Handle<DescriptorArray> new_descriptors = |
| 2229 isolate->factory()->NewDescriptorArray(number_of_descriptors, slack); |
| 2230 DescriptorArray::WhitenessWitness witness(*new_descriptors); |
| 2231 |
| 2232 for (int i = 0; i < number_of_descriptors; ++i) { |
| 2233 new_descriptors->CopyFrom(i, *descriptors, i, witness); |
| 2234 } |
| 2235 |
| 2236 Map::SetDescriptors(map, new_descriptors); |
| 2237 } |
| 2238 |
| 2239 |
| 2240 void Map::AppendCallbackDescriptors(Handle<Map> map, |
| 2241 Handle<Object> descriptors) { |
2225 Isolate* isolate = map->GetIsolate(); | 2242 Isolate* isolate = map->GetIsolate(); |
2226 Handle<DescriptorArray> array(map->instance_descriptors()); | 2243 Handle<DescriptorArray> array(map->instance_descriptors()); |
2227 v8::NeanderArray callbacks(descriptors); | 2244 NeanderArray callbacks(descriptors); |
2228 int nof_callbacks = callbacks.length(); | 2245 int nof_callbacks = callbacks.length(); |
2229 int descriptor_count = array->number_of_descriptors(); | 2246 |
2230 ASSERT(descriptor_count == map->NumberOfOwnDescriptors()); | 2247 ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks); |
2231 | 2248 |
2232 // Ensure the keys are symbols before writing them into the instance | 2249 // Ensure the keys are symbols before writing them into the instance |
2233 // descriptor. Since it may cause a GC, it has to be done before we | 2250 // descriptor. Since it may cause a GC, it has to be done before we |
2234 // temporarily put the heap in an invalid state while appending descriptors. | 2251 // temporarily put the heap in an invalid state while appending descriptors. |
2235 for (int i = 0; i < nof_callbacks; ++i) { | 2252 for (int i = 0; i < nof_callbacks; ++i) { |
2236 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i))); | 2253 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i))); |
2237 Handle<String> key = | 2254 Handle<String> key = |
2238 isolate->factory()->SymbolFromString( | 2255 isolate->factory()->SymbolFromString( |
2239 Handle<String>(String::cast(entry->name()))); | 2256 Handle<String>(String::cast(entry->name()))); |
2240 entry->set_name(*key); | 2257 entry->set_name(*key); |
2241 } | 2258 } |
2242 | 2259 |
2243 Handle<DescriptorArray> result = | 2260 int nof = map->NumberOfOwnDescriptors(); |
2244 isolate->factory()->NewDescriptorArray(descriptor_count + nof_callbacks); | |
2245 | |
2246 // Ensure that marking will not progress and change color of objects. | |
2247 DescriptorArray::WhitenessWitness witness(*result); | |
2248 | |
2249 // Copy the descriptors from the array. | |
2250 for (int i = 0; i < descriptor_count; i++) { | |
2251 result->CopyFrom(i, *array, i, witness); | |
2252 } | |
2253 | |
2254 // After this point the GC is not allowed to run anymore until the map is in a | |
2255 // consistent state again, i.e., all the descriptors are appended and the | |
2256 // descriptor array is trimmed to the right size. | |
2257 Map::SetDescriptors(map, result); | |
2258 | 2261 |
2259 // Fill in new callback descriptors. Process the callbacks from | 2262 // Fill in new callback descriptors. Process the callbacks from |
2260 // back to front so that the last callback with a given name takes | 2263 // back to front so that the last callback with a given name takes |
2261 // precedence over previously added callbacks with that name. | 2264 // precedence over previously added callbacks with that name. |
2262 int nof = descriptor_count; | |
2263 for (int i = nof_callbacks - 1; i >= 0; i--) { | 2265 for (int i = nof_callbacks - 1; i >= 0; i--) { |
2264 AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i)); | 2266 AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i)); |
2265 String* key = String::cast(entry->name()); | 2267 String* key = String::cast(entry->name()); |
2266 // Check if a descriptor with this name already exists before writing. | 2268 // Check if a descriptor with this name already exists before writing. |
2267 if (result->Search(key, nof) == DescriptorArray::kNotFound) { | 2269 if (array->Search(key, nof) == DescriptorArray::kNotFound) { |
2268 CallbacksDescriptor desc(key, entry, entry->property_attributes()); | 2270 CallbacksDescriptor desc(key, entry, entry->property_attributes()); |
2269 map->AppendDescriptor(&desc, witness); | 2271 array->Append(&desc); |
2270 nof += 1; | 2272 nof += 1; |
2271 } | 2273 } |
2272 } | 2274 } |
2273 | 2275 |
2274 ASSERT(nof == map->NumberOfOwnDescriptors()); | 2276 map->SetNumberOfOwnDescriptors(nof); |
2275 | |
2276 // Reinstall the original descriptor array if no new elements were added. | |
2277 if (nof == descriptor_count) { | |
2278 Map::SetDescriptors(map, array); | |
2279 return; | |
2280 } | |
2281 | |
2282 // If duplicates were detected, trim the descriptor array to the right size. | |
2283 int new_array_size = DescriptorArray::LengthFor(nof); | |
2284 if (new_array_size < result->length()) { | |
2285 RightTrimFixedArray<FROM_MUTATOR>( | |
2286 isolate->heap(), *result, result->length() - new_array_size); | |
2287 } | |
2288 } | 2277 } |
2289 | 2278 |
2290 | 2279 |
2291 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { | 2280 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { |
2292 ASSERT(!map.is_null()); | 2281 ASSERT(!map.is_null()); |
2293 for (int i = 0; i < maps->length(); ++i) { | 2282 for (int i = 0; i < maps->length(); ++i) { |
2294 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true; | 2283 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true; |
2295 } | 2284 } |
2296 return false; | 2285 return false; |
2297 } | 2286 } |
(...skipping 2715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5013 String* name = descriptor->GetKey(); | 5002 String* name = descriptor->GetKey(); |
5014 | 5003 |
5015 TransitionArray* transitions; | 5004 TransitionArray* transitions; |
5016 MaybeObject* maybe_transitions = AddTransition(name, result); | 5005 MaybeObject* maybe_transitions = AddTransition(name, result); |
5017 if (!maybe_transitions->To(&transitions)) return maybe_transitions; | 5006 if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
5018 | 5007 |
5019 DescriptorArray* descriptors = instance_descriptors(); | 5008 DescriptorArray* descriptors = instance_descriptors(); |
5020 int old_size = descriptors->number_of_descriptors(); | 5009 int old_size = descriptors->number_of_descriptors(); |
5021 | 5010 |
5022 DescriptorArray* new_descriptors; | 5011 DescriptorArray* new_descriptors; |
5023 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size + 1); | |
5024 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | |
5025 DescriptorArray::WhitenessWitness witness(new_descriptors); | |
5026 | 5012 |
5027 for (int i = 0; i < old_size; ++i) { | 5013 if (descriptors->NumberOfSlackDescriptors() > 0) { |
5028 new_descriptors->CopyFrom(i, descriptors, i, witness); | 5014 new_descriptors = descriptors; |
5029 } | 5015 new_descriptors->Append(descriptor); |
5030 new_descriptors->Append(descriptor, witness, old_size); | 5016 } else { |
| 5017 // Descriptor arrays grow by 50%. |
| 5018 MaybeObject* maybe_descriptors = DescriptorArray::Allocate( |
| 5019 old_size, old_size < 4 ? 1 : old_size / 2); |
| 5020 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
5031 | 5021 |
5032 // If the source descriptors had an enum cache we copy it. This ensures that | 5022 DescriptorArray::WhitenessWitness witness(new_descriptors); |
5033 // the maps to which we push the new descriptor array back can rely on a | 5023 |
5034 // cache always being available once it is set. If the map has more | 5024 // Copy the descriptors, inserting a descriptor. |
5035 // enumerated descriptors than available in the original cache, the cache | 5025 for (int i = 0; i < old_size; ++i) { |
5036 // will be lazily replaced by the extended cache when needed. | 5026 new_descriptors->CopyFrom(i, descriptors, i, witness); |
5037 if (descriptors->HasEnumCache()) { | 5027 } |
5038 new_descriptors->CopyEnumCacheFrom(descriptors); | 5028 |
| 5029 new_descriptors->Append(descriptor, witness); |
| 5030 |
| 5031 // If the source descriptors had an enum cache we copy it. This ensures that |
| 5032 // the maps to which we push the new descriptor array back can rely on a |
| 5033 // cache always being available once it is set. If the map has more |
| 5034 // enumerated descriptors than available in the original cache, the cache |
| 5035 // will be lazily replaced by the extended cache when needed. |
| 5036 if (descriptors->HasEnumCache()) { |
| 5037 new_descriptors->CopyEnumCacheFrom(descriptors); |
| 5038 } |
5039 } | 5039 } |
5040 | 5040 |
5041 transitions->set_descriptors(new_descriptors); | 5041 transitions->set_descriptors(new_descriptors); |
| 5042 |
5042 set_transitions(transitions); | 5043 set_transitions(transitions); |
5043 result->SetBackPointer(this); | 5044 result->SetBackPointer(this); |
5044 set_owns_descriptors(false); | 5045 set_owns_descriptors(false); |
5045 | 5046 |
5046 result->SetNumberOfOwnDescriptors(new_descriptors->number_of_descriptors()); | 5047 result->SetNumberOfOwnDescriptors(new_descriptors->number_of_descriptors()); |
5047 ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1); | 5048 ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1); |
5048 | 5049 |
5049 return result; | 5050 return result; |
5050 } | 5051 } |
5051 | 5052 |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5207 int new_size = old_size + 1; | 5208 int new_size = old_size + 1; |
5208 descriptor->SetEnumerationIndex(new_size); | 5209 descriptor->SetEnumerationIndex(new_size); |
5209 | 5210 |
5210 if (flag == INSERT_TRANSITION && | 5211 if (flag == INSERT_TRANSITION && |
5211 owns_descriptors() && | 5212 owns_descriptors() && |
5212 CanHaveMoreTransitions()) { | 5213 CanHaveMoreTransitions()) { |
5213 return ShareDescriptor(descriptor); | 5214 return ShareDescriptor(descriptor); |
5214 } | 5215 } |
5215 | 5216 |
5216 DescriptorArray* new_descriptors; | 5217 DescriptorArray* new_descriptors; |
5217 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size + 1); | 5218 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size, 1); |
5218 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | 5219 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
5219 | 5220 |
5220 DescriptorArray::WhitenessWitness witness(new_descriptors); | 5221 DescriptorArray::WhitenessWitness witness(new_descriptors); |
5221 | 5222 |
5222 // Copy the descriptors, inserting a descriptor. | 5223 // Copy the descriptors, inserting a descriptor. |
5223 for (int i = 0; i < old_size; ++i) { | 5224 for (int i = 0; i < old_size; ++i) { |
5224 new_descriptors->CopyFrom(i, descriptors, i, witness); | 5225 new_descriptors->CopyFrom(i, descriptors, i, witness); |
5225 } | 5226 } |
5226 | 5227 |
5227 new_descriptors->Set(old_size, descriptor, witness); | 5228 if (old_size != descriptors->number_of_descriptors()) { |
5228 new_descriptors->Sort(); | 5229 new_descriptors->SetNumberOfDescriptors(new_size); |
| 5230 new_descriptors->Set(old_size, descriptor, witness); |
| 5231 new_descriptors->Sort(); |
| 5232 } else { |
| 5233 new_descriptors->Append(descriptor, witness); |
| 5234 } |
5229 | 5235 |
5230 return CopyReplaceDescriptors(new_descriptors, descriptor->GetKey(), flag); | 5236 String* key = descriptor->GetKey(); |
| 5237 |
| 5238 return CopyReplaceDescriptors(new_descriptors, key, flag); |
5231 } | 5239 } |
5232 | 5240 |
5233 | 5241 |
5234 MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, | 5242 MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, |
5235 TransitionFlag flag) { | 5243 TransitionFlag flag) { |
5236 DescriptorArray* old_descriptors = instance_descriptors(); | 5244 DescriptorArray* old_descriptors = instance_descriptors(); |
5237 | 5245 |
5238 // Ensure the key is a symbol. | 5246 // Ensure the key is a symbol. |
5239 MaybeObject* maybe_result = descriptor->KeyToSymbol(); | 5247 MaybeObject* maybe_result = descriptor->KeyToSymbol(); |
5240 if (maybe_result->IsFailure()) return maybe_result; | 5248 if (maybe_result->IsFailure()) return maybe_result; |
(...skipping 830 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6071 bool FixedArray::IsEqualTo(FixedArray* other) { | 6079 bool FixedArray::IsEqualTo(FixedArray* other) { |
6072 if (length() != other->length()) return false; | 6080 if (length() != other->length()) return false; |
6073 for (int i = 0 ; i < length(); ++i) { | 6081 for (int i = 0 ; i < length(); ++i) { |
6074 if (get(i) != other->get(i)) return false; | 6082 if (get(i) != other->get(i)) return false; |
6075 } | 6083 } |
6076 return true; | 6084 return true; |
6077 } | 6085 } |
6078 #endif | 6086 #endif |
6079 | 6087 |
6080 | 6088 |
6081 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { | 6089 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) { |
6082 Heap* heap = Isolate::Current()->heap(); | 6090 Heap* heap = Isolate::Current()->heap(); |
6083 // Do not use DescriptorArray::cast on incomplete object. | 6091 // Do not use DescriptorArray::cast on incomplete object. |
| 6092 int size = number_of_descriptors + slack; |
| 6093 if (size == 0) return heap->empty_descriptor_array(); |
6084 FixedArray* result; | 6094 FixedArray* result; |
6085 if (number_of_descriptors == 0) return heap->empty_descriptor_array(); | |
6086 // Allocate the array of keys. | 6095 // Allocate the array of keys. |
6087 MaybeObject* maybe_array = | 6096 MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size)); |
6088 heap->AllocateFixedArray(LengthFor(number_of_descriptors)); | |
6089 if (!maybe_array->To(&result)) return maybe_array; | 6097 if (!maybe_array->To(&result)) return maybe_array; |
6090 | 6098 |
| 6099 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors)); |
6091 result->set(kEnumCacheIndex, Smi::FromInt(0)); | 6100 result->set(kEnumCacheIndex, Smi::FromInt(0)); |
6092 return result; | 6101 return result; |
6093 } | 6102 } |
6094 | 6103 |
6095 | 6104 |
6096 void DescriptorArray::ClearEnumCache() { | 6105 void DescriptorArray::ClearEnumCache() { |
6097 set(kEnumCacheIndex, Smi::FromInt(0)); | 6106 set(kEnumCacheIndex, Smi::FromInt(0)); |
6098 } | 6107 } |
6099 | 6108 |
6100 | 6109 |
(...skipping 1394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7495 if (transition_index == t->number_of_transitions()) return; | 7504 if (transition_index == t->number_of_transitions()) return; |
7496 } | 7505 } |
7497 | 7506 |
7498 int number_of_own_descriptors = NumberOfOwnDescriptors(); | 7507 int number_of_own_descriptors = NumberOfOwnDescriptors(); |
7499 | 7508 |
7500 if (descriptors_owner_died) { | 7509 if (descriptors_owner_died) { |
7501 if (number_of_own_descriptors > 0) { | 7510 if (number_of_own_descriptors > 0) { |
7502 int number_of_descriptors = descriptors->number_of_descriptors(); | 7511 int number_of_descriptors = descriptors->number_of_descriptors(); |
7503 int to_trim = number_of_descriptors - number_of_own_descriptors; | 7512 int to_trim = number_of_descriptors - number_of_own_descriptors; |
7504 if (to_trim > 0) { | 7513 if (to_trim > 0) { |
7505 RightTrimFixedArray<FROM_GC>( | 7514 // Maximally keep 50% of unused descriptors. |
7506 heap, descriptors, to_trim * DescriptorArray::kDescriptorSize); | 7515 int keep = Min(to_trim, number_of_own_descriptors / 2); |
| 7516 for (int i = number_of_own_descriptors; |
| 7517 i < number_of_own_descriptors + keep; |
| 7518 ++i) { |
| 7519 descriptors->EraseDescriptor(heap, i); |
| 7520 } |
| 7521 if (to_trim > keep) { |
| 7522 RightTrimFixedArray<FROM_GC>(heap, descriptors, to_trim - keep); |
| 7523 } |
| 7524 descriptors->SetNumberOfDescriptors(number_of_own_descriptors); |
7507 if (descriptors->HasEnumCache()) { | 7525 if (descriptors->HasEnumCache()) { |
7508 int live_enum = | 7526 int live_enum = |
7509 NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM); | 7527 NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM); |
7510 if (live_enum == 0) { | 7528 if (live_enum == 0) { |
7511 descriptors->ClearEnumCache(); | 7529 descriptors->ClearEnumCache(); |
7512 } else { | 7530 } else { |
7513 FixedArray* enum_cache = | 7531 FixedArray* enum_cache = |
7514 FixedArray::cast(descriptors->GetEnumCache()); | 7532 FixedArray::cast(descriptors->GetEnumCache()); |
7515 to_trim = enum_cache->length() - live_enum; | 7533 to_trim = enum_cache->length() - live_enum; |
7516 if (to_trim > 0) { | 7534 if (to_trim > 0) { |
(...skipping 5990 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13507 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13525 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
13508 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13526 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
13509 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13527 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
13510 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13528 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
13511 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13529 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
13512 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13530 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
13513 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13531 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
13514 } | 13532 } |
13515 | 13533 |
13516 } } // namespace v8::internal | 13534 } } // namespace v8::internal |
OLD | NEW |