Chromium Code Reviews| 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 |