OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/allocation-site-scopes.h" | 8 #include "src/allocation-site-scopes.h" |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/arguments.h" | 10 #include "src/arguments.h" |
(...skipping 3452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3463 ElementsKind to_kind) { | 3463 ElementsKind to_kind) { |
3464 ElementsKind from_kind = map->elements_kind(); | 3464 ElementsKind from_kind = map->elements_kind(); |
3465 | 3465 |
3466 if (from_kind == to_kind) { | 3466 if (from_kind == to_kind) { |
3467 return map; | 3467 return map; |
3468 } | 3468 } |
3469 | 3469 |
3470 bool allow_store_transition = | 3470 bool allow_store_transition = |
3471 // Only remember the map transition if there is not an already existing | 3471 // Only remember the map transition if there is not an already existing |
3472 // non-matching element transition. | 3472 // non-matching element transition. |
3473 !map->IsUndefined() && !map->is_shared() && | 3473 !map->IsUndefined() && !map->is_dictionary_map() && |
3474 IsTransitionElementsKind(from_kind); | 3474 IsTransitionElementsKind(from_kind); |
3475 | 3475 |
3476 // Only store fast element maps in ascending generality. | 3476 // Only store fast element maps in ascending generality. |
3477 if (IsFastElementsKind(to_kind)) { | 3477 if (IsFastElementsKind(to_kind)) { |
3478 allow_store_transition &= | 3478 allow_store_transition &= |
3479 IsTransitionableFastElementsKind(from_kind) && | 3479 IsTransitionableFastElementsKind(from_kind) && |
3480 IsMoreGeneralElementsKindTransition(from_kind, to_kind); | 3480 IsMoreGeneralElementsKindTransition(from_kind, to_kind); |
3481 } | 3481 } |
3482 | 3482 |
3483 if (!allow_store_transition) { | 3483 if (!allow_store_transition) { |
(...skipping 949 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4433 | 4433 |
4434 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) { | 4434 Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) { |
4435 Handle<FixedArray> array( | 4435 Handle<FixedArray> array( |
4436 isolate->factory()->NewFixedArray(kEntries, TENURED)); | 4436 isolate->factory()->NewFixedArray(kEntries, TENURED)); |
4437 return Handle<NormalizedMapCache>::cast(array); | 4437 return Handle<NormalizedMapCache>::cast(array); |
4438 } | 4438 } |
4439 | 4439 |
4440 | 4440 |
4441 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map, | 4441 MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map, |
4442 PropertyNormalizationMode mode) { | 4442 PropertyNormalizationMode mode) { |
| 4443 // Only use the cache once it is initialized. |
| 4444 if (!IsNormalizedMapCache(this)) return MaybeHandle<Map>(); |
4443 DisallowHeapAllocation no_gc; | 4445 DisallowHeapAllocation no_gc; |
4444 Object* value = FixedArray::get(GetIndex(fast_map)); | 4446 Object* value = FixedArray::get(GetIndex(fast_map)); |
4445 if (!value->IsMap() || | 4447 if (!value->IsMap() || |
4446 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) { | 4448 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) { |
4447 return MaybeHandle<Map>(); | 4449 return MaybeHandle<Map>(); |
4448 } | 4450 } |
4449 return handle(Map::cast(value)); | 4451 return handle(Map::cast(value)); |
4450 } | 4452 } |
4451 | 4453 |
4452 | 4454 |
4453 void NormalizedMapCache::Set(Handle<Map> fast_map, | 4455 void NormalizedMapCache::Set(Handle<Map> fast_map, |
4454 Handle<Map> normalized_map) { | 4456 Handle<Map> normalized_map) { |
| 4457 // Only use the cache once it is initialized. |
| 4458 if (!IsNormalizedMapCache(this)) return; |
4455 DisallowHeapAllocation no_gc; | 4459 DisallowHeapAllocation no_gc; |
4456 DCHECK(normalized_map->is_dictionary_map()); | 4460 DCHECK(normalized_map->is_dictionary_map()); |
4457 FixedArray::set(GetIndex(fast_map), *normalized_map); | 4461 FixedArray::set(GetIndex(fast_map), *normalized_map); |
4458 } | 4462 } |
4459 | 4463 |
4460 | 4464 |
4461 void NormalizedMapCache::Clear() { | 4465 void NormalizedMapCache::Clear() { |
4462 int entries = length(); | 4466 int entries = length(); |
4463 for (int i = 0; i != entries; i++) { | 4467 for (int i = 0; i != entries; i++) { |
4464 set_undefined(i); | 4468 set_undefined(i); |
(...skipping 2509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6974 PropertyNormalizationMode mode) { | 6978 PropertyNormalizationMode mode) { |
6975 DCHECK(!fast_map->is_dictionary_map()); | 6979 DCHECK(!fast_map->is_dictionary_map()); |
6976 | 6980 |
6977 Isolate* isolate = fast_map->GetIsolate(); | 6981 Isolate* isolate = fast_map->GetIsolate(); |
6978 Handle<NormalizedMapCache> cache( | 6982 Handle<NormalizedMapCache> cache( |
6979 isolate->context()->native_context()->normalized_map_cache()); | 6983 isolate->context()->native_context()->normalized_map_cache()); |
6980 | 6984 |
6981 Handle<Map> new_map; | 6985 Handle<Map> new_map; |
6982 if (cache->Get(fast_map, mode).ToHandle(&new_map)) { | 6986 if (cache->Get(fast_map, mode).ToHandle(&new_map)) { |
6983 #ifdef VERIFY_HEAP | 6987 #ifdef VERIFY_HEAP |
6984 if (FLAG_verify_heap) { | 6988 if (FLAG_verify_heap) new_map->DictionaryMapVerify(); |
6985 new_map->SharedMapVerify(); | |
6986 } | |
6987 #endif | 6989 #endif |
6988 #ifdef ENABLE_SLOW_DCHECKS | 6990 #ifdef ENABLE_SLOW_DCHECKS |
6989 if (FLAG_enable_slow_asserts) { | 6991 if (FLAG_enable_slow_asserts) { |
6990 // The cached map should match newly created normalized map bit-by-bit, | 6992 // The cached map should match newly created normalized map bit-by-bit, |
6991 // except for the code cache, which can contain some ics which can be | 6993 // except for the code cache, which can contain some ics which can be |
6992 // applied to the shared map. | 6994 // applied to the shared map. |
6993 Handle<Map> fresh = Map::CopyNormalized( | 6995 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode); |
6994 fast_map, mode, SHARED_NORMALIZED_MAP); | |
6995 | 6996 |
6996 DCHECK(memcmp(fresh->address(), | 6997 DCHECK(memcmp(fresh->address(), |
6997 new_map->address(), | 6998 new_map->address(), |
6998 Map::kCodeCacheOffset) == 0); | 6999 Map::kCodeCacheOffset) == 0); |
6999 STATIC_ASSERT(Map::kDependentCodeOffset == | 7000 STATIC_ASSERT(Map::kDependentCodeOffset == |
7000 Map::kCodeCacheOffset + kPointerSize); | 7001 Map::kCodeCacheOffset + kPointerSize); |
7001 int offset = Map::kDependentCodeOffset + kPointerSize; | 7002 int offset = Map::kDependentCodeOffset + kPointerSize; |
7002 DCHECK(memcmp(fresh->address() + offset, | 7003 DCHECK(memcmp(fresh->address() + offset, |
7003 new_map->address() + offset, | 7004 new_map->address() + offset, |
7004 Map::kSize - offset) == 0); | 7005 Map::kSize - offset) == 0); |
7005 } | 7006 } |
7006 #endif | 7007 #endif |
7007 } else { | 7008 } else { |
7008 new_map = Map::CopyNormalized(fast_map, mode, SHARED_NORMALIZED_MAP); | 7009 new_map = Map::CopyNormalized(fast_map, mode); |
7009 cache->Set(fast_map, new_map); | 7010 cache->Set(fast_map, new_map); |
7010 isolate->counters()->normalized_maps()->Increment(); | 7011 isolate->counters()->normalized_maps()->Increment(); |
7011 } | 7012 } |
7012 fast_map->NotifyLeafMapLayoutChange(); | 7013 fast_map->NotifyLeafMapLayoutChange(); |
7013 return new_map; | 7014 return new_map; |
7014 } | 7015 } |
7015 | 7016 |
7016 | 7017 |
7017 Handle<Map> Map::CopyNormalized(Handle<Map> map, | 7018 Handle<Map> Map::CopyNormalized(Handle<Map> map, |
7018 PropertyNormalizationMode mode, | 7019 PropertyNormalizationMode mode) { |
7019 NormalizedMapSharingMode sharing) { | |
7020 int new_instance_size = map->instance_size(); | 7020 int new_instance_size = map->instance_size(); |
7021 if (mode == CLEAR_INOBJECT_PROPERTIES) { | 7021 if (mode == CLEAR_INOBJECT_PROPERTIES) { |
7022 new_instance_size -= map->inobject_properties() * kPointerSize; | 7022 new_instance_size -= map->inobject_properties() * kPointerSize; |
7023 } | 7023 } |
7024 | 7024 |
7025 Handle<Map> result = RawCopy(map, new_instance_size); | 7025 Handle<Map> result = RawCopy(map, new_instance_size); |
7026 | 7026 |
7027 if (mode != CLEAR_INOBJECT_PROPERTIES) { | 7027 if (mode != CLEAR_INOBJECT_PROPERTIES) { |
7028 result->set_inobject_properties(map->inobject_properties()); | 7028 result->set_inobject_properties(map->inobject_properties()); |
7029 } | 7029 } |
7030 | 7030 |
7031 result->set_is_shared(sharing == SHARED_NORMALIZED_MAP); | |
7032 result->set_dictionary_map(true); | 7031 result->set_dictionary_map(true); |
7033 result->set_migration_target(false); | 7032 result->set_migration_target(false); |
7034 | 7033 |
7035 #ifdef VERIFY_HEAP | 7034 #ifdef VERIFY_HEAP |
7036 if (FLAG_verify_heap && result->is_shared()) { | 7035 if (FLAG_verify_heap) result->DictionaryMapVerify(); |
7037 result->SharedMapVerify(); | |
7038 } | |
7039 #endif | 7036 #endif |
7040 | 7037 |
7041 return result; | 7038 return result; |
7042 } | 7039 } |
7043 | 7040 |
7044 | 7041 |
7045 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) { | 7042 Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) { |
7046 Handle<Map> result = RawCopy(map, map->instance_size()); | 7043 Handle<Map> result = RawCopy(map, map->instance_size()); |
7047 | 7044 |
7048 // Please note instance_type and instance_size are set when allocated. | 7045 // Please note instance_type and instance_size are set when allocated. |
7049 result->set_inobject_properties(map->inobject_properties()); | 7046 result->set_inobject_properties(map->inobject_properties()); |
7050 result->set_unused_property_fields(map->unused_property_fields()); | 7047 result->set_unused_property_fields(map->unused_property_fields()); |
7051 | 7048 |
7052 result->set_pre_allocated_property_fields( | 7049 result->set_pre_allocated_property_fields( |
7053 map->pre_allocated_property_fields()); | 7050 map->pre_allocated_property_fields()); |
7054 result->set_is_shared(false); | |
7055 result->ClearCodeCache(map->GetHeap()); | 7051 result->ClearCodeCache(map->GetHeap()); |
7056 map->NotifyLeafMapLayoutChange(); | 7052 map->NotifyLeafMapLayoutChange(); |
7057 return result; | 7053 return result; |
7058 } | 7054 } |
7059 | 7055 |
7060 | 7056 |
7061 Handle<Map> Map::ShareDescriptor(Handle<Map> map, | 7057 Handle<Map> Map::ShareDescriptor(Handle<Map> map, |
7062 Handle<DescriptorArray> descriptors, | 7058 Handle<DescriptorArray> descriptors, |
7063 Descriptor* descriptor) { | 7059 Descriptor* descriptor) { |
7064 // Sanity check. This path is only to be taken if the map owns its descriptor | 7060 // Sanity check. This path is only to be taken if the map owns its descriptor |
(...skipping 2740 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9805 DCHECK(shrink_by % kEntryLength == 0); | 9801 DCHECK(shrink_by % kEntryLength == 0); |
9806 DCHECK(shrink_by <= code_map->length() - kEntriesStart); | 9802 DCHECK(shrink_by <= code_map->length() - kEntriesStart); |
9807 // Always trim even when array is cleared because of heap verifier. | 9803 // Always trim even when array is cleared because of heap verifier. |
9808 GetHeap()->RightTrimFixedArray<Heap::FROM_GC>(code_map, shrink_by); | 9804 GetHeap()->RightTrimFixedArray<Heap::FROM_GC>(code_map, shrink_by); |
9809 if (code_map->length() == kEntriesStart) { | 9805 if (code_map->length() == kEntriesStart) { |
9810 ClearOptimizedCodeMap(); | 9806 ClearOptimizedCodeMap(); |
9811 } | 9807 } |
9812 } | 9808 } |
9813 | 9809 |
9814 | 9810 |
9815 void JSObject::OptimizeAsPrototype(Handle<JSObject> object) { | 9811 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, |
| 9812 PrototypeOptimizationMode mode) { |
9816 if (object->IsGlobalObject()) return; | 9813 if (object->IsGlobalObject()) return; |
9817 | 9814 if (object->IsJSGlobalProxy()) return; |
9818 // Make sure prototypes are fast objects and their maps have the bit set | 9815 if (mode == FAST_PROTOTYPE && !object->map()->is_prototype_map()) { |
9819 // so they remain fast. | 9816 // First normalize to ensure all JSFunctions are CONSTANT. |
| 9817 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0); |
| 9818 } |
9820 if (!object->HasFastProperties()) { | 9819 if (!object->HasFastProperties()) { |
9821 MigrateSlowToFast(object, 0); | 9820 JSObject::MigrateSlowToFast(object, 0); |
| 9821 } |
| 9822 if (mode == FAST_PROTOTYPE && object->HasFastProperties() && |
| 9823 !object->map()->is_prototype_map()) { |
| 9824 Handle<Map> new_map = Map::Copy(handle(object->map())); |
| 9825 JSObject::MigrateToMap(object, new_map); |
| 9826 object->map()->set_is_prototype_map(true); |
9822 } | 9827 } |
9823 } | 9828 } |
9824 | 9829 |
9825 | 9830 |
9826 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { | 9831 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { |
9827 if (!object->map()->is_prototype_map()) return; | 9832 if (!object->map()->is_prototype_map()) return; |
9828 OptimizeAsPrototype(object); | 9833 OptimizeAsPrototype(object, FAST_PROTOTYPE); |
9829 } | 9834 } |
9830 | 9835 |
9831 | 9836 |
9832 Handle<Object> CacheInitialJSArrayMaps( | 9837 Handle<Object> CacheInitialJSArrayMaps( |
9833 Handle<Context> native_context, Handle<Map> initial_map) { | 9838 Handle<Context> native_context, Handle<Map> initial_map) { |
9834 // Replace all of the cached initial array maps in the native context with | 9839 // Replace all of the cached initial array maps in the native context with |
9835 // the appropriate transitioned elements kind maps. | 9840 // the appropriate transitioned elements kind maps. |
9836 Factory* factory = native_context->GetIsolate()->factory(); | 9841 Factory* factory = native_context->GetIsolate()->factory(); |
9837 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles( | 9842 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles( |
9838 kElementsKindCount, TENURED); | 9843 kElementsKindCount, TENURED); |
(...skipping 30 matching lines...) Expand all Loading... |
9869 // Now some logic for the maps of the objects that are created by using this | 9874 // Now some logic for the maps of the objects that are created by using this |
9870 // function as a constructor. | 9875 // function as a constructor. |
9871 if (function->has_initial_map()) { | 9876 if (function->has_initial_map()) { |
9872 // If the function has allocated the initial map replace it with a | 9877 // If the function has allocated the initial map replace it with a |
9873 // copy containing the new prototype. Also complete any in-object | 9878 // copy containing the new prototype. Also complete any in-object |
9874 // slack tracking that is in progress at this point because it is | 9879 // slack tracking that is in progress at this point because it is |
9875 // still tracking the old copy. | 9880 // still tracking the old copy. |
9876 if (function->IsInobjectSlackTrackingInProgress()) { | 9881 if (function->IsInobjectSlackTrackingInProgress()) { |
9877 function->CompleteInobjectSlackTracking(); | 9882 function->CompleteInobjectSlackTracking(); |
9878 } | 9883 } |
| 9884 |
9879 Handle<Map> initial_map(function->initial_map(), isolate); | 9885 Handle<Map> initial_map(function->initial_map(), isolate); |
9880 Handle<Map> new_map = Map::Copy(initial_map); | |
9881 new_map->set_prototype(*value); | |
9882 | 9886 |
9883 // If the function is used as the global Array function, cache the | 9887 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() && |
9884 // initial map (and transitioned versions) in the native context. | 9888 initial_map->instance_type() == JS_OBJECT_TYPE) { |
9885 Context* native_context = function->context()->native_context(); | 9889 // Put the value in the initial map field until an initial map is needed. |
9886 Object* array_function = native_context->get(Context::ARRAY_FUNCTION_INDEX); | 9890 // At that point, a new initial map is created and the prototype is put |
9887 if (array_function->IsJSFunction() && | 9891 // into the initial map where it belongs. |
9888 *function == JSFunction::cast(array_function)) { | 9892 function->set_prototype_or_initial_map(*value); |
9889 CacheInitialJSArrayMaps(handle(native_context, isolate), new_map); | 9893 } else { |
| 9894 Handle<Map> new_map = Map::Copy(initial_map); |
| 9895 JSFunction::SetInitialMap(function, new_map, value); |
| 9896 |
| 9897 // If the function is used as the global Array function, cache the |
| 9898 // initial map (and transitioned versions) in the native context. |
| 9899 Context* native_context = function->context()->native_context(); |
| 9900 Object* array_function = |
| 9901 native_context->get(Context::ARRAY_FUNCTION_INDEX); |
| 9902 if (array_function->IsJSFunction() && |
| 9903 *function == JSFunction::cast(array_function)) { |
| 9904 CacheInitialJSArrayMaps(handle(native_context, isolate), new_map); |
| 9905 } |
9890 } | 9906 } |
9891 | 9907 |
9892 JSFunction::SetInitialMap(function, new_map); | |
9893 | |
9894 // Deoptimize all code that embeds the previous initial map. | 9908 // Deoptimize all code that embeds the previous initial map. |
9895 initial_map->dependent_code()->DeoptimizeDependentCodeGroup( | 9909 initial_map->dependent_code()->DeoptimizeDependentCodeGroup( |
9896 isolate, DependentCode::kInitialMapChangedGroup); | 9910 isolate, DependentCode::kInitialMapChangedGroup); |
9897 } else { | 9911 } else { |
9898 // Put the value in the initial map field until an initial map is | 9912 // Put the value in the initial map field until an initial map is |
9899 // needed. At that point, a new initial map is created and the | 9913 // needed. At that point, a new initial map is created and the |
9900 // prototype is put into the initial map where it belongs. | 9914 // prototype is put into the initial map where it belongs. |
9901 function->set_prototype_or_initial_map(*value); | 9915 function->set_prototype_or_initial_map(*value); |
9902 } | 9916 } |
9903 isolate->heap()->ClearInstanceofCache(); | 9917 isolate->heap()->ClearInstanceofCache(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9949 return false; | 9963 return false; |
9950 } | 9964 } |
9951 #endif | 9965 #endif |
9952 | 9966 |
9953 set_map(no_prototype_map); | 9967 set_map(no_prototype_map); |
9954 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value()); | 9968 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value()); |
9955 return true; | 9969 return true; |
9956 } | 9970 } |
9957 | 9971 |
9958 | 9972 |
9959 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map) { | 9973 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map, |
9960 if (map->prototype()->IsJSObject()) { | 9974 Handle<Object> prototype) { |
9961 Handle<JSObject> js_proto = handle(JSObject::cast(map->prototype())); | 9975 if (prototype->IsJSObject()) { |
9962 if (!js_proto->map()->is_prototype_map() && | 9976 Handle<JSObject> js_proto = Handle<JSObject>::cast(prototype); |
9963 !js_proto->map()->IsGlobalObjectMap() && | 9977 JSObject::OptimizeAsPrototype(js_proto, FAST_PROTOTYPE); |
9964 !js_proto->map()->IsJSGlobalProxyMap()) { | |
9965 // Normalize and turn fast again to make all functions CONSTANT | |
9966 // properties. | |
9967 if (!js_proto->GetIsolate()->bootstrapper()->IsActive()) { | |
9968 JSObject::NormalizeProperties(js_proto, KEEP_INOBJECT_PROPERTIES, 0); | |
9969 } | |
9970 if (!js_proto->HasFastProperties()) { | |
9971 JSObject::MigrateSlowToFast(js_proto, 0); | |
9972 } | |
9973 if (js_proto->HasFastProperties()) { | |
9974 Handle<Map> new_map = Map::Copy(handle(js_proto->map())); | |
9975 JSObject::MigrateToMap(js_proto, new_map); | |
9976 js_proto->map()->set_is_prototype_map(true); | |
9977 } | |
9978 } | |
9979 } | 9978 } |
| 9979 map->set_prototype(*prototype); |
9980 function->set_prototype_or_initial_map(*map); | 9980 function->set_prototype_or_initial_map(*map); |
9981 map->set_constructor(*function); | 9981 map->set_constructor(*function); |
9982 } | 9982 } |
9983 | 9983 |
9984 | 9984 |
9985 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { | 9985 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { |
9986 if (function->has_initial_map()) return; | 9986 if (function->has_initial_map()) return; |
9987 Isolate* isolate = function->GetIsolate(); | 9987 Isolate* isolate = function->GetIsolate(); |
9988 | 9988 |
9989 // First create a new map with the size and number of in-object properties | 9989 // First create a new map with the size and number of in-object properties |
(...skipping 14 matching lines...) Expand all Loading... |
10004 | 10004 |
10005 // Fetch or allocate prototype. | 10005 // Fetch or allocate prototype. |
10006 Handle<Object> prototype; | 10006 Handle<Object> prototype; |
10007 if (function->has_instance_prototype()) { | 10007 if (function->has_instance_prototype()) { |
10008 prototype = handle(function->instance_prototype(), isolate); | 10008 prototype = handle(function->instance_prototype(), isolate); |
10009 } else { | 10009 } else { |
10010 prototype = isolate->factory()->NewFunctionPrototype(function); | 10010 prototype = isolate->factory()->NewFunctionPrototype(function); |
10011 } | 10011 } |
10012 map->set_inobject_properties(in_object_properties); | 10012 map->set_inobject_properties(in_object_properties); |
10013 map->set_unused_property_fields(in_object_properties); | 10013 map->set_unused_property_fields(in_object_properties); |
10014 map->set_prototype(*prototype); | |
10015 DCHECK(map->has_fast_object_elements()); | 10014 DCHECK(map->has_fast_object_elements()); |
10016 | 10015 |
10017 // Finally link initial map and constructor function. | 10016 // Finally link initial map and constructor function. |
10018 JSFunction::SetInitialMap(function, map); | 10017 JSFunction::SetInitialMap(function, map, Handle<JSReceiver>::cast(prototype)); |
10019 | 10018 |
10020 if (!function->shared()->is_generator()) { | 10019 if (!function->shared()->is_generator()) { |
10021 function->StartInobjectSlackTracking(); | 10020 function->StartInobjectSlackTracking(); |
10022 } | 10021 } |
10023 } | 10022 } |
10024 | 10023 |
10025 | 10024 |
10026 void JSFunction::SetInstanceClassName(String* name) { | 10025 void JSFunction::SetInstanceClassName(String* name) { |
10027 shared()->set_instance_class_name(name); | 10026 shared()->set_instance_class_name(name); |
10028 } | 10027 } |
(...skipping 1741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11770 | 11769 |
11771 | 11770 |
11772 Handle<Map> Map::PutPrototypeTransition(Handle<Map> map, | 11771 Handle<Map> Map::PutPrototypeTransition(Handle<Map> map, |
11773 Handle<Object> prototype, | 11772 Handle<Object> prototype, |
11774 Handle<Map> target_map) { | 11773 Handle<Map> target_map) { |
11775 DCHECK(target_map->IsMap()); | 11774 DCHECK(target_map->IsMap()); |
11776 DCHECK(HeapObject::cast(*prototype)->map()->IsMap()); | 11775 DCHECK(HeapObject::cast(*prototype)->map()->IsMap()); |
11777 // Don't cache prototype transition if this map is either shared, or a map of | 11776 // Don't cache prototype transition if this map is either shared, or a map of |
11778 // a prototype. | 11777 // a prototype. |
11779 if (map->is_prototype_map()) return map; | 11778 if (map->is_prototype_map()) return map; |
11780 if (map->is_shared() || !FLAG_cache_prototype_transitions) return map; | 11779 if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map; |
11781 | 11780 |
11782 const int step = kProtoTransitionElementsPerEntry; | 11781 const int step = kProtoTransitionElementsPerEntry; |
11783 const int header = kProtoTransitionHeaderSize; | 11782 const int header = kProtoTransitionHeaderSize; |
11784 | 11783 |
11785 Handle<FixedArray> cache(map->GetPrototypeTransitions()); | 11784 Handle<FixedArray> cache(map->GetPrototypeTransitions()); |
11786 int capacity = (cache->length() - header) / step; | 11785 int capacity = (cache->length() - header) / step; |
11787 int transitions = map->NumberOfProtoTransitions() + 1; | 11786 int transitions = map->NumberOfProtoTransitions() + 1; |
11788 | 11787 |
11789 if (transitions > capacity) { | 11788 if (transitions > capacity) { |
11790 if (capacity > kMaxCachedPrototypeTransitions) return map; | 11789 if (capacity > kMaxCachedPrototypeTransitions) return map; |
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12093 new_map = Copy(map); | 12092 new_map = Copy(map); |
12094 PutPrototypeTransition(map, prototype, new_map); | 12093 PutPrototypeTransition(map, prototype, new_map); |
12095 new_map->set_prototype(*prototype); | 12094 new_map->set_prototype(*prototype); |
12096 } | 12095 } |
12097 return new_map; | 12096 return new_map; |
12098 } | 12097 } |
12099 | 12098 |
12100 | 12099 |
12101 MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object, | 12100 MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object, |
12102 Handle<Object> value, | 12101 Handle<Object> value, |
12103 bool skip_hidden_prototypes) { | 12102 bool from_javascript) { |
12104 #ifdef DEBUG | 12103 #ifdef DEBUG |
12105 int size = object->Size(); | 12104 int size = object->Size(); |
12106 #endif | 12105 #endif |
12107 | 12106 |
12108 Isolate* isolate = object->GetIsolate(); | 12107 Isolate* isolate = object->GetIsolate(); |
12109 Heap* heap = isolate->heap(); | 12108 Heap* heap = isolate->heap(); |
12110 // Silently ignore the change if value is not a JSObject or null. | 12109 // Silently ignore the change if value is not a JSObject or null. |
12111 // SpiderMonkey behaves this way. | 12110 // SpiderMonkey behaves this way. |
12112 if (!value->IsJSReceiver() && !value->IsNull()) return value; | 12111 if (!value->IsJSReceiver() && !value->IsNull()) return value; |
12113 | 12112 |
(...skipping 24 matching lines...) Expand all Loading... |
12138 Handle<Object> error = isolate->factory()->NewError( | 12137 Handle<Object> error = isolate->factory()->NewError( |
12139 "cyclic_proto", HandleVector<Object>(NULL, 0)); | 12138 "cyclic_proto", HandleVector<Object>(NULL, 0)); |
12140 return isolate->Throw<Object>(error); | 12139 return isolate->Throw<Object>(error); |
12141 } | 12140 } |
12142 } | 12141 } |
12143 | 12142 |
12144 bool dictionary_elements_in_chain = | 12143 bool dictionary_elements_in_chain = |
12145 object->map()->DictionaryElementsInPrototypeChainOnly(); | 12144 object->map()->DictionaryElementsInPrototypeChainOnly(); |
12146 Handle<JSObject> real_receiver = object; | 12145 Handle<JSObject> real_receiver = object; |
12147 | 12146 |
12148 if (skip_hidden_prototypes) { | 12147 if (from_javascript) { |
12149 // Find the first object in the chain whose prototype object is not | 12148 // Find the first object in the chain whose prototype object is not |
12150 // hidden and set the new prototype on that object. | 12149 // hidden and set the new prototype on that object. |
12151 PrototypeIterator iter(isolate, real_receiver); | 12150 PrototypeIterator iter(isolate, real_receiver); |
12152 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { | 12151 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
12153 real_receiver = | 12152 real_receiver = |
12154 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | 12153 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
12155 iter.Advance(); | 12154 iter.Advance(); |
12156 } | 12155 } |
12157 } | 12156 } |
12158 | 12157 |
12159 // Set the new prototype of the object. | 12158 // Set the new prototype of the object. |
12160 Handle<Map> map(real_receiver->map()); | 12159 Handle<Map> map(real_receiver->map()); |
12161 | 12160 |
12162 // Nothing to do if prototype is already set. | 12161 // Nothing to do if prototype is already set. |
12163 if (map->prototype() == *value) return value; | 12162 if (map->prototype() == *value) return value; |
12164 | 12163 |
12165 if (value->IsJSObject()) { | 12164 if (value->IsJSObject()) { |
12166 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value)); | 12165 PrototypeOptimizationMode mode = |
| 12166 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE; |
| 12167 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value), mode); |
12167 } | 12168 } |
12168 | 12169 |
12169 Handle<Map> new_map = Map::TransitionToPrototype(map, value); | 12170 Handle<Map> new_map = Map::TransitionToPrototype(map, value); |
12170 DCHECK(new_map->prototype() == *value); | 12171 DCHECK(new_map->prototype() == *value); |
12171 JSObject::MigrateToMap(real_receiver, new_map); | 12172 JSObject::MigrateToMap(real_receiver, new_map); |
12172 | 12173 |
12173 if (!dictionary_elements_in_chain && | 12174 if (!dictionary_elements_in_chain && |
12174 new_map->DictionaryElementsInPrototypeChainOnly()) { | 12175 new_map->DictionaryElementsInPrototypeChainOnly()) { |
12175 // If the prototype chain didn't previously have element callbacks, then | 12176 // If the prototype chain didn't previously have element callbacks, then |
12176 // KeyedStoreICs need to be cleared to ensure any that involve this | 12177 // KeyedStoreICs need to be cleared to ensure any that involve this |
(...skipping 4721 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16898 #define ERROR_MESSAGES_TEXTS(C, T) T, | 16899 #define ERROR_MESSAGES_TEXTS(C, T) T, |
16899 static const char* error_messages_[] = { | 16900 static const char* error_messages_[] = { |
16900 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16901 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
16901 }; | 16902 }; |
16902 #undef ERROR_MESSAGES_TEXTS | 16903 #undef ERROR_MESSAGES_TEXTS |
16903 return error_messages_[reason]; | 16904 return error_messages_[reason]; |
16904 } | 16905 } |
16905 | 16906 |
16906 | 16907 |
16907 } } // namespace v8::internal | 16908 } } // namespace v8::internal |
OLD | NEW |