OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 2930 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2941 bool has_pending_exception; | 2941 bool has_pending_exception; |
2942 Handle<Object> argv[] = { value }; | 2942 Handle<Object> argv[] = { value }; |
2943 Execution::Call( | 2943 Execution::Call( |
2944 isolate, setter, object, ARRAY_SIZE(argv), argv, &has_pending_exception); | 2944 isolate, setter, object, ARRAY_SIZE(argv), argv, &has_pending_exception); |
2945 // Check for pending exception and return the result. | 2945 // Check for pending exception and return the result. |
2946 if (has_pending_exception) return Handle<Object>(); | 2946 if (has_pending_exception) return Handle<Object>(); |
2947 return value; | 2947 return value; |
2948 } | 2948 } |
2949 | 2949 |
2950 | 2950 |
2951 bool Map::MayHaveIndexedCallbacksInPrototypeChain() { | |
2952 Heap* heap = GetHeap(); | |
2953 | |
2954 if (has_element_callbacks()) { | |
2955 return true; | |
2956 } | |
2957 | |
2958 for (Object* pt = prototype(); | |
danno
2013/10/30 12:17:45
don't use the abbreviation, use the variable name
mvstanton
2013/10/30 18:22:28
Done.
| |
2959 pt != heap->null_value(); | |
2960 pt = pt->GetPrototype(GetIsolate())) { | |
2961 if (pt->IsJSProxy()) { | |
2962 // Be conservative, don't walk into proxies. | |
2963 return true; | |
2964 } | |
2965 | |
2966 if (JSObject::cast(pt)->map()->has_element_callbacks()) { | |
2967 return true; | |
2968 } | |
2969 } | |
2970 | |
2971 return false; | |
2972 } | |
2973 | |
2974 | |
2951 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( | 2975 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( |
2952 uint32_t index, | 2976 uint32_t index, |
2953 Object* value, | 2977 Object* value, |
2954 bool* found, | 2978 bool* found, |
2955 StrictModeFlag strict_mode) { | 2979 StrictModeFlag strict_mode) { |
2956 Heap* heap = GetHeap(); | 2980 Heap* heap = GetHeap(); |
2957 for (Object* pt = GetPrototype(); | 2981 for (Object* pt = GetPrototype(); |
2958 pt != heap->null_value(); | 2982 pt != heap->null_value(); |
2959 pt = pt->GetPrototype(GetIsolate())) { | 2983 pt = pt->GetPrototype(GetIsolate())) { |
2960 if (pt->IsJSProxy()) { | 2984 if (pt->IsJSProxy()) { |
(...skipping 1510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4471 | 4495 |
4472 | 4496 |
4473 Handle<Map> NormalizedMapCache::Get(Handle<NormalizedMapCache> cache, | 4497 Handle<Map> NormalizedMapCache::Get(Handle<NormalizedMapCache> cache, |
4474 Handle<JSObject> obj, | 4498 Handle<JSObject> obj, |
4475 PropertyNormalizationMode mode) { | 4499 PropertyNormalizationMode mode) { |
4476 int index = obj->map()->Hash() % kEntries; | 4500 int index = obj->map()->Hash() % kEntries; |
4477 Handle<Object> result = handle(cache->get(index), cache->GetIsolate()); | 4501 Handle<Object> result = handle(cache->get(index), cache->GetIsolate()); |
4478 if (result->IsMap() && | 4502 if (result->IsMap() && |
4479 Handle<Map>::cast(result)->EquivalentToForNormalization(obj->map(), | 4503 Handle<Map>::cast(result)->EquivalentToForNormalization(obj->map(), |
4480 mode)) { | 4504 mode)) { |
4505 Handle<Map> result_map = Handle<Map>::cast(result); | |
4481 #ifdef VERIFY_HEAP | 4506 #ifdef VERIFY_HEAP |
4482 if (FLAG_verify_heap) { | 4507 if (FLAG_verify_heap) { |
4483 Handle<Map>::cast(result)->SharedMapVerify(); | 4508 result_map->SharedMapVerify(); |
4484 } | 4509 } |
4485 #endif | 4510 #endif |
4486 #ifdef ENABLE_SLOW_ASSERTS | 4511 #ifdef ENABLE_SLOW_ASSERTS |
4487 if (FLAG_enable_slow_asserts) { | 4512 if (FLAG_enable_slow_asserts) { |
4488 // The cached map should match newly created normalized map bit-by-bit, | 4513 // The cached map should match newly created normalized map bit-by-bit, |
4489 // except for the code cache, which can contain some ics which can be | 4514 // except for the code cache, which can contain some ics which can be |
4490 // applied to the shared map. | 4515 // applied to the shared map. |
4491 Handle<Map> fresh = Map::CopyNormalized(handle(obj->map()), mode, | 4516 Handle<Map> fresh = Map::CopyNormalized(handle(obj->map()), mode, |
4492 SHARED_NORMALIZED_MAP); | 4517 SHARED_NORMALIZED_MAP); |
4493 | 4518 |
4494 ASSERT(memcmp(fresh->address(), | 4519 ASSERT(memcmp(fresh->address(), |
4495 Handle<Map>::cast(result)->address(), | 4520 result_map->address(), |
4496 Map::kCodeCacheOffset) == 0); | 4521 Map::kTransitionsOrBackPointerOffset) == 0); |
4497 STATIC_ASSERT(Map::kDependentCodeOffset == | 4522 STATIC_ASSERT(Map::kDependentCodeOffset == |
4498 Map::kCodeCacheOffset + kPointerSize); | 4523 Map::kTransitionsOrBackPointerOffset + 3 * kPointerSize); |
4499 int offset = Map::kDependentCodeOffset + kPointerSize; | 4524 |
4500 ASSERT(memcmp(fresh->address() + offset, | 4525 // The final fields to look at are flag fields 3 and 4. Field 3 |
danno
2013/10/30 12:17:45
Is the logic needed? I thought the conclusion was
| |
4501 Handle<Map>::cast(result)->address() + offset, | 4526 // needs special attention. |
4502 Map::kSize - offset) == 0); | 4527 STATIC_ASSERT(Map::kDependentCodeOffset + kPointerSize == |
4528 Map::kBitField3Offset); | |
4529 STATIC_ASSERT(Map::kSize - (2 * kPointerSize) == Map::kBitField3Offset); | |
4530 STATIC_ASSERT(Map::kSize - kPointerSize == Map::kBitField4Offset); | |
4531 | |
4532 int mask = Map::EnumLengthBits::kMask | | |
4533 Map::NumberOfOwnDescriptorsBits::kMask | | |
4534 Map::IsShared::kMask | | |
4535 Map::FunctionWithPrototype::kMask | | |
4536 Map::DictionaryMap::kMask | | |
4537 // OwnsDescriptors::kMask | | |
4538 Map::IsObserved::kMask | | |
4539 Map::Deprecated::kMask | | |
4540 Map::IsFrozen::kMask | | |
4541 Map::IsUnstable::kMask | | |
4542 Map::IsMigrationTarget::kMask; | |
4543 int fresh_field3 = fresh->bit_field3() & mask; | |
4544 int result_field3 = result_map->bit_field3() & mask; | |
4545 ASSERT(fresh_field3 == result_field3); | |
4546 ASSERT(fresh->bit_field4() == result_map->bit_field4()); | |
4503 } | 4547 } |
4504 #endif | 4548 #endif |
4505 return Handle<Map>::cast(result); | 4549 return result_map; |
4506 } | 4550 } |
4507 | 4551 |
4508 Isolate* isolate = cache->GetIsolate(); | 4552 Isolate* isolate = cache->GetIsolate(); |
4509 Handle<Map> map = Map::CopyNormalized(handle(obj->map()), mode, | 4553 Handle<Map> map = Map::CopyNormalized(handle(obj->map()), mode, |
4510 SHARED_NORMALIZED_MAP); | 4554 SHARED_NORMALIZED_MAP); |
4511 ASSERT(map->is_dictionary_map()); | 4555 ASSERT(map->is_dictionary_map()); |
4512 cache->set(index, *map); | 4556 cache->set(index, *map); |
4513 isolate->counters()->normalized_maps()->Increment(); | 4557 isolate->counters()->normalized_maps()->Increment(); |
4514 | 4558 |
4515 return map; | 4559 return map; |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4696 | 4740 |
4697 Handle<SeededNumberDictionary> JSObject::NormalizeElements( | 4741 Handle<SeededNumberDictionary> JSObject::NormalizeElements( |
4698 Handle<JSObject> object) { | 4742 Handle<JSObject> object) { |
4699 CALL_HEAP_FUNCTION(object->GetIsolate(), | 4743 CALL_HEAP_FUNCTION(object->GetIsolate(), |
4700 object->NormalizeElements(), | 4744 object->NormalizeElements(), |
4701 SeededNumberDictionary); | 4745 SeededNumberDictionary); |
4702 } | 4746 } |
4703 | 4747 |
4704 | 4748 |
4705 MaybeObject* JSObject::NormalizeElements() { | 4749 MaybeObject* JSObject::NormalizeElements() { |
4706 ASSERT(!HasExternalArrayElements()); | 4750 SeededNumberDictionary* dictionary; |
4707 | 4751 FixedArrayBase* array = GetElements(); |
danno
2013/10/30 12:17:45
I'd call this GetElementBackingStore(), and you mi
| |
4708 // Find the backing store. | |
4709 FixedArrayBase* array = FixedArrayBase::cast(elements()); | |
4710 Map* old_map = array->map(); | |
4711 bool is_arguments = | |
4712 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map()); | |
4713 if (is_arguments) { | |
4714 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1)); | |
4715 } | |
4716 if (array->IsDictionary()) return array; | 4752 if (array->IsDictionary()) return array; |
4717 | 4753 |
4718 ASSERT(HasFastSmiOrObjectElements() || | 4754 MaybeObject* maybe_dictionary = CreateNormalizedElements(); |
4719 HasFastDoubleElements() || | |
4720 HasFastArgumentsElements()); | |
4721 // Compute the effective length and allocate a new backing store. | |
4722 int length = IsJSArray() | |
4723 ? Smi::cast(JSArray::cast(this)->length())->value() | |
4724 : array->length(); | |
4725 int old_capacity = 0; | |
4726 int used_elements = 0; | |
4727 GetElementsCapacityAndUsage(&old_capacity, &used_elements); | |
4728 SeededNumberDictionary* dictionary; | |
4729 MaybeObject* maybe_dictionary = | |
4730 SeededNumberDictionary::Allocate(GetHeap(), used_elements); | |
4731 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | |
4732 | |
4733 maybe_dictionary = CopyFastElementsToDictionary( | |
4734 GetIsolate(), array, length, dictionary); | |
4735 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | 4755 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
4736 | 4756 |
4737 // Switch to using the dictionary as the backing storage for elements. | 4757 // Switch to using the dictionary as the backing storage for elements. |
4738 if (is_arguments) { | 4758 if (HasNonStrictArgumentsElementsMap()) { |
4739 FixedArray::cast(elements())->set(1, dictionary); | 4759 FixedArray::cast(elements())->set(1, dictionary); |
4740 } else { | 4760 } else { |
4741 // Set the new map first to satify the elements type assert in | 4761 // Set the new map first to satify the elements type assert in |
4742 // set_elements(). | 4762 // set_elements(). |
4743 Map* new_map; | 4763 Map* new_map; |
4744 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), | 4764 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), |
4745 DICTIONARY_ELEMENTS); | 4765 DICTIONARY_ELEMENTS); |
4746 if (!maybe->To(&new_map)) return maybe; | 4766 if (!maybe->To(&new_map)) return maybe; |
4747 set_map(new_map); | 4767 set_map(new_map); |
4748 set_elements(dictionary); | 4768 set_elements(dictionary); |
4749 } | 4769 } |
4750 | 4770 |
4751 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()-> | 4771 GetHeap()->isolate()->counters()->elements_to_dictionary()->Increment(); |
4752 Increment(); | |
4753 | 4772 |
4754 #ifdef DEBUG | 4773 #ifdef DEBUG |
4755 if (FLAG_trace_normalization) { | 4774 if (FLAG_trace_normalization) { |
4756 PrintF("Object elements have been normalized:\n"); | 4775 PrintF("Object elements have been normalized:\n"); |
4757 Print(); | 4776 Print(); |
4758 } | 4777 } |
4759 #endif | 4778 #endif |
4760 | 4779 |
4761 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | 4780 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
4762 return dictionary; | 4781 return dictionary; |
4763 } | 4782 } |
4764 | 4783 |
4765 | 4784 |
4785 Handle<SeededNumberDictionary> JSObject::CreateNormalizedElements( | |
4786 Handle<JSObject> object) { | |
4787 CALL_HEAP_FUNCTION(object->GetIsolate(), | |
4788 object->CreateNormalizedElements(), | |
4789 SeededNumberDictionary); | |
4790 } | |
4791 | |
4792 | |
4793 MaybeObject* JSObject::CreateNormalizedElements() { | |
4794 ASSERT(!HasExternalArrayElements()); | |
4795 | |
4796 // Find the backing store. | |
4797 FixedArrayBase* array = GetElements(); | |
4798 ASSERT(!array->IsDictionary()); | |
4799 | |
4800 ASSERT(HasFastSmiOrObjectElements() || | |
4801 HasFastDoubleElements() || | |
4802 HasFastArgumentsElements()); | |
4803 // Compute the effective length and allocate a new backing store. | |
4804 int length = IsJSArray() | |
4805 ? Smi::cast(JSArray::cast(this)->length())->value() | |
4806 : array->length(); | |
4807 int old_capacity = 0; | |
4808 int used_elements = 0; | |
4809 GetElementsCapacityAndUsage(&old_capacity, &used_elements); | |
4810 SeededNumberDictionary* dictionary; | |
4811 MaybeObject* maybe_dictionary = | |
4812 SeededNumberDictionary::Allocate(GetHeap(), used_elements); | |
4813 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | |
4814 | |
4815 maybe_dictionary = CopyFastElementsToDictionary( | |
4816 GetIsolate(), array, length, dictionary); | |
4817 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | |
4818 | |
4819 return dictionary; | |
4820 } | |
4821 | |
4822 | |
4766 Smi* JSReceiver::GenerateIdentityHash() { | 4823 Smi* JSReceiver::GenerateIdentityHash() { |
4767 Isolate* isolate = GetIsolate(); | 4824 Isolate* isolate = GetIsolate(); |
4768 | 4825 |
4769 int hash_value; | 4826 int hash_value; |
4770 int attempts = 0; | 4827 int attempts = 0; |
4771 do { | 4828 do { |
4772 // Generate a random 32-bit hash value but limit range to fit | 4829 // Generate a random 32-bit hash value but limit range to fit |
4773 // within a smi. | 4830 // within a smi. |
4774 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue; | 4831 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue; |
4775 attempts++; | 4832 attempts++; |
(...skipping 782 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5558 } | 5615 } |
5559 } | 5616 } |
5560 | 5617 |
5561 LookupResult result(isolate); | 5618 LookupResult result(isolate); |
5562 Handle<Map> old_map(object->map()); | 5619 Handle<Map> old_map(object->map()); |
5563 old_map->LookupTransition(*object, isolate->heap()->frozen_symbol(), &result); | 5620 old_map->LookupTransition(*object, isolate->heap()->frozen_symbol(), &result); |
5564 if (result.IsTransition()) { | 5621 if (result.IsTransition()) { |
5565 Map* transition_map = result.GetTransitionTarget(); | 5622 Map* transition_map = result.GetTransitionTarget(); |
5566 ASSERT(transition_map->has_dictionary_elements()); | 5623 ASSERT(transition_map->has_dictionary_elements()); |
5567 ASSERT(transition_map->is_frozen()); | 5624 ASSERT(transition_map->is_frozen()); |
5568 ASSERT(!transition_map->is_extensible()); | 5625 ASSERT(!transition_map->is_extensible()); |
danno
2013/10/30 12:17:45
nit: remove stray whitespace change.
mvstanton
2013/10/30 18:22:28
Done.
| |
5569 object->set_map(transition_map); | 5626 object->set_map(transition_map); |
5570 } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) { | 5627 } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) { |
5571 // Create a new descriptor array with fully-frozen properties | 5628 // Create a new descriptor array with fully-frozen properties |
5572 int num_descriptors = old_map->NumberOfOwnDescriptors(); | 5629 int num_descriptors = old_map->NumberOfOwnDescriptors(); |
5573 Handle<DescriptorArray> new_descriptors = | 5630 Handle<DescriptorArray> new_descriptors = |
5574 DescriptorArray::CopyUpToAddAttributes( | 5631 DescriptorArray::CopyUpToAddAttributes( |
5575 handle(old_map->instance_descriptors()), num_descriptors, FROZEN); | 5632 handle(old_map->instance_descriptors()), num_descriptors, FROZEN); |
5576 Handle<Map> new_map = Map::CopyReplaceDescriptors( | 5633 Handle<Map> new_map = Map::CopyReplaceDescriptors( |
5577 old_map, new_descriptors, INSERT_TRANSITION, | 5634 old_map, new_descriptors, INSERT_TRANSITION, |
5578 isolate->factory()->frozen_symbol()); | 5635 isolate->factory()->frozen_symbol()); |
(...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6219 } | 6276 } |
6220 } | 6277 } |
6221 return true; | 6278 return true; |
6222 } | 6279 } |
6223 | 6280 |
6224 | 6281 |
6225 void JSObject::SetElementCallback(Handle<JSObject> object, | 6282 void JSObject::SetElementCallback(Handle<JSObject> object, |
6226 uint32_t index, | 6283 uint32_t index, |
6227 Handle<Object> structure, | 6284 Handle<Object> structure, |
6228 PropertyAttributes attributes) { | 6285 PropertyAttributes attributes) { |
6286 Isolate* isolate = object->GetIsolate(); | |
6229 Heap* heap = object->GetHeap(); | 6287 Heap* heap = object->GetHeap(); |
6230 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0); | 6288 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0); |
6289 bool is_arguments = object->HasNonStrictArgumentsElements(); | |
6231 | 6290 |
6232 // Normalize elements to make this operation simple. | 6291 // Do we need to create a new dictionary? |
6233 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); | 6292 Handle<SeededNumberDictionary> new_element_dictionary; |
danno
2013/10/30 12:17:45
I think NormalizeElements will do the right thing
mvstanton
2013/10/30 18:22:28
Yep, I thought combining the move to dictionary an
| |
6293 FixedArrayBase* array = object->GetElements(); | |
6294 if (!array->IsDictionary()) { | |
6295 new_element_dictionary = CreateNormalizedElements(object); | |
6296 } | |
6297 | |
6298 if (!object->map()->has_element_callbacks()) { | |
6299 LookupResult result(isolate); | |
6300 Handle<Map> old_map(object->map()); | |
6301 old_map->LookupTransition(*object, | |
danno
2013/10/30 12:17:45
It looks like JSObject::SetObserve does almost exa
mvstanton
2013/10/30 18:22:28
addressed.
| |
6302 heap->element_callbacks_symbol(), | |
6303 &result); | |
6304 if (result.IsTransition()) { | |
6305 object->set_map(result.GetTransitionTarget()); | |
6306 } else { | |
6307 Handle<Map> new_map = Map::CopyAsElementCallbacksTransition(old_map, | |
6308 !is_arguments); | |
6309 object->set_map(*new_map); | |
6310 } | |
6311 | |
6312 ASSERT(object->map()->has_element_callbacks()); | |
6313 | |
6314 // Install the dictionary if required without doing an extra transition. | |
6315 if (!new_element_dictionary.is_null()) { | |
6316 if (is_arguments) { | |
6317 FixedArray::cast(object->elements())->set(1, *new_element_dictionary); | |
6318 } else { | |
6319 object->set_elements(*new_element_dictionary); | |
6320 } | |
6321 } | |
6322 | |
6323 // KeyedStoreICs (at least the non-generic ones) need a reset. | |
6324 // I *could* look at the maps and only reset the poly/mono ones that | |
danno
2013/10/30 12:17:45
nit: we try to avoid using "I" or "we" in comments
mvstanton
2013/10/30 18:22:28
:) done.
| |
6325 // depend on a map in this prototype chain? | |
6326 heap->ClearAllICsByKind(Code::KEYED_STORE_IC); | |
6327 } else { | |
6328 // If our map is already flagged for element callbacks, then we should | |
6329 // not have had to create a new element dictionary. | |
6330 ASSERT(new_element_dictionary.is_null()); | |
6331 } | |
6332 | |
6333 Handle<SeededNumberDictionary> dictionary = Handle<SeededNumberDictionary>( | |
6334 SeededNumberDictionary::cast(object->GetElements()), isolate); | |
6335 | |
6234 ASSERT(object->HasDictionaryElements() || | 6336 ASSERT(object->HasDictionaryElements() || |
6235 object->HasDictionaryArgumentsElements()); | 6337 object->HasDictionaryArgumentsElements()); |
6236 | 6338 |
6237 // Update the dictionary with the new CALLBACKS property. | 6339 // Update the dictionary with the new CALLBACKS property. |
6238 dictionary = SeededNumberDictionary::Set(dictionary, index, structure, | 6340 dictionary = SeededNumberDictionary::Set(dictionary, index, structure, |
6239 details); | 6341 details); |
6240 dictionary->set_requires_slow_elements(); | 6342 dictionary->set_requires_slow_elements(); |
6241 | 6343 |
6242 // Update the dictionary backing store on the object. | 6344 // Update the dictionary backing store on the object. |
6243 if (object->elements()->map() == heap->non_strict_arguments_elements_map()) { | 6345 if (is_arguments) { |
6244 // Also delete any parameter alias. | 6346 // Also delete any parameter alias. |
6245 // | 6347 // |
6246 // TODO(kmillikin): when deleting the last parameter alias we could | 6348 // TODO(kmillikin): when deleting the last parameter alias we could |
6247 // switch to a direct backing store without the parameter map. This | 6349 // switch to a direct backing store without the parameter map. This |
6248 // would allow GC of the context. | 6350 // would allow GC of the context. |
6249 FixedArray* parameter_map = FixedArray::cast(object->elements()); | 6351 FixedArray* parameter_map = FixedArray::cast(object->elements()); |
6250 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) { | 6352 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) { |
6251 parameter_map->set(index + 2, heap->the_hole_value()); | 6353 parameter_map->set(index + 2, heap->the_hole_value()); |
6252 } | 6354 } |
6253 parameter_map->set(1, *dictionary); | 6355 parameter_map->set(1, *dictionary); |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6665 result->set_constructor(constructor()); | 6767 result->set_constructor(constructor()); |
6666 result->set_bit_field(bit_field()); | 6768 result->set_bit_field(bit_field()); |
6667 result->set_bit_field2(bit_field2()); | 6769 result->set_bit_field2(bit_field2()); |
6668 int new_bit_field3 = bit_field3(); | 6770 int new_bit_field3 = bit_field3(); |
6669 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); | 6771 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); |
6670 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); | 6772 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); |
6671 new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache); | 6773 new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache); |
6672 new_bit_field3 = Deprecated::update(new_bit_field3, false); | 6774 new_bit_field3 = Deprecated::update(new_bit_field3, false); |
6673 new_bit_field3 = IsUnstable::update(new_bit_field3, false); | 6775 new_bit_field3 = IsUnstable::update(new_bit_field3, false); |
6674 result->set_bit_field3(new_bit_field3); | 6776 result->set_bit_field3(new_bit_field3); |
6777 result->set_bit_field4(bit_field4()); | |
6675 return result; | 6778 return result; |
6676 } | 6779 } |
6677 | 6780 |
6678 | 6781 |
6679 Handle<Map> Map::CopyNormalized(Handle<Map> map, | 6782 Handle<Map> Map::CopyNormalized(Handle<Map> map, |
6680 PropertyNormalizationMode mode, | 6783 PropertyNormalizationMode mode, |
6681 NormalizedMapSharingMode sharing) { | 6784 NormalizedMapSharingMode sharing) { |
6682 int new_instance_size = map->instance_size(); | 6785 int new_instance_size = map->instance_size(); |
6683 if (mode == CLEAR_INOBJECT_PROPERTIES) { | 6786 if (mode == CLEAR_INOBJECT_PROPERTIES) { |
6684 new_instance_size -= map->inobject_properties() * kPointerSize; | 6787 new_instance_size -= map->inobject_properties() * kPointerSize; |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6916 if (insert_transition) { | 7019 if (insert_transition) { |
6917 MaybeObject* added_elements = set_elements_transition_map(new_map); | 7020 MaybeObject* added_elements = set_elements_transition_map(new_map); |
6918 if (added_elements->IsFailure()) return added_elements; | 7021 if (added_elements->IsFailure()) return added_elements; |
6919 new_map->SetBackPointer(this); | 7022 new_map->SetBackPointer(this); |
6920 } | 7023 } |
6921 | 7024 |
6922 return new_map; | 7025 return new_map; |
6923 } | 7026 } |
6924 | 7027 |
6925 | 7028 |
7029 MaybeObject* Map::CopyAsElementCallbacksTransition( | |
danno
2013/10/30 12:17:45
I think with a little work, you can 100% share thi
mvstanton
2013/10/30 18:22:28
I this this in a basic way, with a protected funct
| |
7030 bool with_dictionary_elements) { | |
7031 ASSERT(!HasElementCallbacksTransition()); | |
7032 | |
7033 if (owns_descriptors()) { | |
7034 // In case the map owned its own descriptors, share the descriptors and | |
7035 // transfer ownership to the new map. | |
7036 Map* new_map; | |
7037 MaybeObject* maybe_new_map = CopyDropDescriptors(); | |
7038 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | |
7039 | |
7040 MaybeObject* added_elements = set_element_callbacks_map(new_map); | |
7041 if (added_elements->IsFailure()) return added_elements; | |
7042 | |
7043 new_map->InitializeDescriptors(instance_descriptors()); | |
7044 new_map->set_has_element_callbacks(true); | |
7045 if (with_dictionary_elements) { | |
7046 new_map->set_elements_kind(DICTIONARY_ELEMENTS); | |
7047 } | |
7048 new_map->SetBackPointer(this); | |
7049 set_owns_descriptors(false); | |
7050 return new_map; | |
7051 } | |
7052 | |
7053 // In case the map did not own its own descriptors, a split is forced by | |
7054 // copying the map; creating a new descriptor array cell. | |
7055 // Create a new free-floating map only if we are not allowed to store it. | |
7056 Map* new_map; | |
7057 MaybeObject* maybe_new_map = Copy(); | |
7058 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | |
7059 new_map->set_has_element_callbacks(true); | |
7060 if (with_dictionary_elements) { | |
7061 new_map->set_elements_kind(DICTIONARY_ELEMENTS); | |
7062 } | |
7063 | |
7064 MaybeObject* added_elements = set_element_callbacks_map(new_map); | |
7065 if (added_elements->IsFailure()) return added_elements; | |
7066 new_map->SetBackPointer(this); | |
7067 | |
7068 return new_map; | |
7069 } | |
7070 | |
7071 | |
7072 Handle<Map> Map::CopyAsElementCallbacksTransition( | |
7073 Handle<Map> map, | |
7074 bool with_dictionary_elements) { | |
7075 Isolate* isolate = map->GetIsolate(); | |
7076 CALL_HEAP_FUNCTION(isolate, | |
7077 map->CopyAsElementCallbacksTransition( | |
7078 with_dictionary_elements), | |
7079 Map); | |
7080 } | |
7081 | |
7082 | |
6926 Handle<Map> Map::CopyForObserved(Handle<Map> map) { | 7083 Handle<Map> Map::CopyForObserved(Handle<Map> map) { |
6927 ASSERT(!map->is_observed()); | 7084 ASSERT(!map->is_observed()); |
6928 | 7085 |
6929 Isolate* isolate = map->GetIsolate(); | 7086 Isolate* isolate = map->GetIsolate(); |
6930 | 7087 |
6931 // In case the map owned its own descriptors, share the descriptors and | 7088 // In case the map owned its own descriptors, share the descriptors and |
6932 // transfer ownership to the new map. | 7089 // transfer ownership to the new map. |
6933 Handle<Map> new_map; | 7090 Handle<Map> new_map; |
6934 if (map->owns_descriptors()) { | 7091 if (map->owns_descriptors()) { |
6935 new_map = Map::CopyDropDescriptors(map); | 7092 new_map = Map::CopyDropDescriptors(map); |
(...skipping 2488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9424 } | 9581 } |
9425 | 9582 |
9426 | 9583 |
9427 static bool CheckEquivalent(Map* first, Map* second) { | 9584 static bool CheckEquivalent(Map* first, Map* second) { |
9428 return | 9585 return |
9429 first->constructor() == second->constructor() && | 9586 first->constructor() == second->constructor() && |
9430 first->prototype() == second->prototype() && | 9587 first->prototype() == second->prototype() && |
9431 first->instance_type() == second->instance_type() && | 9588 first->instance_type() == second->instance_type() && |
9432 first->bit_field() == second->bit_field() && | 9589 first->bit_field() == second->bit_field() && |
9433 first->bit_field2() == second->bit_field2() && | 9590 first->bit_field2() == second->bit_field2() && |
9591 first->bit_field4() == second->bit_field4() && | |
9434 first->is_observed() == second->is_observed() && | 9592 first->is_observed() == second->is_observed() && |
9435 first->function_with_prototype() == second->function_with_prototype(); | 9593 first->function_with_prototype() == second->function_with_prototype(); |
9436 } | 9594 } |
9437 | 9595 |
9438 | 9596 |
9439 bool Map::EquivalentToForTransition(Map* other) { | 9597 bool Map::EquivalentToForTransition(Map* other) { |
9440 return CheckEquivalent(this, other); | 9598 return CheckEquivalent(this, other); |
9441 } | 9599 } |
9442 | 9600 |
9443 | 9601 |
(...skipping 1114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10558 if (--n == 0) { | 10716 if (--n == 0) { |
10559 info->set_target_cell(replace_with); | 10717 info->set_target_cell(replace_with); |
10560 return; | 10718 return; |
10561 } | 10719 } |
10562 } | 10720 } |
10563 UNREACHABLE(); | 10721 UNREACHABLE(); |
10564 } | 10722 } |
10565 | 10723 |
10566 | 10724 |
10567 void Code::ClearInlineCaches() { | 10725 void Code::ClearInlineCaches() { |
10726 ClearInlineCaches(NULL); | |
10727 } | |
10728 | |
10729 | |
10730 void Code::ClearInlineCaches(Code::Kind kind) { | |
10731 ClearInlineCaches(&kind); | |
10732 } | |
10733 | |
10734 | |
10735 void Code::ClearInlineCaches(Code::Kind* kind) { | |
10568 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | | 10736 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | |
10569 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) | | 10737 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) | |
10570 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) | | 10738 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) | |
10571 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT); | 10739 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT); |
10572 for (RelocIterator it(this, mask); !it.done(); it.next()) { | 10740 for (RelocIterator it(this, mask); !it.done(); it.next()) { |
10573 RelocInfo* info = it.rinfo(); | 10741 RelocInfo* info = it.rinfo(); |
10574 Code* target(Code::GetCodeFromTargetAddress(info->target_address())); | 10742 Code* target(Code::GetCodeFromTargetAddress(info->target_address())); |
10575 if (target->is_inline_cache_stub()) { | 10743 if (target->is_inline_cache_stub()) { |
10576 IC::Clear(this->GetIsolate(), info->pc()); | 10744 if (kind == NULL || *kind == target->kind()) { |
10745 IC::Clear(this->GetIsolate(), info->pc()); | |
10746 } | |
10577 } | 10747 } |
10578 } | 10748 } |
10579 } | 10749 } |
10580 | 10750 |
10581 | 10751 |
10582 void Code::ClearTypeFeedbackCells(Heap* heap) { | 10752 void Code::ClearTypeFeedbackCells(Heap* heap) { |
10583 if (kind() != FUNCTION) return; | 10753 if (kind() != FUNCTION) return; |
10584 Object* raw_info = type_feedback_info(); | 10754 Object* raw_info = type_feedback_info(); |
10585 if (raw_info->IsTypeFeedbackInfo()) { | 10755 if (raw_info->IsTypeFeedbackInfo()) { |
10586 TypeFeedbackCells* type_feedback_cells = | 10756 TypeFeedbackCells* type_feedback_cells = |
(...skipping 1152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
11739 pt = pt->GetPrototype(isolate)) { | 11909 pt = pt->GetPrototype(isolate)) { |
11740 if (JSReceiver::cast(pt) == *object) { | 11910 if (JSReceiver::cast(pt) == *object) { |
11741 // Cycle detected. | 11911 // Cycle detected. |
11742 Handle<Object> error = isolate->factory()->NewError( | 11912 Handle<Object> error = isolate->factory()->NewError( |
11743 "cyclic_proto", HandleVector<Object>(NULL, 0)); | 11913 "cyclic_proto", HandleVector<Object>(NULL, 0)); |
11744 isolate->Throw(*error); | 11914 isolate->Throw(*error); |
11745 return Handle<Object>(); | 11915 return Handle<Object>(); |
11746 } | 11916 } |
11747 } | 11917 } |
11748 | 11918 |
11919 bool has_element_callbacks_in_chain = | |
11920 object->map()->MayHaveIndexedCallbacksInPrototypeChain(); | |
11749 Handle<JSObject> real_receiver = object; | 11921 Handle<JSObject> real_receiver = object; |
11750 | 11922 |
11751 if (skip_hidden_prototypes) { | 11923 if (skip_hidden_prototypes) { |
11752 // Find the first object in the chain whose prototype object is not | 11924 // Find the first object in the chain whose prototype object is not |
11753 // hidden and set the new prototype on that object. | 11925 // hidden and set the new prototype on that object. |
11754 Object* current_proto = real_receiver->GetPrototype(); | 11926 Object* current_proto = real_receiver->GetPrototype(); |
11755 while (current_proto->IsJSObject() && | 11927 while (current_proto->IsJSObject() && |
11756 JSObject::cast(current_proto)->map()->is_hidden_prototype()) { | 11928 JSObject::cast(current_proto)->map()->is_hidden_prototype()) { |
11757 real_receiver = handle(JSObject::cast(current_proto), isolate); | 11929 real_receiver = handle(JSObject::cast(current_proto), isolate); |
11758 current_proto = current_proto->GetPrototype(isolate); | 11930 current_proto = current_proto->GetPrototype(isolate); |
(...skipping 12 matching lines...) Expand all Loading... | |
11771 | 11943 |
11772 Handle<Map> new_map = Map::GetPrototypeTransition(map, value); | 11944 Handle<Map> new_map = Map::GetPrototypeTransition(map, value); |
11773 if (new_map.is_null()) { | 11945 if (new_map.is_null()) { |
11774 new_map = Map::Copy(map); | 11946 new_map = Map::Copy(map); |
11775 Map::PutPrototypeTransition(map, value, new_map); | 11947 Map::PutPrototypeTransition(map, value, new_map); |
11776 new_map->set_prototype(*value); | 11948 new_map->set_prototype(*value); |
11777 } | 11949 } |
11778 ASSERT(new_map->prototype() == *value); | 11950 ASSERT(new_map->prototype() == *value); |
11779 real_receiver->set_map(*new_map); | 11951 real_receiver->set_map(*new_map); |
11780 | 11952 |
11953 if (!has_element_callbacks_in_chain && | |
11954 new_map->MayHaveIndexedCallbacksInPrototypeChain()) { | |
11955 // If our prototype chain didn't have element callbacks, and now we do | |
11956 // have them, then we need to clear KeyedStoreICs. | |
11957 object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC); | |
11958 } | |
11959 | |
11781 heap->ClearInstanceofCache(); | 11960 heap->ClearInstanceofCache(); |
11782 ASSERT(size == object->Size()); | 11961 ASSERT(size == object->Size()); |
11783 return value; | 11962 return value; |
11784 } | 11963 } |
11785 | 11964 |
11786 | 11965 |
11787 MaybeObject* JSObject::EnsureCanContainElements(Arguments* args, | 11966 MaybeObject* JSObject::EnsureCanContainElements(Arguments* args, |
11788 uint32_t first_arg, | 11967 uint32_t first_arg, |
11789 uint32_t arg_count, | 11968 uint32_t arg_count, |
11790 EnsureElementsMode mode) { | 11969 EnsureElementsMode mode) { |
(...skipping 969 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12760 MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) { | 12939 MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) { |
12761 ASSERT(!map()->is_observed()); | 12940 ASSERT(!map()->is_observed()); |
12762 ElementsKind from_kind = map()->elements_kind(); | 12941 ElementsKind from_kind = map()->elements_kind(); |
12763 | 12942 |
12764 if (IsFastHoleyElementsKind(from_kind)) { | 12943 if (IsFastHoleyElementsKind(from_kind)) { |
12765 to_kind = GetHoleyElementsKind(to_kind); | 12944 to_kind = GetHoleyElementsKind(to_kind); |
12766 } | 12945 } |
12767 | 12946 |
12768 if (from_kind == to_kind) return this; | 12947 if (from_kind == to_kind) return this; |
12769 | 12948 |
12770 MaybeObject* maybe_failure = UpdateAllocationSite(to_kind); | 12949 // Don't update the site if to_kind isn't fast |
12771 if (maybe_failure->IsFailure()) return maybe_failure; | 12950 if (IsFastElementsKind(to_kind)) { |
12951 MaybeObject* maybe_failure = UpdateAllocationSite(to_kind); | |
12952 if (maybe_failure->IsFailure()) return maybe_failure; | |
12953 } | |
12772 | 12954 |
12773 Isolate* isolate = GetIsolate(); | 12955 Isolate* isolate = GetIsolate(); |
12774 if (elements() == isolate->heap()->empty_fixed_array() || | 12956 if (elements() == isolate->heap()->empty_fixed_array() || |
12775 (IsFastSmiOrObjectElementsKind(from_kind) && | 12957 (IsFastSmiOrObjectElementsKind(from_kind) && |
12776 IsFastSmiOrObjectElementsKind(to_kind)) || | 12958 IsFastSmiOrObjectElementsKind(to_kind)) || |
12777 (from_kind == FAST_DOUBLE_ELEMENTS && | 12959 (from_kind == FAST_DOUBLE_ELEMENTS && |
12778 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) { | 12960 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) { |
12779 ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND); | 12961 ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND); |
12780 // No change is needed to the elements() buffer, the transition | 12962 // No change is needed to the elements() buffer, the transition |
12781 // only requires a map change. | 12963 // only requires a map change. |
(...skipping 3616 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
16398 #define ERROR_MESSAGES_TEXTS(C, T) T, | 16580 #define ERROR_MESSAGES_TEXTS(C, T) T, |
16399 static const char* error_messages_[] = { | 16581 static const char* error_messages_[] = { |
16400 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16582 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
16401 }; | 16583 }; |
16402 #undef ERROR_MESSAGES_TEXTS | 16584 #undef ERROR_MESSAGES_TEXTS |
16403 return error_messages_[reason]; | 16585 return error_messages_[reason]; |
16404 } | 16586 } |
16405 | 16587 |
16406 | 16588 |
16407 } } // namespace v8::internal | 16589 } } // namespace v8::internal |
OLD | NEW |