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 6961 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6972 | 6972 |
6973 Handle<Map> Map::Normalize(Handle<Map> fast_map, | 6973 Handle<Map> Map::Normalize(Handle<Map> fast_map, |
6974 PropertyNormalizationMode mode) { | 6974 PropertyNormalizationMode mode) { |
6975 DCHECK(!fast_map->is_dictionary_map()); | 6975 DCHECK(!fast_map->is_dictionary_map()); |
6976 | 6976 |
6977 Isolate* isolate = fast_map->GetIsolate(); | 6977 Isolate* isolate = fast_map->GetIsolate(); |
6978 Handle<NormalizedMapCache> cache( | 6978 Handle<NormalizedMapCache> cache( |
6979 isolate->context()->native_context()->normalized_map_cache()); | 6979 isolate->context()->native_context()->normalized_map_cache()); |
6980 | 6980 |
6981 Handle<Map> new_map; | 6981 Handle<Map> new_map; |
6982 if (cache->Get(fast_map, mode).ToHandle(&new_map)) { | 6982 if (!fast_map->is_prototype_map() && |
6983 cache->Get(fast_map, mode).ToHandle(&new_map)) { | |
6983 #ifdef VERIFY_HEAP | 6984 #ifdef VERIFY_HEAP |
6984 if (FLAG_verify_heap) { | 6985 if (FLAG_verify_heap) { |
6985 new_map->SharedMapVerify(); | 6986 new_map->SharedMapVerify(); |
6986 } | 6987 } |
6987 #endif | 6988 #endif |
6988 #ifdef ENABLE_SLOW_DCHECKS | 6989 #ifdef ENABLE_SLOW_DCHECKS |
6989 if (FLAG_enable_slow_asserts) { | 6990 if (FLAG_enable_slow_asserts) { |
6990 // The cached map should match newly created normalized map bit-by-bit, | 6991 // 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 | 6992 // except for the code cache, which can contain some ics which can be |
6992 // applied to the shared map. | 6993 // applied to the shared map. |
6993 Handle<Map> fresh = Map::CopyNormalized( | 6994 Handle<Map> fresh = Map::CopyNormalized( |
6994 fast_map, mode, SHARED_NORMALIZED_MAP); | 6995 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, SHARED_NORMALIZED_MAP); |
7009 cache->Set(fast_map, new_map); | 7010 if (!fast_map->is_prototype_map()) { |
7010 isolate->counters()->normalized_maps()->Increment(); | 7011 cache->Set(fast_map, new_map); |
7012 isolate->counters()->normalized_maps()->Increment(); | |
7013 } | |
7011 } | 7014 } |
7012 fast_map->NotifyLeafMapLayoutChange(); | 7015 fast_map->NotifyLeafMapLayoutChange(); |
7013 return new_map; | 7016 return new_map; |
7014 } | 7017 } |
7015 | 7018 |
7016 | 7019 |
7017 Handle<Map> Map::CopyNormalized(Handle<Map> map, | 7020 Handle<Map> Map::CopyNormalized(Handle<Map> map, |
7018 PropertyNormalizationMode mode, | 7021 PropertyNormalizationMode mode, |
7019 NormalizedMapSharingMode sharing) { | 7022 NormalizedMapSharingMode sharing) { |
7020 int new_instance_size = map->instance_size(); | 7023 int new_instance_size = map->instance_size(); |
(...skipping 2848 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9869 // Now some logic for the maps of the objects that are created by using this | 9872 // Now some logic for the maps of the objects that are created by using this |
9870 // function as a constructor. | 9873 // function as a constructor. |
9871 if (function->has_initial_map()) { | 9874 if (function->has_initial_map()) { |
9872 // If the function has allocated the initial map replace it with a | 9875 // If the function has allocated the initial map replace it with a |
9873 // copy containing the new prototype. Also complete any in-object | 9876 // copy containing the new prototype. Also complete any in-object |
9874 // slack tracking that is in progress at this point because it is | 9877 // slack tracking that is in progress at this point because it is |
9875 // still tracking the old copy. | 9878 // still tracking the old copy. |
9876 if (function->IsInobjectSlackTrackingInProgress()) { | 9879 if (function->IsInobjectSlackTrackingInProgress()) { |
9877 function->CompleteInobjectSlackTracking(); | 9880 function->CompleteInobjectSlackTracking(); |
9878 } | 9881 } |
9882 | |
9879 Handle<Map> initial_map(function->initial_map(), isolate); | 9883 Handle<Map> initial_map(function->initial_map(), isolate); |
9880 Handle<Map> new_map = Map::Copy(initial_map); | |
9881 new_map->set_prototype(*value); | |
9882 | 9884 |
9883 // If the function is used as the global Array function, cache the | 9885 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() && |
9884 // initial map (and transitioned versions) in the native context. | 9886 initial_map->instance_type() == JS_OBJECT_TYPE) { |
9885 Context* native_context = function->context()->native_context(); | 9887 // 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); | 9888 // At that point, a new initial map is created and the prototype is put |
9887 if (array_function->IsJSFunction() && | 9889 // into the initial map where it belongs. |
9888 *function == JSFunction::cast(array_function)) { | 9890 function->set_prototype_or_initial_map(*value); |
9889 CacheInitialJSArrayMaps(handle(native_context, isolate), new_map); | 9891 } else { |
9892 Handle<Map> new_map = Map::Copy(initial_map); | |
9893 JSFunction::SetInitialMap(function, new_map, value); | |
9894 | |
9895 // If the function is used as the global Array function, cache the | |
9896 // initial map (and transitioned versions) in the native context. | |
9897 Context* native_context = function->context()->native_context(); | |
9898 Object* array_function = | |
9899 native_context->get(Context::ARRAY_FUNCTION_INDEX); | |
9900 if (array_function->IsJSFunction() && | |
9901 *function == JSFunction::cast(array_function)) { | |
9902 CacheInitialJSArrayMaps(handle(native_context, isolate), new_map); | |
9903 } | |
9890 } | 9904 } |
9891 | 9905 |
9892 JSFunction::SetInitialMap(function, new_map); | |
9893 | |
9894 // Deoptimize all code that embeds the previous initial map. | 9906 // Deoptimize all code that embeds the previous initial map. |
9895 initial_map->dependent_code()->DeoptimizeDependentCodeGroup( | 9907 initial_map->dependent_code()->DeoptimizeDependentCodeGroup( |
9896 isolate, DependentCode::kInitialMapChangedGroup); | 9908 isolate, DependentCode::kInitialMapChangedGroup); |
9897 } else { | 9909 } else { |
9898 // Put the value in the initial map field until an initial map is | 9910 // 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 | 9911 // needed. At that point, a new initial map is created and the |
9900 // prototype is put into the initial map where it belongs. | 9912 // prototype is put into the initial map where it belongs. |
9901 function->set_prototype_or_initial_map(*value); | 9913 function->set_prototype_or_initial_map(*value); |
9902 } | 9914 } |
9903 isolate->heap()->ClearInstanceofCache(); | 9915 isolate->heap()->ClearInstanceofCache(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9949 return false; | 9961 return false; |
9950 } | 9962 } |
9951 #endif | 9963 #endif |
9952 | 9964 |
9953 set_map(no_prototype_map); | 9965 set_map(no_prototype_map); |
9954 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value()); | 9966 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value()); |
9955 return true; | 9967 return true; |
9956 } | 9968 } |
9957 | 9969 |
9958 | 9970 |
9959 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map) { | 9971 void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map, |
9960 if (map->prototype()->IsJSObject()) { | 9972 Handle<Object> prototype) { |
9961 Handle<JSObject> js_proto = handle(JSObject::cast(map->prototype())); | 9973 if (prototype->IsJSObject()) { |
9974 Handle<JSObject> js_proto = Handle<JSObject>::cast(prototype); | |
9962 if (!js_proto->map()->is_prototype_map() && | 9975 if (!js_proto->map()->is_prototype_map() && |
9963 !js_proto->map()->IsGlobalObjectMap() && | 9976 !js_proto->map()->IsGlobalObjectMap() && |
9964 !js_proto->map()->IsJSGlobalProxyMap()) { | 9977 !js_proto->map()->IsJSGlobalProxyMap()) { |
9965 // Normalize and turn fast again to make all functions CONSTANT | 9978 // Normalize and turn fast again to make all functions CONSTANT |
9966 // properties. | 9979 // properties. |
9967 if (!js_proto->GetIsolate()->bootstrapper()->IsActive()) { | 9980 if (!js_proto->GetIsolate()->bootstrapper()->IsActive()) { |
9968 JSObject::NormalizeProperties(js_proto, KEEP_INOBJECT_PROPERTIES, 0); | 9981 JSObject::NormalizeProperties(js_proto, KEEP_INOBJECT_PROPERTIES, 0); |
9969 } | 9982 } |
9970 if (!js_proto->HasFastProperties()) { | 9983 if (!js_proto->HasFastProperties()) { |
9971 JSObject::MigrateSlowToFast(js_proto, 0); | 9984 JSObject::MigrateSlowToFast(js_proto, 0); |
9972 } | 9985 } |
9973 if (js_proto->HasFastProperties()) { | 9986 if (js_proto->HasFastProperties()) { |
9974 Handle<Map> new_map = Map::Copy(handle(js_proto->map())); | 9987 Handle<Map> new_map = Map::Copy(handle(js_proto->map())); |
9975 JSObject::MigrateToMap(js_proto, new_map); | 9988 JSObject::MigrateToMap(js_proto, new_map); |
9976 js_proto->map()->set_is_prototype_map(true); | 9989 js_proto->map()->set_is_prototype_map(true); |
9977 } | 9990 } |
9978 } | 9991 } |
9979 } | 9992 } |
9993 map->set_prototype(*prototype); | |
9980 function->set_prototype_or_initial_map(*map); | 9994 function->set_prototype_or_initial_map(*map); |
9981 map->set_constructor(*function); | 9995 map->set_constructor(*function); |
9982 } | 9996 } |
9983 | 9997 |
9984 | 9998 |
9985 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { | 9999 void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) { |
9986 if (function->has_initial_map()) return; | 10000 if (function->has_initial_map()) return; |
9987 Isolate* isolate = function->GetIsolate(); | 10001 Isolate* isolate = function->GetIsolate(); |
9988 | 10002 |
9989 // First create a new map with the size and number of in-object properties | 10003 // First create a new map with the size and number of in-object properties |
(...skipping 14 matching lines...) Expand all Loading... | |
10004 | 10018 |
10005 // Fetch or allocate prototype. | 10019 // Fetch or allocate prototype. |
10006 Handle<Object> prototype; | 10020 Handle<Object> prototype; |
10007 if (function->has_instance_prototype()) { | 10021 if (function->has_instance_prototype()) { |
10008 prototype = handle(function->instance_prototype(), isolate); | 10022 prototype = handle(function->instance_prototype(), isolate); |
10009 } else { | 10023 } else { |
10010 prototype = isolate->factory()->NewFunctionPrototype(function); | 10024 prototype = isolate->factory()->NewFunctionPrototype(function); |
10011 } | 10025 } |
10012 map->set_inobject_properties(in_object_properties); | 10026 map->set_inobject_properties(in_object_properties); |
10013 map->set_unused_property_fields(in_object_properties); | 10027 map->set_unused_property_fields(in_object_properties); |
10014 map->set_prototype(*prototype); | |
10015 DCHECK(map->has_fast_object_elements()); | 10028 DCHECK(map->has_fast_object_elements()); |
10016 | 10029 |
10017 // Finally link initial map and constructor function. | 10030 // Finally link initial map and constructor function. |
10018 JSFunction::SetInitialMap(function, map); | 10031 JSFunction::SetInitialMap(function, map, Handle<JSReceiver>::cast(prototype)); |
10019 | 10032 |
10020 if (!function->shared()->is_generator()) { | 10033 if (!function->shared()->is_generator()) { |
10021 function->StartInobjectSlackTracking(); | 10034 function->StartInobjectSlackTracking(); |
10022 } | 10035 } |
10023 } | 10036 } |
10024 | 10037 |
10025 | 10038 |
10026 void JSFunction::SetInstanceClassName(String* name) { | 10039 void JSFunction::SetInstanceClassName(String* name) { |
10027 shared()->set_instance_class_name(name); | 10040 shared()->set_instance_class_name(name); |
10028 } | 10041 } |
(...skipping 2064 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12093 new_map = Copy(map); | 12106 new_map = Copy(map); |
12094 PutPrototypeTransition(map, prototype, new_map); | 12107 PutPrototypeTransition(map, prototype, new_map); |
12095 new_map->set_prototype(*prototype); | 12108 new_map->set_prototype(*prototype); |
12096 } | 12109 } |
12097 return new_map; | 12110 return new_map; |
12098 } | 12111 } |
12099 | 12112 |
12100 | 12113 |
12101 MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object, | 12114 MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object, |
12102 Handle<Object> value, | 12115 Handle<Object> value, |
12103 bool skip_hidden_prototypes) { | 12116 bool from_javascript) { |
12104 #ifdef DEBUG | 12117 #ifdef DEBUG |
12105 int size = object->Size(); | 12118 int size = object->Size(); |
12106 #endif | 12119 #endif |
12107 | 12120 |
12108 Isolate* isolate = object->GetIsolate(); | 12121 Isolate* isolate = object->GetIsolate(); |
12109 Heap* heap = isolate->heap(); | 12122 Heap* heap = isolate->heap(); |
12110 // Silently ignore the change if value is not a JSObject or null. | 12123 // Silently ignore the change if value is not a JSObject or null. |
12111 // SpiderMonkey behaves this way. | 12124 // SpiderMonkey behaves this way. |
12112 if (!value->IsJSReceiver() && !value->IsNull()) return value; | 12125 if (!value->IsJSReceiver() && !value->IsNull()) return value; |
12113 | 12126 |
(...skipping 24 matching lines...) Expand all Loading... | |
12138 Handle<Object> error = isolate->factory()->NewError( | 12151 Handle<Object> error = isolate->factory()->NewError( |
12139 "cyclic_proto", HandleVector<Object>(NULL, 0)); | 12152 "cyclic_proto", HandleVector<Object>(NULL, 0)); |
12140 return isolate->Throw<Object>(error); | 12153 return isolate->Throw<Object>(error); |
12141 } | 12154 } |
12142 } | 12155 } |
12143 | 12156 |
12144 bool dictionary_elements_in_chain = | 12157 bool dictionary_elements_in_chain = |
12145 object->map()->DictionaryElementsInPrototypeChainOnly(); | 12158 object->map()->DictionaryElementsInPrototypeChainOnly(); |
12146 Handle<JSObject> real_receiver = object; | 12159 Handle<JSObject> real_receiver = object; |
12147 | 12160 |
12148 if (skip_hidden_prototypes) { | 12161 if (from_javascript) { |
12149 // Find the first object in the chain whose prototype object is not | 12162 // Find the first object in the chain whose prototype object is not |
12150 // hidden and set the new prototype on that object. | 12163 // hidden and set the new prototype on that object. |
12151 PrototypeIterator iter(isolate, real_receiver); | 12164 PrototypeIterator iter(isolate, real_receiver); |
12152 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { | 12165 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { |
12153 real_receiver = | 12166 real_receiver = |
12154 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | 12167 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
12155 iter.Advance(); | 12168 iter.Advance(); |
12156 } | 12169 } |
12157 } | 12170 } |
12158 | 12171 |
12159 // Set the new prototype of the object. | 12172 // Set the new prototype of the object. |
12160 Handle<Map> map(real_receiver->map()); | 12173 Handle<Map> map(real_receiver->map()); |
12161 | 12174 |
12162 // Nothing to do if prototype is already set. | 12175 // Nothing to do if prototype is already set. |
12163 if (map->prototype() == *value) return value; | 12176 if (map->prototype() == *value) return value; |
12164 | 12177 |
12165 if (value->IsJSObject()) { | 12178 if (value->IsJSObject()) { |
12166 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value)); | 12179 Handle<JSObject> js_proto = Handle<JSObject>::cast(value); |
12180 if (!from_javascript && !js_proto->IsJSGlobalProxy() && | |
12181 !js_proto->IsGlobalObject() && !js_proto->map()->is_prototype_map()) { | |
12182 JSObject::NormalizeProperties(js_proto, KEEP_INOBJECT_PROPERTIES, 0); | |
12183 JSObject::MigrateSlowToFast(js_proto, 0); | |
12184 if (js_proto->HasFastProperties()) { | |
12185 Handle<Map> new_map = Map::Copy(handle(js_proto->map())); | |
12186 JSObject::MigrateToMap(js_proto, new_map); | |
12187 js_proto->map()->set_is_prototype_map(true); | |
12188 } | |
Igor Sheludko
2014/08/11 07:42:13
The "make-prototype-super-fast" piece of code look
| |
12189 } else { | |
12190 JSObject::OptimizeAsPrototype(js_proto); | |
12191 } | |
12167 } | 12192 } |
12168 | 12193 |
12169 Handle<Map> new_map = Map::TransitionToPrototype(map, value); | 12194 Handle<Map> new_map = Map::TransitionToPrototype(map, value); |
12170 DCHECK(new_map->prototype() == *value); | 12195 DCHECK(new_map->prototype() == *value); |
12171 JSObject::MigrateToMap(real_receiver, new_map); | 12196 JSObject::MigrateToMap(real_receiver, new_map); |
12172 | 12197 |
12173 if (!dictionary_elements_in_chain && | 12198 if (!dictionary_elements_in_chain && |
12174 new_map->DictionaryElementsInPrototypeChainOnly()) { | 12199 new_map->DictionaryElementsInPrototypeChainOnly()) { |
12175 // If the prototype chain didn't previously have element callbacks, then | 12200 // If the prototype chain didn't previously have element callbacks, then |
12176 // KeyedStoreICs need to be cleared to ensure any that involve this | 12201 // 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, | 16923 #define ERROR_MESSAGES_TEXTS(C, T) T, |
16899 static const char* error_messages_[] = { | 16924 static const char* error_messages_[] = { |
16900 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16925 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
16901 }; | 16926 }; |
16902 #undef ERROR_MESSAGES_TEXTS | 16927 #undef ERROR_MESSAGES_TEXTS |
16903 return error_messages_[reason]; | 16928 return error_messages_[reason]; |
16904 } | 16929 } |
16905 | 16930 |
16906 | 16931 |
16907 } } // namespace v8::internal | 16932 } } // namespace v8::internal |
OLD | NEW |