| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 946 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 957 Object* value, | 957 Object* value, |
| 958 PropertyAttributes attributes) { | 958 PropertyAttributes attributes) { |
| 959 // Normalize the object if the name is not a real identifier. | 959 // Normalize the object if the name is not a real identifier. |
| 960 StringInputBuffer buffer(name); | 960 StringInputBuffer buffer(name); |
| 961 if (!Scanner::IsIdentifier(&buffer)) { | 961 if (!Scanner::IsIdentifier(&buffer)) { |
| 962 Object* obj = NormalizeProperties(); | 962 Object* obj = NormalizeProperties(); |
| 963 if (obj->IsFailure()) return obj; | 963 if (obj->IsFailure()) return obj; |
| 964 return AddSlowProperty(name, value, attributes); | 964 return AddSlowProperty(name, value, attributes); |
| 965 } | 965 } |
| 966 | 966 |
| 967 // Replace a CONSTANT_TRANSITION flag with a transition. | |
| 968 // Do this by removing it, and the standard code for adding a map transition | |
| 969 // will then run. | |
| 970 DescriptorArray* old_descriptors = map()->instance_descriptors(); | 967 DescriptorArray* old_descriptors = map()->instance_descriptors(); |
| 971 int old_name_index = old_descriptors->Search(name); | |
| 972 bool constant_transition = false; // Only used in assertions. | |
| 973 if (old_name_index != DescriptorArray::kNotFound && CONSTANT_TRANSITION == | |
| 974 PropertyDetails(old_descriptors->GetDetails(old_name_index)).type()) { | |
| 975 constant_transition = true; | |
| 976 Object* r = old_descriptors->CopyRemove(name); | |
| 977 if (r->IsFailure()) return r; | |
| 978 old_descriptors = DescriptorArray::cast(r); | |
| 979 old_name_index = DescriptorArray::kNotFound; | |
| 980 } | |
| 981 | |
| 982 // Compute the new index for new field. | 968 // Compute the new index for new field. |
| 983 int index = map()->NextFreePropertyIndex(); | 969 int index = map()->NextFreePropertyIndex(); |
| 984 | 970 |
| 985 // Allocate new instance descriptors with (name, index) added | 971 // Allocate new instance descriptors with (name, index) added |
| 986 FieldDescriptor new_field(name, index, attributes); | 972 FieldDescriptor new_field(name, index, attributes); |
| 987 Object* new_descriptors = | 973 Object* new_descriptors = |
| 988 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS); | 974 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS); |
| 989 if (new_descriptors->IsFailure()) return new_descriptors; | 975 if (new_descriptors->IsFailure()) return new_descriptors; |
| 990 | 976 |
| 991 // Only allow map transition if the object's map is NOT equal to the | 977 // Only allow map transition if the object's map is NOT equal to the |
| 992 // global object_function's map and there is not a transition for name. | 978 // global object_function's map and there is not a transition for name. |
| 993 bool allow_map_transition = | 979 bool allow_map_transition = |
| 994 !old_descriptors->Contains(name) && | 980 !old_descriptors->Contains(name) && |
| 995 (Top::context()->global_context()->object_function()->map() != map()); | 981 (Top::context()->global_context()->object_function()->map() != map()); |
| 996 ASSERT(allow_map_transition || !constant_transition); | |
| 997 | 982 |
| 998 if (map()->unused_property_fields() > 0) { | 983 ASSERT(index < properties()->length() || |
| 999 ASSERT(index < properties()->length()); | 984 map()->unused_property_fields() == 0); |
| 1000 // Allocate a new map for the object. | 985 // Allocate a new map for the object. |
| 1001 Object* r = map()->Copy(); | 986 Object* r = map()->Copy(); |
| 987 if (r->IsFailure()) return r; |
| 988 Map* new_map = Map::cast(r); |
| 989 if (allow_map_transition) { |
| 990 // Allocate new instance descriptors for the old map with map transition. |
| 991 MapTransitionDescriptor d(name, Map::cast(new_map), attributes); |
| 992 Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); |
| 1002 if (r->IsFailure()) return r; | 993 if (r->IsFailure()) return r; |
| 1003 Map* new_map = Map::cast(r); | 994 old_descriptors = DescriptorArray::cast(r); |
| 1004 if (allow_map_transition) { | 995 } |
| 1005 // Allocate new instance descriptors for the old map with map transition. | |
| 1006 MapTransitionDescriptor d(name, Map::cast(new_map), attributes); | |
| 1007 Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); | |
| 1008 if (r->IsFailure()) return r; | |
| 1009 old_descriptors = DescriptorArray::cast(r); | |
| 1010 } | |
| 1011 // We have now allocated all the necessary objects. | |
| 1012 // All the changes can be applied at once, so they are atomic. | |
| 1013 map()->set_instance_descriptors(old_descriptors); | |
| 1014 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | |
| 1015 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); | |
| 1016 set_map(new_map); | |
| 1017 properties()->set(index, value); | |
| 1018 } else { | |
| 1019 ASSERT(map()->unused_property_fields() == 0); | |
| 1020 | 996 |
| 997 |
| 998 if (map()->unused_property_fields() == 0) { |
| 1021 if (properties()->length() > kMaxFastProperties) { | 999 if (properties()->length() > kMaxFastProperties) { |
| 1022 Object* obj = NormalizeProperties(); | 1000 Object* obj = NormalizeProperties(); |
| 1023 if (obj->IsFailure()) return obj; | 1001 if (obj->IsFailure()) return obj; |
| 1024 return AddSlowProperty(name, value, attributes); | 1002 return AddSlowProperty(name, value, attributes); |
| 1025 } | 1003 } |
| 1026 | |
| 1027 static const int kExtraFields = 3; | |
| 1028 // Make room for the new value | 1004 // Make room for the new value |
| 1029 Object* values = | 1005 Object* values = |
| 1030 properties()->CopySize(properties()->length() + kExtraFields); | 1006 properties()->CopySize(properties()->length() + kFieldsAdded); |
| 1031 if (values->IsFailure()) return values; | 1007 if (values->IsFailure()) return values; |
| 1032 FixedArray::cast(values)->set(index, value); | |
| 1033 | |
| 1034 // Allocate a new map for the object. | |
| 1035 Object* r = map()->Copy(); | |
| 1036 if (r->IsFailure()) return r; | |
| 1037 Map* new_map = Map::cast(r); | |
| 1038 | |
| 1039 if (allow_map_transition) { | |
| 1040 MapTransitionDescriptor d(name, Map::cast(new_map), attributes); | |
| 1041 // Allocate new instance descriptors for the old map with map transition. | |
| 1042 Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); | |
| 1043 if (r->IsFailure()) return r; | |
| 1044 old_descriptors = DescriptorArray::cast(r); | |
| 1045 } | |
| 1046 // We have now allocated all the necessary objects. | |
| 1047 // All changes can be done at once, atomically. | |
| 1048 map()->set_instance_descriptors(old_descriptors); | |
| 1049 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | |
| 1050 new_map->set_unused_property_fields(kExtraFields - 1); | |
| 1051 set_map(new_map); | |
| 1052 set_properties(FixedArray::cast(values)); | 1008 set_properties(FixedArray::cast(values)); |
| 1009 new_map->set_unused_property_fields(kFieldsAdded - 1); |
| 1010 } else { |
| 1011 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); |
| 1053 } | 1012 } |
| 1013 // We have now allocated all the necessary objects. |
| 1014 // All the changes can be applied at once, so they are atomic. |
| 1015 map()->set_instance_descriptors(old_descriptors); |
| 1016 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
| 1017 set_map(new_map); |
| 1018 properties()->set(index, value); |
| 1054 | 1019 |
| 1055 return value; | 1020 return value; |
| 1056 } | 1021 } |
| 1057 | 1022 |
| 1058 | 1023 |
| 1059 Object* JSObject::AddConstantFunctionProperty(String* name, | 1024 Object* JSObject::AddConstantFunctionProperty(String* name, |
| 1060 JSFunction* function, | 1025 JSFunction* function, |
| 1061 PropertyAttributes attributes) { | 1026 PropertyAttributes attributes) { |
| 1062 // Allocate new instance descriptors with (name, function) added | 1027 // Allocate new instance descriptors with (name, function) added |
| 1063 ConstantFunctionDescriptor d(name, function, attributes); | 1028 ConstantFunctionDescriptor d(name, function, attributes); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1097 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS); | 1062 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS); |
| 1098 if (new_descriptors->IsFailure()) { | 1063 if (new_descriptors->IsFailure()) { |
| 1099 return function; // We have accomplished the main goal, so return success. | 1064 return function; // We have accomplished the main goal, so return success. |
| 1100 } | 1065 } |
| 1101 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | 1066 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
| 1102 | 1067 |
| 1103 return function; | 1068 return function; |
| 1104 } | 1069 } |
| 1105 | 1070 |
| 1106 | 1071 |
| 1107 Object* JSObject::ReplaceConstantFunctionProperty(String* name, | |
| 1108 Object* value) { | |
| 1109 // There are two situations to handle here: | |
| 1110 // 1: Replace a constant function with another function. | |
| 1111 // 2: Replace a constant function with an object. | |
| 1112 if (value->IsJSFunction()) { | |
| 1113 JSFunction* function = JSFunction::cast(value); | |
| 1114 | |
| 1115 Object* new_map = map()->CopyDropTransitions(); | |
| 1116 if (new_map->IsFailure()) return new_map; | |
| 1117 set_map(Map::cast(new_map)); | |
| 1118 | |
| 1119 // Replace the function entry | |
| 1120 int index = map()->instance_descriptors()->Search(name); | |
| 1121 ASSERT(index != DescriptorArray::kNotFound); | |
| 1122 map()->instance_descriptors()->ReplaceConstantFunction(index, function); | |
| 1123 } else { | |
| 1124 // Allocate new instance descriptors with updated property index. | |
| 1125 int index = map()->NextFreePropertyIndex(); | |
| 1126 Object* new_descriptors = | |
| 1127 map()->instance_descriptors()->CopyReplace(name, index, NONE); | |
| 1128 if (new_descriptors->IsFailure()) return new_descriptors; | |
| 1129 | |
| 1130 if (map()->unused_property_fields() > 0) { | |
| 1131 ASSERT(index < properties()->length()); | |
| 1132 | |
| 1133 // Allocate a new map for the object. | |
| 1134 Object* new_map = map()->Copy(); | |
| 1135 if (new_map->IsFailure()) return new_map; | |
| 1136 | |
| 1137 Map::cast(new_map)-> | |
| 1138 set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | |
| 1139 Map::cast(new_map)-> | |
| 1140 set_unused_property_fields(map()->unused_property_fields()-1); | |
| 1141 set_map(Map::cast(new_map)); | |
| 1142 properties()->set(index, value); | |
| 1143 } else { | |
| 1144 ASSERT(map()->unused_property_fields() == 0); | |
| 1145 static const int kFastNofProperties = 20; | |
| 1146 if (properties()->length() > kFastNofProperties) { | |
| 1147 Object* obj = NormalizeProperties(); | |
| 1148 if (obj->IsFailure()) return obj; | |
| 1149 return SetProperty(name, value, NONE); | |
| 1150 } | |
| 1151 | |
| 1152 static const int kExtraFields = 5; | |
| 1153 // Make room for the more properties. | |
| 1154 Object* values = | |
| 1155 properties()->CopySize(properties()->length() + kExtraFields); | |
| 1156 if (values->IsFailure()) return values; | |
| 1157 FixedArray::cast(values)->set(index, value); | |
| 1158 | |
| 1159 // Allocate a new map for the object. | |
| 1160 Object* new_map = map()->Copy(); | |
| 1161 if (new_map->IsFailure()) return new_map; | |
| 1162 | |
| 1163 Map::cast(new_map)-> | |
| 1164 set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | |
| 1165 Map::cast(new_map)-> | |
| 1166 set_unused_property_fields(kExtraFields - 1); | |
| 1167 set_map(Map::cast(new_map)); | |
| 1168 set_properties(FixedArray::cast(values)); | |
| 1169 } | |
| 1170 } | |
| 1171 return value; | |
| 1172 } | |
| 1173 | |
| 1174 | |
| 1175 // Add property in slow mode | 1072 // Add property in slow mode |
| 1176 Object* JSObject::AddSlowProperty(String* name, | 1073 Object* JSObject::AddSlowProperty(String* name, |
| 1177 Object* value, | 1074 Object* value, |
| 1178 PropertyAttributes attributes) { | 1075 PropertyAttributes attributes) { |
| 1179 PropertyDetails details = PropertyDetails(attributes, NORMAL); | 1076 PropertyDetails details = PropertyDetails(attributes, NORMAL); |
| 1180 Object* result = property_dictionary()->AddStringEntry(name, value, details); | 1077 Object* result = property_dictionary()->AddStringEntry(name, value, details); |
| 1181 if (result->IsFailure()) return result; | 1078 if (result->IsFailure()) return result; |
| 1182 if (property_dictionary() != result) { | 1079 if (property_dictionary() != result) { |
| 1183 set_properties(Dictionary::cast(result)); | 1080 set_properties(Dictionary::cast(result)); |
| 1184 } | 1081 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1216 PropertyAttributes attributes) { | 1113 PropertyAttributes attributes) { |
| 1217 // Check local property, ignore interceptor. | 1114 // Check local property, ignore interceptor. |
| 1218 LookupResult result; | 1115 LookupResult result; |
| 1219 LocalLookupRealNamedProperty(name, &result); | 1116 LocalLookupRealNamedProperty(name, &result); |
| 1220 if (result.IsValid()) return SetProperty(&result, name, value, attributes); | 1117 if (result.IsValid()) return SetProperty(&result, name, value, attributes); |
| 1221 // Add real property. | 1118 // Add real property. |
| 1222 return AddProperty(name, value, attributes); | 1119 return AddProperty(name, value, attributes); |
| 1223 } | 1120 } |
| 1224 | 1121 |
| 1225 | 1122 |
| 1123 Object* JSObject::ReplaceSlowProperty(String* name, |
| 1124 Object* value, |
| 1125 PropertyAttributes attributes) { |
| 1126 Dictionary* dictionary = property_dictionary(); |
| 1127 PropertyDetails old_details = |
| 1128 dictionary->DetailsAt(dictionary->FindStringEntry(name)); |
| 1129 int new_index = old_details.index(); |
| 1130 if (old_details.IsTransition()) new_index = 0; |
| 1131 |
| 1132 PropertyDetails new_details(attributes, NORMAL, old_details.index()); |
| 1133 Object* result = |
| 1134 property_dictionary()->SetOrAddStringEntry(name, value, new_details); |
| 1135 if (result->IsFailure()) return result; |
| 1136 if (property_dictionary() != result) { |
| 1137 set_properties(Dictionary::cast(result)); |
| 1138 } |
| 1139 return value; |
| 1140 } |
| 1141 |
| 1142 Object* JSObject::ConvertDescriptorToFieldAndMapTransition( |
| 1143 String* name, |
| 1144 Object* new_value, |
| 1145 PropertyAttributes attributes) { |
| 1146 Map* old_map = map(); |
| 1147 Object* result = ConvertDescriptorToField(name, new_value, attributes); |
| 1148 if (result->IsFailure()) return result; |
| 1149 // If we get to this point we have succeeded - do not return failure |
| 1150 // after this point. Later stuff is optional. |
| 1151 if (!HasFastProperties()) { |
| 1152 return result; |
| 1153 } |
| 1154 // Do not add transitions to the map of "new Object()". |
| 1155 if (map() == Top::context()->global_context()->object_function()->map()) { |
| 1156 return result; |
| 1157 } |
| 1158 |
| 1159 MapTransitionDescriptor transition(name, |
| 1160 map(), |
| 1161 attributes); |
| 1162 Object* new_descriptors = |
| 1163 old_map->instance_descriptors()-> |
| 1164 CopyInsert(&transition, KEEP_TRANSITIONS); |
| 1165 if (new_descriptors->IsFailure()) return result; // Yes, return _result_. |
| 1166 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
| 1167 return result; |
| 1168 } |
| 1169 |
| 1170 |
| 1171 Object* JSObject::ConvertDescriptorToField(String* name, |
| 1172 Object* new_value, |
| 1173 PropertyAttributes attributes) { |
| 1174 if (map()->unused_property_fields() == 0 && |
| 1175 properties()->length() > kMaxFastProperties) { |
| 1176 Object* obj = NormalizeProperties(); |
| 1177 if (obj->IsFailure()) return obj; |
| 1178 return ReplaceSlowProperty(name, new_value, attributes); |
| 1179 } |
| 1180 |
| 1181 int index = map()->NextFreePropertyIndex(); |
| 1182 FieldDescriptor new_field(name, index, attributes); |
| 1183 // Make a new DescriptorArray replacing an entry with FieldDescriptor. |
| 1184 Object* descriptors_unchecked = map()->instance_descriptors()-> |
| 1185 CopyInsert(&new_field, REMOVE_TRANSITIONS); |
| 1186 if (descriptors_unchecked->IsFailure()) return descriptors_unchecked; |
| 1187 DescriptorArray* new_descriptors = |
| 1188 DescriptorArray::cast(descriptors_unchecked); |
| 1189 |
| 1190 // Make a new map for the object. |
| 1191 Object* new_map_unchecked = map()->Copy(); |
| 1192 if (new_map_unchecked->IsFailure()) return new_map_unchecked; |
| 1193 Map* new_map = Map::cast(new_map_unchecked); |
| 1194 new_map->set_instance_descriptors(new_descriptors); |
| 1195 |
| 1196 // Make new properties array if necessary. |
| 1197 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer. |
| 1198 int new_unused_property_fields = map()->unused_property_fields() - 1; |
| 1199 if (map()->unused_property_fields() == 0) { |
| 1200 new_unused_property_fields = kFieldsAdded - 1; |
| 1201 Object* new_properties_unchecked = |
| 1202 properties()->CopySize(properties()->length() + kFieldsAdded); |
| 1203 if (new_properties_unchecked->IsFailure()) return new_properties_unchecked; |
| 1204 new_properties = FixedArray::cast(new_properties_unchecked); |
| 1205 } |
| 1206 |
| 1207 // Update pointers to commit changes. |
| 1208 // Object points to the new map. |
| 1209 new_map->set_unused_property_fields(new_unused_property_fields); |
| 1210 set_map(new_map); |
| 1211 if (new_properties) { |
| 1212 set_properties(FixedArray::cast(new_properties)); |
| 1213 } |
| 1214 properties()->set(index, new_value); |
| 1215 return new_value; |
| 1216 } |
| 1217 |
| 1218 |
| 1219 |
| 1226 Object* JSObject::SetPropertyWithInterceptor(String* name, | 1220 Object* JSObject::SetPropertyWithInterceptor(String* name, |
| 1227 Object* value, | 1221 Object* value, |
| 1228 PropertyAttributes attributes) { | 1222 PropertyAttributes attributes) { |
| 1229 HandleScope scope; | 1223 HandleScope scope; |
| 1230 Handle<JSObject> this_handle(this); | 1224 Handle<JSObject> this_handle(this); |
| 1231 Handle<String> name_handle(name); | 1225 Handle<String> name_handle(name); |
| 1232 Handle<Object> value_handle(value); | 1226 Handle<Object> value_handle(value); |
| 1233 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); | 1227 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); |
| 1234 if (!interceptor->setter()->IsUndefined()) { | 1228 if (!interceptor->setter()->IsUndefined()) { |
| 1235 Handle<Object> data_handle(interceptor->data()); | 1229 Handle<Object> data_handle(interceptor->data()); |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1521 return value; | 1515 return value; |
| 1522 case FIELD: | 1516 case FIELD: |
| 1523 properties()->set(result->GetFieldIndex(), value); | 1517 properties()->set(result->GetFieldIndex(), value); |
| 1524 return value; | 1518 return value; |
| 1525 case MAP_TRANSITION: | 1519 case MAP_TRANSITION: |
| 1526 if (attributes == result->GetAttributes()) { | 1520 if (attributes == result->GetAttributes()) { |
| 1527 // Only use map transition if the attributes match. | 1521 // Only use map transition if the attributes match. |
| 1528 return AddFastPropertyUsingMap(result->GetTransitionMap(), | 1522 return AddFastPropertyUsingMap(result->GetTransitionMap(), |
| 1529 name, | 1523 name, |
| 1530 value); | 1524 value); |
| 1531 } else { | |
| 1532 return AddFastProperty(name, value, attributes); | |
| 1533 } | 1525 } |
| 1526 return ConvertDescriptorToField(name, value, attributes); |
| 1534 case CONSTANT_FUNCTION: | 1527 case CONSTANT_FUNCTION: |
| 1535 if (value == result->GetConstantFunction()) return value; | 1528 if (value == result->GetConstantFunction()) return value; |
| 1536 // Only replace the function if necessary. | 1529 // Only replace the function if necessary. |
| 1537 return ReplaceConstantFunctionProperty(name, value); | 1530 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
| 1538 case CALLBACKS: | 1531 case CALLBACKS: |
| 1539 return SetPropertyWithCallback(result->GetCallbackObject(), | 1532 return SetPropertyWithCallback(result->GetCallbackObject(), |
| 1540 name, | 1533 name, |
| 1541 value, | 1534 value, |
| 1542 result->holder()); | 1535 result->holder()); |
| 1543 case INTERCEPTOR: | 1536 case INTERCEPTOR: |
| 1544 return SetPropertyWithInterceptor(name, value, attributes); | 1537 return SetPropertyWithInterceptor(name, value, attributes); |
| 1545 case CONSTANT_TRANSITION: | 1538 case CONSTANT_TRANSITION: |
| 1546 // Replace with a MAP_TRANSITION to a new map with a FIELD, even | 1539 // Replace with a MAP_TRANSITION to a new map with a FIELD, even |
| 1547 // if the value is a function. | 1540 // if the value is a function. |
| 1548 // AddProperty has been extended to do this, in this case. | 1541 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
| 1549 return AddFastProperty(name, value, attributes); | |
| 1550 case NULL_DESCRIPTOR: | 1542 case NULL_DESCRIPTOR: |
| 1551 UNREACHABLE(); | 1543 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
| 1552 default: | 1544 default: |
| 1553 UNREACHABLE(); | 1545 UNREACHABLE(); |
| 1554 } | 1546 } |
| 1555 UNREACHABLE(); | 1547 UNREACHABLE(); |
| 1556 return value; | 1548 return value; |
| 1557 } | 1549 } |
| 1558 | 1550 |
| 1559 | 1551 |
| 1560 // Set a real local property, even if it is READ_ONLY. If the property is not | 1552 // Set a real local property, even if it is READ_ONLY. If the property is not |
| 1561 // present, add it with attributes NONE. This code is an exact clone of | 1553 // present, add it with attributes NONE. This code is an exact clone of |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1573 // ADDED TO CLONE | 1565 // ADDED TO CLONE |
| 1574 LookupResult result_struct; | 1566 LookupResult result_struct; |
| 1575 LocalLookup(name, &result_struct); | 1567 LocalLookup(name, &result_struct); |
| 1576 LookupResult* result = &result_struct; | 1568 LookupResult* result = &result_struct; |
| 1577 // END ADDED TO CLONE | 1569 // END ADDED TO CLONE |
| 1578 // Check access rights if needed. | 1570 // Check access rights if needed. |
| 1579 if (IsAccessCheckNeeded() | 1571 if (IsAccessCheckNeeded() |
| 1580 && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { | 1572 && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { |
| 1581 return SetPropertyWithFailedAccessCheck(result, name, value); | 1573 return SetPropertyWithFailedAccessCheck(result, name, value); |
| 1582 } | 1574 } |
| 1583 /* | 1575 // Check for accessor in prototype chain removed here in clone. |
| 1584 REMOVED FROM CLONE | |
| 1585 if (result->IsNotFound() || !result->IsProperty()) { | |
| 1586 // We could not find a local property so let's check whether there is an | |
| 1587 // accessor that wants to handle the property. | |
| 1588 LookupResult accessor_result; | |
| 1589 LookupCallbackSetterInPrototypes(name, &accessor_result); | |
| 1590 if (accessor_result.IsValid()) { | |
| 1591 return SetPropertyWithCallback(accessor_result.GetCallbackObject(), | |
| 1592 name, | |
| 1593 value, | |
| 1594 accessor_result.holder()); | |
| 1595 } | |
| 1596 } | |
| 1597 */ | |
| 1598 if (result->IsNotFound()) { | 1576 if (result->IsNotFound()) { |
| 1599 return AddProperty(name, value, attributes); | 1577 return AddProperty(name, value, attributes); |
| 1600 } | 1578 } |
| 1601 if (!result->IsLoaded()) { | 1579 if (!result->IsLoaded()) { |
| 1602 return SetLazyProperty(result, name, value, attributes); | 1580 return SetLazyProperty(result, name, value, attributes); |
| 1603 } | 1581 } |
| 1604 /* | 1582 // Check of IsReadOnly removed from here in clone. |
| 1605 REMOVED FROM CLONE | |
| 1606 if (result->IsReadOnly() && result->IsProperty()) return value; | |
| 1607 */ | |
| 1608 // This is a real property that is not read-only, or it is a | |
| 1609 // transition or null descriptor and there are no setters in the prototypes. | |
| 1610 switch (result->type()) { | 1583 switch (result->type()) { |
| 1611 case NORMAL: | 1584 case NORMAL: |
| 1612 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value); | 1585 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value); |
| 1613 return value; | 1586 return value; |
| 1614 case FIELD: | 1587 case FIELD: |
| 1615 properties()->set(result->GetFieldIndex(), value); | 1588 properties()->set(result->GetFieldIndex(), value); |
| 1616 return value; | 1589 return value; |
| 1617 case MAP_TRANSITION: | 1590 case MAP_TRANSITION: |
| 1618 if (attributes == result->GetAttributes()) { | 1591 if (attributes == result->GetAttributes()) { |
| 1619 // Only use map transition if the attributes match. | 1592 // Only use map transition if the attributes match. |
| 1620 return AddFastPropertyUsingMap(result->GetTransitionMap(), | 1593 return AddFastPropertyUsingMap(result->GetTransitionMap(), |
| 1621 name, | 1594 name, |
| 1622 value); | 1595 value); |
| 1623 } else { | 1596 } else { |
| 1624 return AddFastProperty(name, value, attributes); | 1597 return ConvertDescriptorToField(name, value, attributes); |
| 1625 } | 1598 } |
| 1626 case CONSTANT_FUNCTION: | 1599 case CONSTANT_FUNCTION: |
| 1627 if (value == result->GetConstantFunction()) return value; | 1600 if (value == result->GetConstantFunction()) return value; |
| 1628 // Only replace the function if necessary. | 1601 // Only replace the function if necessary. |
| 1629 return ReplaceConstantFunctionProperty(name, value); | 1602 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
| 1630 case CALLBACKS: | 1603 case CALLBACKS: |
| 1631 return SetPropertyWithCallback(result->GetCallbackObject(), | 1604 return SetPropertyWithCallback(result->GetCallbackObject(), |
| 1632 name, | 1605 name, |
| 1633 value, | 1606 value, |
| 1634 result->holder()); | 1607 result->holder()); |
| 1635 case INTERCEPTOR: | 1608 case INTERCEPTOR: |
| 1636 return SetPropertyWithInterceptor(name, value, attributes); | 1609 return SetPropertyWithInterceptor(name, value, attributes); |
| 1637 case CONSTANT_TRANSITION: | 1610 case CONSTANT_TRANSITION: |
| 1638 // Replace with a MAP_TRANSITION to a new map with a FIELD, even | 1611 // Replace with a MAP_TRANSITION to a new map with a FIELD, even |
| 1639 // if the value is a function. | 1612 // if the value is a function. |
| 1640 // AddProperty has been extended to do this, in this case. | 1613 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
| 1641 return AddFastProperty(name, value, attributes); | |
| 1642 case NULL_DESCRIPTOR: | 1614 case NULL_DESCRIPTOR: |
| 1643 UNREACHABLE(); | 1615 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); |
| 1644 default: | 1616 default: |
| 1645 UNREACHABLE(); | 1617 UNREACHABLE(); |
| 1646 } | 1618 } |
| 1647 UNREACHABLE(); | 1619 UNREACHABLE(); |
| 1648 return value; | 1620 return value; |
| 1649 } | 1621 } |
| 1650 | 1622 |
| 1651 | 1623 |
| 1652 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( | 1624 PropertyAttributes JSObject::GetPropertyAttributePostInterceptor( |
| 1653 JSObject* receiver, | 1625 JSObject* receiver, |
| (...skipping 1002 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2656 FixedArray::cast(bridge_storage)-> | 2628 FixedArray::cast(bridge_storage)-> |
| 2657 set(kEnumCacheBridgeCacheIndex, new_cache); | 2629 set(kEnumCacheBridgeCacheIndex, new_cache); |
| 2658 fast_set(FixedArray::cast(bridge_storage), | 2630 fast_set(FixedArray::cast(bridge_storage), |
| 2659 kEnumCacheBridgeEnumIndex, | 2631 kEnumCacheBridgeEnumIndex, |
| 2660 get(kEnumerationIndexIndex)); | 2632 get(kEnumerationIndexIndex)); |
| 2661 set(kEnumerationIndexIndex, bridge_storage); | 2633 set(kEnumerationIndexIndex, bridge_storage); |
| 2662 } | 2634 } |
| 2663 } | 2635 } |
| 2664 | 2636 |
| 2665 | 2637 |
| 2666 void DescriptorArray::ReplaceConstantFunction(int descriptor_number, | |
| 2667 JSFunction* value) { | |
| 2668 ASSERT(!Heap::InNewSpace(value)); | |
| 2669 FixedArray* content_array = GetContentArray(); | |
| 2670 fast_set(content_array, ToValueIndex(descriptor_number), value); | |
| 2671 } | |
| 2672 | |
| 2673 | |
| 2674 Object* DescriptorArray::CopyInsert(Descriptor* descriptor, | 2638 Object* DescriptorArray::CopyInsert(Descriptor* descriptor, |
| 2675 TransitionFlag transition_flag) { | 2639 TransitionFlag transition_flag) { |
| 2676 // Transitions are only kept when inserting another transition. | 2640 // Transitions are only kept when inserting another transition. |
| 2677 // This precondition is not required by this function's implementation, but | 2641 // This precondition is not required by this function's implementation, but |
| 2678 // is currently required by the semantics of maps, so we check it. | 2642 // is currently required by the semantics of maps, so we check it. |
| 2679 // Conversely, we filter after replacing, so replacing a transition and | 2643 // Conversely, we filter after replacing, so replacing a transition and |
| 2680 // removing all other transitions is not supported. | 2644 // removing all other transitions is not supported. |
| 2681 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS; | 2645 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS; |
| 2682 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition()); | 2646 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition()); |
| 2683 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR); | 2647 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2764 if (r.IsNullDescriptor()) continue; | 2728 if (r.IsNullDescriptor()) continue; |
| 2765 if (remove_transitions && r.IsTransition()) continue; | 2729 if (remove_transitions && r.IsTransition()) continue; |
| 2766 w.WriteFrom(&r); | 2730 w.WriteFrom(&r); |
| 2767 } | 2731 } |
| 2768 ASSERT(w.eos()); | 2732 ASSERT(w.eos()); |
| 2769 | 2733 |
| 2770 return new_descriptors; | 2734 return new_descriptors; |
| 2771 } | 2735 } |
| 2772 | 2736 |
| 2773 | 2737 |
| 2774 Object* DescriptorArray::CopyReplace(String* name, | |
| 2775 int index, | |
| 2776 PropertyAttributes attributes) { | |
| 2777 // Allocate the new descriptor array. | |
| 2778 Object* result = DescriptorArray::Allocate(number_of_descriptors()); | |
| 2779 if (result->IsFailure()) return result; | |
| 2780 | |
| 2781 // Make sure only symbols are added to the instance descriptor. | |
| 2782 if (!name->IsSymbol()) { | |
| 2783 Object* result = Heap::LookupSymbol(name); | |
| 2784 if (result->IsFailure()) return result; | |
| 2785 name = String::cast(result); | |
| 2786 } | |
| 2787 | |
| 2788 DescriptorWriter w(DescriptorArray::cast(result)); | |
| 2789 for (DescriptorReader r(this); !r.eos(); r.advance()) { | |
| 2790 if (r.Equals(name)) { | |
| 2791 FieldDescriptor d(name, index, attributes); | |
| 2792 d.SetEnumerationIndex(r.GetDetails().index()); | |
| 2793 w.Write(&d); | |
| 2794 } else { | |
| 2795 w.WriteFrom(&r); | |
| 2796 } | |
| 2797 } | |
| 2798 | |
| 2799 // Copy the next enumeration index. | |
| 2800 DescriptorArray::cast(result)-> | |
| 2801 SetNextEnumerationIndex(NextEnumerationIndex()); | |
| 2802 | |
| 2803 ASSERT(w.eos()); | |
| 2804 return result; | |
| 2805 } | |
| 2806 | |
| 2807 | |
| 2808 Object* DescriptorArray::CopyRemove(String* name) { | |
| 2809 if (!name->IsSymbol()) { | |
| 2810 Object* result = Heap::LookupSymbol(name); | |
| 2811 if (result->IsFailure()) return result; | |
| 2812 name = String::cast(result); | |
| 2813 } | |
| 2814 ASSERT(name->IsSymbol()); | |
| 2815 Object* result = Allocate(number_of_descriptors() - 1); | |
| 2816 if (result->IsFailure()) return result; | |
| 2817 DescriptorArray* new_descriptors = DescriptorArray::cast(result); | |
| 2818 | |
| 2819 // Set the enumeration index in the descriptors and set the enumeration index | |
| 2820 // in the result. | |
| 2821 new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex()); | |
| 2822 // Write the old content and the descriptor information | |
| 2823 DescriptorWriter w(new_descriptors); | |
| 2824 DescriptorReader r(this); | |
| 2825 while (!r.eos()) { | |
| 2826 if (r.GetKey() != name) { // Both are symbols; object identity suffices. | |
| 2827 w.WriteFrom(&r); | |
| 2828 } | |
| 2829 r.advance(); | |
| 2830 } | |
| 2831 ASSERT(w.eos()); | |
| 2832 | |
| 2833 return new_descriptors; | |
| 2834 } | |
| 2835 | |
| 2836 | |
| 2837 Object* DescriptorArray::RemoveTransitions() { | 2738 Object* DescriptorArray::RemoveTransitions() { |
| 2838 // Remove all transitions. Return a copy of the array with all transitions | 2739 // Remove all transitions. Return a copy of the array with all transitions |
| 2839 // removed, or a Failure object if the new array could not be allocated. | 2740 // removed, or a Failure object if the new array could not be allocated. |
| 2840 | 2741 |
| 2841 // Compute the size of the map transition entries to be removed. | 2742 // Compute the size of the map transition entries to be removed. |
| 2842 int count_transitions = 0; | 2743 int count_transitions = 0; |
| 2843 for (DescriptorReader r(this); !r.eos(); r.advance()) { | 2744 for (DescriptorReader r(this); !r.eos(); r.advance()) { |
| 2844 if (r.IsTransition()) count_transitions++; | 2745 if (r.IsTransition()) count_transitions++; |
| 2845 } | 2746 } |
| 2846 | 2747 |
| (...skipping 3695 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6542 // No break point. | 6443 // No break point. |
| 6543 if (break_point_objects()->IsUndefined()) return 0; | 6444 if (break_point_objects()->IsUndefined()) return 0; |
| 6544 // Single beak point. | 6445 // Single beak point. |
| 6545 if (!break_point_objects()->IsFixedArray()) return 1; | 6446 if (!break_point_objects()->IsFixedArray()) return 1; |
| 6546 // Multiple break points. | 6447 // Multiple break points. |
| 6547 return FixedArray::cast(break_point_objects())->length(); | 6448 return FixedArray::cast(break_point_objects())->length(); |
| 6548 } | 6449 } |
| 6549 | 6450 |
| 6550 | 6451 |
| 6551 } } // namespace v8::internal | 6452 } } // namespace v8::internal |
| OLD | NEW |