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 // 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 |