OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <sstream> | 9 #include <sstream> |
10 | 10 |
(...skipping 1008 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1019 Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate, | 1019 Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate, |
1020 Object* receiver) { | 1020 Object* receiver) { |
1021 // API calls are only supported with JSObject receivers. | 1021 // API calls are only supported with JSObject receivers. |
1022 if (!receiver->IsJSObject()) return isolate->heap()->null_value(); | 1022 if (!receiver->IsJSObject()) return isolate->heap()->null_value(); |
1023 Object* recv_type = this->signature(); | 1023 Object* recv_type = this->signature(); |
1024 // No signature, return holder. | 1024 // No signature, return holder. |
1025 if (recv_type->IsUndefined(isolate)) return receiver; | 1025 if (recv_type->IsUndefined(isolate)) return receiver; |
1026 FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type); | 1026 FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type); |
1027 // Check the receiver. | 1027 // Check the receiver. |
1028 for (PrototypeIterator iter(isolate, JSObject::cast(receiver), | 1028 for (PrototypeIterator iter(isolate, JSObject::cast(receiver), |
1029 PrototypeIterator::START_AT_RECEIVER, | 1029 kStartAtReceiver, |
1030 PrototypeIterator::END_AT_NON_HIDDEN); | 1030 PrototypeIterator::END_AT_NON_HIDDEN); |
1031 !iter.IsAtEnd(); iter.Advance()) { | 1031 !iter.IsAtEnd(); iter.Advance()) { |
1032 if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent(); | 1032 if (signature->IsTemplateFor(iter.GetCurrent())) return iter.GetCurrent(); |
1033 } | 1033 } |
1034 return isolate->heap()->null_value(); | 1034 return isolate->heap()->null_value(); |
1035 } | 1035 } |
1036 | 1036 |
1037 | 1037 |
1038 // static | 1038 // static |
1039 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor, | 1039 MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor, |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1477 details = details.set_index(enumeration_index); | 1477 details = details.set_index(enumeration_index); |
1478 property_dictionary->SetEntry(entry, name, value, details); | 1478 property_dictionary->SetEntry(entry, name, value, details); |
1479 } | 1479 } |
1480 } | 1480 } |
1481 } | 1481 } |
1482 | 1482 |
1483 // static | 1483 // static |
1484 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate, | 1484 Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate, |
1485 Handle<JSReceiver> object, | 1485 Handle<JSReceiver> object, |
1486 Handle<Object> proto) { | 1486 Handle<Object> proto) { |
1487 PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER); | 1487 PrototypeIterator iter(isolate, object, kStartAtReceiver); |
1488 while (true) { | 1488 while (true) { |
1489 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); | 1489 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); |
1490 if (iter.IsAtEnd()) return Just(false); | 1490 if (iter.IsAtEnd()) return Just(false); |
1491 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) { | 1491 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) { |
1492 return Just(true); | 1492 return Just(true); |
1493 } | 1493 } |
1494 } | 1494 } |
1495 } | 1495 } |
1496 | 1496 |
1497 Map* Object::GetRootMap(Isolate* isolate) { | 1497 Map* Object::GetRootMap(Isolate* isolate) { |
(...skipping 10357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11855 if (details.location() == kDescriptor) continue; | 11855 if (details.location() == kDescriptor) continue; |
11856 if (details.representation().IsHeapObject() || | 11856 if (details.representation().IsHeapObject() || |
11857 details.representation().IsTagged()) { | 11857 details.representation().IsTagged()) { |
11858 FieldIndex index = FieldIndex::ForDescriptor(map, i); | 11858 FieldIndex index = FieldIndex::ForDescriptor(map, i); |
11859 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true; | 11859 if (object->RawFastPropertyAt(index)->IsJSFunction()) return true; |
11860 } | 11860 } |
11861 } | 11861 } |
11862 return false; | 11862 return false; |
11863 } | 11863 } |
11864 | 11864 |
| 11865 // static |
| 11866 void JSObject::MakePrototypesFast(Handle<Object> receiver, |
| 11867 WhereToStart where_to_start, |
| 11868 Isolate* isolate) { |
| 11869 if (!receiver->IsJSReceiver()) return; |
| 11870 for (PrototypeIterator iter(isolate, Handle<JSReceiver>::cast(receiver), |
| 11871 where_to_start); |
| 11872 !iter.IsAtEnd(); iter.Advance()) { |
| 11873 Handle<Object> current = PrototypeIterator::GetCurrent(iter); |
| 11874 if (!current->IsJSObject()) return; |
| 11875 Handle<JSObject> current_obj = Handle<JSObject>::cast(current); |
| 11876 Map* current_map = current_obj->map(); |
| 11877 if (current_map->is_prototype_map() && |
| 11878 !current_map->should_be_fast_prototype_map()) { |
| 11879 Handle<Map> map(current_map); |
| 11880 Map::SetShouldBeFastPrototypeMap(map, true, isolate); |
| 11881 JSObject::OptimizeAsPrototype(current_obj, FAST_PROTOTYPE); |
| 11882 } |
| 11883 } |
| 11884 } |
11865 | 11885 |
11866 // static | 11886 // static |
11867 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, | 11887 void JSObject::OptimizeAsPrototype(Handle<JSObject> object, |
11868 PrototypeOptimizationMode mode) { | 11888 PrototypeOptimizationMode mode) { |
11869 if (object->IsJSGlobalObject()) return; | 11889 if (object->IsJSGlobalObject()) return; |
11870 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) { | 11890 if (mode == FAST_PROTOTYPE && PrototypeBenefitsFromNormalization(object)) { |
11871 // First normalize to ensure all JSFunctions are DATA_CONSTANT. | 11891 // First normalize to ensure all JSFunctions are DATA_CONSTANT. |
11872 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, | 11892 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, |
11873 "NormalizeAsPrototype"); | 11893 "NormalizeAsPrototype"); |
11874 } | 11894 } |
11875 Handle<Map> previous_map(object->map()); | 11895 Handle<Map> previous_map(object->map()); |
11876 if (!object->HasFastProperties()) { | 11896 if (object->map()->is_prototype_map()) { |
11877 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); | 11897 if (object->map()->should_be_fast_prototype_map() && |
11878 } | 11898 !object->HasFastProperties()) { |
11879 if (!object->map()->is_prototype_map()) { | 11899 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); |
| 11900 } |
| 11901 } else { |
11880 if (object->map() == *previous_map) { | 11902 if (object->map() == *previous_map) { |
11881 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); | 11903 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype"); |
11882 JSObject::MigrateToMap(object, new_map); | 11904 JSObject::MigrateToMap(object, new_map); |
11883 } | 11905 } |
11884 object->map()->set_is_prototype_map(true); | 11906 object->map()->set_is_prototype_map(true); |
11885 | 11907 |
11886 // Replace the pointer to the exact constructor with the Object function | 11908 // Replace the pointer to the exact constructor with the Object function |
11887 // from the same context if undetectable from JS. This is to avoid keeping | 11909 // from the same context if undetectable from JS. This is to avoid keeping |
11888 // memory alive unnecessarily. | 11910 // memory alive unnecessarily. |
11889 Object* maybe_constructor = object->map()->GetConstructor(); | 11911 Object* maybe_constructor = object->map()->GetConstructor(); |
11890 if (maybe_constructor->IsJSFunction()) { | 11912 if (maybe_constructor->IsJSFunction()) { |
11891 JSFunction* constructor = JSFunction::cast(maybe_constructor); | 11913 JSFunction* constructor = JSFunction::cast(maybe_constructor); |
11892 Isolate* isolate = object->GetIsolate(); | 11914 Isolate* isolate = object->GetIsolate(); |
11893 if (!constructor->shared()->IsApiFunction() && | 11915 if (!constructor->shared()->IsApiFunction() && |
11894 object->class_name() == isolate->heap()->Object_string()) { | 11916 object->class_name() == isolate->heap()->Object_string()) { |
11895 Context* context = constructor->context()->native_context(); | 11917 Context* context = constructor->context()->native_context(); |
11896 JSFunction* object_function = context->object_function(); | 11918 JSFunction* object_function = context->object_function(); |
11897 object->map()->SetConstructor(object_function); | 11919 object->map()->SetConstructor(object_function); |
11898 } | 11920 } |
11899 } | 11921 } |
11900 } | 11922 } |
11901 } | 11923 } |
11902 | 11924 |
11903 | 11925 |
11904 // static | 11926 // static |
11905 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { | 11927 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { |
11906 if (!object->map()->is_prototype_map()) return; | 11928 if (!object->map()->is_prototype_map()) return; |
| 11929 if (!object->map()->should_be_fast_prototype_map()) return; |
11907 OptimizeAsPrototype(object, FAST_PROTOTYPE); | 11930 OptimizeAsPrototype(object, FAST_PROTOTYPE); |
11908 } | 11931 } |
11909 | 11932 |
11910 | 11933 |
11911 // static | 11934 // static |
11912 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) { | 11935 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) { |
11913 // Contract: In line with InvalidatePrototypeChains()'s requirements, | 11936 // Contract: In line with InvalidatePrototypeChains()'s requirements, |
11914 // leaf maps don't need to register as users, only prototypes do. | 11937 // leaf maps don't need to register as users, only prototypes do. |
11915 DCHECK(user->is_prototype_map()); | 11938 DCHECK(user->is_prototype_map()); |
11916 | 11939 |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12038 Isolate* isolate) { | 12061 Isolate* isolate) { |
12039 Object* maybe_proto_info = prototype_map->prototype_info(); | 12062 Object* maybe_proto_info = prototype_map->prototype_info(); |
12040 if (maybe_proto_info->IsPrototypeInfo()) { | 12063 if (maybe_proto_info->IsPrototypeInfo()) { |
12041 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); | 12064 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); |
12042 } | 12065 } |
12043 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); | 12066 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); |
12044 prototype_map->set_prototype_info(*proto_info); | 12067 prototype_map->set_prototype_info(*proto_info); |
12045 return proto_info; | 12068 return proto_info; |
12046 } | 12069 } |
12047 | 12070 |
| 12071 // static |
| 12072 void Map::SetShouldBeFastPrototypeMap(Handle<Map> map, bool value, |
| 12073 Isolate* isolate) { |
| 12074 if (value == false && !map->prototype_info()->IsPrototypeInfo()) { |
| 12075 // "False" is the implicit default value, so there's nothing to do. |
| 12076 return; |
| 12077 } |
| 12078 GetOrCreatePrototypeInfo(map, isolate)->set_should_be_fast_map(value); |
| 12079 } |
12048 | 12080 |
12049 // static | 12081 // static |
12050 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, | 12082 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, |
12051 Isolate* isolate) { | 12083 Isolate* isolate) { |
12052 Handle<Object> maybe_prototype(map->prototype(), isolate); | 12084 Handle<Object> maybe_prototype(map->prototype(), isolate); |
12053 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null(); | 12085 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null(); |
12054 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); | 12086 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); |
12055 // Ensure the prototype is registered with its own prototypes so its cell | 12087 // Ensure the prototype is registered with its own prototypes so its cell |
12056 // will be invalidated when necessary. | 12088 // will be invalidated when necessary. |
12057 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate), | 12089 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate), |
(...skipping 976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13034 shared()->expected_nof_properties(), | 13066 shared()->expected_nof_properties(), |
13035 instance_size, in_object_properties); | 13067 instance_size, in_object_properties); |
13036 } | 13068 } |
13037 | 13069 |
13038 | 13070 |
13039 void JSFunction::CalculateInstanceSizeForDerivedClass( | 13071 void JSFunction::CalculateInstanceSizeForDerivedClass( |
13040 InstanceType instance_type, int requested_internal_fields, | 13072 InstanceType instance_type, int requested_internal_fields, |
13041 int* instance_size, int* in_object_properties) { | 13073 int* instance_size, int* in_object_properties) { |
13042 Isolate* isolate = GetIsolate(); | 13074 Isolate* isolate = GetIsolate(); |
13043 int expected_nof_properties = 0; | 13075 int expected_nof_properties = 0; |
13044 for (PrototypeIterator iter(isolate, this, | 13076 for (PrototypeIterator iter(isolate, this, kStartAtReceiver); !iter.IsAtEnd(); |
13045 PrototypeIterator::START_AT_RECEIVER); | 13077 iter.Advance()) { |
13046 !iter.IsAtEnd(); iter.Advance()) { | |
13047 JSReceiver* current = iter.GetCurrent<JSReceiver>(); | 13078 JSReceiver* current = iter.GetCurrent<JSReceiver>(); |
13048 if (!current->IsJSFunction()) break; | 13079 if (!current->IsJSFunction()) break; |
13049 JSFunction* func = JSFunction::cast(current); | 13080 JSFunction* func = JSFunction::cast(current); |
13050 SharedFunctionInfo* shared = func->shared(); | 13081 SharedFunctionInfo* shared = func->shared(); |
13051 expected_nof_properties += shared->expected_nof_properties(); | 13082 expected_nof_properties += shared->expected_nof_properties(); |
13052 if (!IsSubclassConstructor(shared->kind())) { | 13083 if (!IsSubclassConstructor(shared->kind())) { |
13053 break; | 13084 break; |
13054 } | 13085 } |
13055 } | 13086 } |
13056 CalculateInstanceSizeHelper(instance_type, requested_internal_fields, | 13087 CalculateInstanceSizeHelper(instance_type, requested_internal_fields, |
(...skipping 1803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14860 if (!value->IsJSReceiver() && !value->IsNull()) return Just(true); | 14891 if (!value->IsJSReceiver() && !value->IsNull()) return Just(true); |
14861 | 14892 |
14862 bool dictionary_elements_in_chain = | 14893 bool dictionary_elements_in_chain = |
14863 object->map()->DictionaryElementsInPrototypeChainOnly(); | 14894 object->map()->DictionaryElementsInPrototypeChainOnly(); |
14864 | 14895 |
14865 bool all_extensible = object->map()->is_extensible(); | 14896 bool all_extensible = object->map()->is_extensible(); |
14866 Handle<JSObject> real_receiver = object; | 14897 Handle<JSObject> real_receiver = object; |
14867 if (from_javascript) { | 14898 if (from_javascript) { |
14868 // Find the first object in the chain whose prototype object is not | 14899 // Find the first object in the chain whose prototype object is not |
14869 // hidden. | 14900 // hidden. |
14870 PrototypeIterator iter(isolate, real_receiver, | 14901 PrototypeIterator iter(isolate, real_receiver, kStartAtPrototype, |
14871 PrototypeIterator::START_AT_PROTOTYPE, | |
14872 PrototypeIterator::END_AT_NON_HIDDEN); | 14902 PrototypeIterator::END_AT_NON_HIDDEN); |
14873 while (!iter.IsAtEnd()) { | 14903 while (!iter.IsAtEnd()) { |
14874 // Casting to JSObject is fine because hidden prototypes are never | 14904 // Casting to JSObject is fine because hidden prototypes are never |
14875 // JSProxies. | 14905 // JSProxies. |
14876 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); | 14906 real_receiver = PrototypeIterator::GetCurrent<JSObject>(iter); |
14877 iter.Advance(); | 14907 iter.Advance(); |
14878 all_extensible = all_extensible && real_receiver->map()->is_extensible(); | 14908 all_extensible = all_extensible && real_receiver->map()->is_extensible(); |
14879 } | 14909 } |
14880 } | 14910 } |
14881 Handle<Map> map(real_receiver->map()); | 14911 Handle<Map> map(real_receiver->map()); |
(...skipping 12 matching lines...) Expand all Loading... |
14894 if (!all_extensible) { | 14924 if (!all_extensible) { |
14895 RETURN_FAILURE(isolate, should_throw, | 14925 RETURN_FAILURE(isolate, should_throw, |
14896 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); | 14926 NewTypeError(MessageTemplate::kNonExtensibleProto, object)); |
14897 } | 14927 } |
14898 | 14928 |
14899 // Before we can set the prototype we need to be sure prototype cycles are | 14929 // Before we can set the prototype we need to be sure prototype cycles are |
14900 // prevented. It is sufficient to validate that the receiver is not in the | 14930 // prevented. It is sufficient to validate that the receiver is not in the |
14901 // new prototype chain. | 14931 // new prototype chain. |
14902 if (value->IsJSReceiver()) { | 14932 if (value->IsJSReceiver()) { |
14903 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value), | 14933 for (PrototypeIterator iter(isolate, JSReceiver::cast(*value), |
14904 PrototypeIterator::START_AT_RECEIVER); | 14934 kStartAtReceiver); |
14905 !iter.IsAtEnd(); iter.Advance()) { | 14935 !iter.IsAtEnd(); iter.Advance()) { |
14906 if (iter.GetCurrent<JSReceiver>() == *object) { | 14936 if (iter.GetCurrent<JSReceiver>() == *object) { |
14907 // Cycle detected. | 14937 // Cycle detected. |
14908 RETURN_FAILURE(isolate, should_throw, | 14938 RETURN_FAILURE(isolate, should_throw, |
14909 NewTypeError(MessageTemplate::kCyclicProto)); | 14939 NewTypeError(MessageTemplate::kCyclicProto)); |
14910 } | 14940 } |
14911 } | 14941 } |
14912 } | 14942 } |
14913 | 14943 |
14914 // Set the new prototype of the object. | 14944 // Set the new prototype of the object. |
(...skipping 3916 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
18831 if (cell->value() != *new_value) { | 18861 if (cell->value() != *new_value) { |
18832 cell->set_value(*new_value); | 18862 cell->set_value(*new_value); |
18833 Isolate* isolate = cell->GetIsolate(); | 18863 Isolate* isolate = cell->GetIsolate(); |
18834 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 18864 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
18835 isolate, DependentCode::kPropertyCellChangedGroup); | 18865 isolate, DependentCode::kPropertyCellChangedGroup); |
18836 } | 18866 } |
18837 } | 18867 } |
18838 | 18868 |
18839 } // namespace internal | 18869 } // namespace internal |
18840 } // namespace v8 | 18870 } // namespace v8 |
OLD | NEW |