| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 namespace v8 { | 48 namespace v8 { |
| 49 namespace internal { | 49 namespace internal { |
| 50 | 50 |
| 51 // Getters and setters are stored in a fixed array property. These are | 51 // Getters and setters are stored in a fixed array property. These are |
| 52 // constants for their indices. | 52 // constants for their indices. |
| 53 const int kGetterIndex = 0; | 53 const int kGetterIndex = 0; |
| 54 const int kSetterIndex = 1; | 54 const int kSetterIndex = 1; |
| 55 | 55 |
| 56 | 56 |
| 57 MUST_USE_RESULT static Object* CreateJSValue(JSFunction* constructor, | 57 MUST_USE_RESULT static Object* CreateJSValue(JSFunction* constructor, |
| 58 Object* result; |
| 59 { TryAllocation t = Heap::AllocateJSObject(constructor); |
| 60 if (!t->ToObject(&result)) return t; |
| 61 } |
| 58 Object* value) { | 62 Object* value) { |
| 59 Object* result = Heap::AllocateJSObject(constructor); | |
| 60 if (result->IsFailure()) return result; | |
| 61 JSValue::cast(result)->set_value(value); | 63 JSValue::cast(result)->set_value(value); |
| 62 return result; | 64 return result; |
| 63 } | 65 } |
| 64 | 66 |
| 65 | 67 |
| 66 Object* Object::ToObject(Context* global_context) { | 68 Object* Object::ToObject(Context* global_context) { |
| 67 if (IsNumber()) { | 69 if (IsNumber()) { |
| 68 return CreateJSValue(global_context->number_function(), this); | 70 return CreateJSValue(global_context->number_function(), this); |
| 69 } else if (IsBoolean()) { | 71 } else if (IsBoolean()) { |
| 70 return CreateJSValue(global_context->boolean_function(), this); | 72 return CreateJSValue(global_context->boolean_function(), this); |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 } | 367 } |
| 366 | 368 |
| 367 | 369 |
| 368 Object* JSObject::SetNormalizedProperty(String* name, | 370 Object* JSObject::SetNormalizedProperty(String* name, |
| 369 Object* value, | 371 Object* value, |
| 370 PropertyDetails details) { | 372 PropertyDetails details) { |
| 371 ASSERT(!HasFastProperties()); | 373 ASSERT(!HasFastProperties()); |
| 372 int entry = property_dictionary()->FindEntry(name); | 374 int entry = property_dictionary()->FindEntry(name); |
| 373 if (entry == StringDictionary::kNotFound) { | 375 if (entry == StringDictionary::kNotFound) { |
| 374 Object* store_value = value; | 376 Object* store_value = value; |
| 377 { TryAllocation t = Heap::AllocateJSGlobalPropertyCell(value); |
| 378 if (!t->ToObject(&store_value)) return t; |
| 379 } |
| 375 if (IsGlobalObject()) { | 380 if (IsGlobalObject()) { |
| 376 store_value = Heap::AllocateJSGlobalPropertyCell(value); | 381 Object* dict; |
| 377 if (store_value->IsFailure()) return store_value; | 382 { TryAllocation t = property_dictionary()->Add(name, store_value, details); |
| 383 if (!t->ToObject(&dict)) return t; |
| 378 } | 384 } |
| 379 Object* dict = property_dictionary()->Add(name, store_value, details); | 385 } |
| 380 if (dict->IsFailure()) return dict; | |
| 381 set_properties(StringDictionary::cast(dict)); | 386 set_properties(StringDictionary::cast(dict)); |
| 382 return value; | 387 return value; |
| 383 } | 388 } |
| 384 // Preserve enumeration index. | 389 // Preserve enumeration index. |
| 385 details = PropertyDetails(details.attributes(), | 390 details = PropertyDetails(details.attributes(), |
| 386 details.type(), | 391 details.type(), |
| 387 property_dictionary()->DetailsAt(entry).index()); | 392 property_dictionary()->DetailsAt(entry).index()); |
| 388 if (IsGlobalObject()) { | 393 if (IsGlobalObject()) { |
| 389 JSGlobalPropertyCell* cell = | 394 JSGlobalPropertyCell* cell = |
| 390 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry)); | 395 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 404 int entry = dictionary->FindEntry(name); | 409 int entry = dictionary->FindEntry(name); |
| 405 if (entry != StringDictionary::kNotFound) { | 410 if (entry != StringDictionary::kNotFound) { |
| 406 // If we have a global object set the cell to the hole. | 411 // If we have a global object set the cell to the hole. |
| 407 if (IsGlobalObject()) { | 412 if (IsGlobalObject()) { |
| 408 PropertyDetails details = dictionary->DetailsAt(entry); | 413 PropertyDetails details = dictionary->DetailsAt(entry); |
| 409 if (details.IsDontDelete()) { | 414 if (details.IsDontDelete()) { |
| 410 if (mode != FORCE_DELETION) return Heap::false_value(); | 415 if (mode != FORCE_DELETION) return Heap::false_value(); |
| 411 // When forced to delete global properties, we have to make a | 416 // When forced to delete global properties, we have to make a |
| 412 // map change to invalidate any ICs that think they can load | 417 // map change to invalidate any ICs that think they can load |
| 413 // from the DontDelete cell without checking if it contains | 418 // from the DontDelete cell without checking if it contains |
| 419 Object* new_map; |
| 420 { TryAllocation t = map()->CopyDropDescriptors(); |
| 421 if (!t->ToObject(&new_map)) return t; |
| 422 } |
| 414 // the hole value. | 423 // the hole value. |
| 415 Object* new_map = map()->CopyDropDescriptors(); | |
| 416 if (new_map->IsFailure()) return new_map; | |
| 417 set_map(Map::cast(new_map)); | 424 set_map(Map::cast(new_map)); |
| 418 } | 425 } |
| 419 JSGlobalPropertyCell* cell = | 426 JSGlobalPropertyCell* cell = |
| 420 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); | 427 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); |
| 421 cell->set_value(Heap::the_hole_value()); | 428 cell->set_value(Heap::the_hole_value()); |
| 422 dictionary->DetailsAtPut(entry, details.AsDeleted()); | 429 dictionary->DetailsAtPut(entry, details.AsDeleted()); |
| 423 } else { | 430 } else { |
| 424 return dictionary->DeleteProperty(entry, mode); | 431 return dictionary->DeleteProperty(entry, mode); |
| 425 } | 432 } |
| 426 } | 433 } |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 if (cs->second()->length() == 0) { | 642 if (cs->second()->length() == 0) { |
| 636 return cs->first(); | 643 return cs->first(); |
| 637 } | 644 } |
| 638 // There's little point in putting the flat string in new space if the | 645 // There's little point in putting the flat string in new space if the |
| 639 // cons string is in old space. It can never get GCed until there is | 646 // cons string is in old space. It can never get GCed until there is |
| 640 // an old space GC. | 647 // an old space GC. |
| 641 PretenureFlag tenure = Heap::InNewSpace(this) ? pretenure : TENURED; | 648 PretenureFlag tenure = Heap::InNewSpace(this) ? pretenure : TENURED; |
| 642 int len = length(); | 649 int len = length(); |
| 643 Object* object; | 650 Object* object; |
| 644 String* result; | 651 String* result; |
| 652 { TryAllocation t = Heap::AllocateRawAsciiString(len, tenure); |
| 653 if (!t->ToObject(&object)) return t; |
| 654 } |
| 645 if (IsAsciiRepresentation()) { | 655 if (IsAsciiRepresentation()) { |
| 646 object = Heap::AllocateRawAsciiString(len, tenure); | |
| 647 if (object->IsFailure()) return object; | |
| 648 result = String::cast(object); | 656 result = String::cast(object); |
| 649 String* first = cs->first(); | 657 String* first = cs->first(); |
| 650 int first_length = first->length(); | 658 int first_length = first->length(); |
| 651 char* dest = SeqAsciiString::cast(result)->GetChars(); | 659 char* dest = SeqAsciiString::cast(result)->GetChars(); |
| 652 WriteToFlat(first, dest, 0, first_length); | 660 WriteToFlat(first, dest, 0, first_length); |
| 653 String* second = cs->second(); | 661 String* second = cs->second(); |
| 654 WriteToFlat(second, | 662 WriteToFlat(second, |
| 655 dest + first_length, | 663 dest + first_length, |
| 656 0, | 664 0, |
| 657 len - first_length); | 665 len - first_length); |
| 666 { TryAllocation t = Heap::AllocateRawTwoByteString(len, tenure); |
| 667 if (!t->ToObject(&object)) return t; |
| 668 } |
| 658 } else { | 669 } else { |
| 659 object = Heap::AllocateRawTwoByteString(len, tenure); | |
| 660 if (object->IsFailure()) return object; | |
| 661 result = String::cast(object); | 670 result = String::cast(object); |
| 662 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); | 671 uc16* dest = SeqTwoByteString::cast(result)->GetChars(); |
| 663 String* first = cs->first(); | 672 String* first = cs->first(); |
| 664 int first_length = first->length(); | 673 int first_length = first->length(); |
| 665 WriteToFlat(first, dest, 0, first_length); | 674 WriteToFlat(first, dest, 0, first_length); |
| 666 String* second = cs->second(); | 675 String* second = cs->second(); |
| 667 WriteToFlat(second, | 676 WriteToFlat(second, |
| 668 dest + first_length, | 677 dest + first_length, |
| 669 0, | 678 0, |
| 670 len - first_length); | 679 len - first_length); |
| (...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1187 } | 1196 } |
| 1188 | 1197 |
| 1189 | 1198 |
| 1190 Object* JSObject::AddFastPropertyUsingMap(Map* new_map, | 1199 Object* JSObject::AddFastPropertyUsingMap(Map* new_map, |
| 1191 String* name, | 1200 String* name, |
| 1192 Object* value) { | 1201 Object* value) { |
| 1193 int index = new_map->PropertyIndexFor(name); | 1202 int index = new_map->PropertyIndexFor(name); |
| 1194 if (map()->unused_property_fields() == 0) { | 1203 if (map()->unused_property_fields() == 0) { |
| 1195 ASSERT(map()->unused_property_fields() == 0); | 1204 ASSERT(map()->unused_property_fields() == 0); |
| 1196 int new_unused = new_map->unused_property_fields(); | 1205 int new_unused = new_map->unused_property_fields(); |
| 1197 Object* values = | 1206 Object* values; |
| 1198 properties()->CopySize(properties()->length() + new_unused + 1); | 1207 { TryAllocation t = |
| 1199 if (values->IsFailure()) return values; | 1208 properties()->CopySize(properties()->length() + new_unused + 1); |
| 1209 if (!t->ToObject(&values)) return t; |
| 1210 } |
| 1200 set_properties(FixedArray::cast(values)); | 1211 set_properties(FixedArray::cast(values)); |
| 1201 } | 1212 } |
| 1202 set_map(new_map); | 1213 set_map(new_map); |
| 1203 return FastPropertyAtPut(index, value); | 1214 return FastPropertyAtPut(index, value); |
| 1204 } | 1215 } |
| 1205 | 1216 |
| 1206 | 1217 |
| 1207 Object* JSObject::AddFastProperty(String* name, | 1218 Object* JSObject::AddFastProperty(String* name, |
| 1208 Object* value, | 1219 Object* value, |
| 1209 PropertyAttributes attributes) { | 1220 PropertyAttributes attributes) { |
| 1210 // Normalize the object if the name is an actual string (not the | 1221 // Normalize the object if the name is an actual string (not the |
| 1211 // hidden symbols) and is not a real identifier. | 1222 // hidden symbols) and is not a real identifier. |
| 1212 StringInputBuffer buffer(name); | 1223 StringInputBuffer buffer(name); |
| 1224 Object* obj; |
| 1225 { TryAllocation t = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 1226 if (!t->ToObject(&obj)) return t; |
| 1227 } |
| 1213 if (!Scanner::IsIdentifier(&buffer) && name != Heap::hidden_symbol()) { | 1228 if (!Scanner::IsIdentifier(&buffer) && name != Heap::hidden_symbol()) { |
| 1214 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | |
| 1215 if (obj->IsFailure()) return obj; | |
| 1216 return AddSlowProperty(name, value, attributes); | 1229 return AddSlowProperty(name, value, attributes); |
| 1217 } | 1230 } |
| 1218 | 1231 |
| 1219 DescriptorArray* old_descriptors = map()->instance_descriptors(); | 1232 DescriptorArray* old_descriptors = map()->instance_descriptors(); |
| 1220 // Compute the new index for new field. | 1233 // Compute the new index for new field. |
| 1221 int index = map()->NextFreePropertyIndex(); | 1234 int index = map()->NextFreePropertyIndex(); |
| 1222 | 1235 |
| 1223 // Allocate new instance descriptors with (name, index) added | 1236 // Allocate new instance descriptors with (name, index) added |
| 1224 FieldDescriptor new_field(name, index, attributes); | 1237 FieldDescriptor new_field(name, index, attributes); |
| 1225 Object* new_descriptors = | 1238 Object* new_descriptors; |
| 1226 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS); | 1239 { TryAllocation t = |
| 1227 if (new_descriptors->IsFailure()) return new_descriptors; | 1240 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS); |
| 1241 if (!t->ToObject(&new_descriptors)) return t; |
| 1242 } |
| 1228 | 1243 |
| 1229 // Only allow map transition if the object's map is NOT equal to the | 1244 // Only allow map transition if the object's map is NOT equal to the |
| 1230 // global object_function's map and there is not a transition for name. | 1245 // global object_function's map and there is not a transition for name. |
| 1231 bool allow_map_transition = | 1246 bool allow_map_transition = |
| 1232 !old_descriptors->Contains(name) && | 1247 !old_descriptors->Contains(name) && |
| 1233 (Top::context()->global_context()->object_function()->map() != map()); | 1248 (Top::context()->global_context()->object_function()->map() != map()); |
| 1234 | 1249 |
| 1235 ASSERT(index < map()->inobject_properties() || | 1250 ASSERT(index < map()->inobject_properties() || |
| 1236 (index - map()->inobject_properties()) < properties()->length() || | 1251 (index - map()->inobject_properties()) < properties()->length() || |
| 1237 map()->unused_property_fields() == 0); | 1252 map()->unused_property_fields() == 0); |
| 1253 Object* r; |
| 1254 { TryAllocation t = map()->CopyDropDescriptors(); |
| 1255 if (!t->ToObject(&r)) return t; |
| 1256 } |
| 1238 // Allocate a new map for the object. | 1257 // Allocate a new map for the object. |
| 1239 Object* r = map()->CopyDropDescriptors(); | |
| 1240 if (r->IsFailure()) return r; | |
| 1241 Map* new_map = Map::cast(r); | 1258 Map* new_map = Map::cast(r); |
| 1242 if (allow_map_transition) { | 1259 if (allow_map_transition) { |
| 1243 // Allocate new instance descriptors for the old map with map transition. | 1260 // Allocate new instance descriptors for the old map with map transition. |
| 1261 Object* r; |
| 1262 { TryAllocation t = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); |
| 1263 if (!t->ToObject(&r)) return t; |
| 1264 } |
| 1244 MapTransitionDescriptor d(name, Map::cast(new_map), attributes); | 1265 MapTransitionDescriptor d(name, Map::cast(new_map), attributes); |
| 1245 Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS); | |
| 1246 if (r->IsFailure()) return r; | |
| 1247 old_descriptors = DescriptorArray::cast(r); | 1266 old_descriptors = DescriptorArray::cast(r); |
| 1248 } | 1267 } |
| 1249 | 1268 |
| 1250 if (map()->unused_property_fields() == 0) { | 1269 if (map()->unused_property_fields() == 0) { |
| 1270 Object* obj; |
| 1271 { TryAllocation t = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 1272 if (!t->ToObject(&obj)) return t; |
| 1273 } |
| 1251 if (properties()->length() > MaxFastProperties()) { | 1274 if (properties()->length() > MaxFastProperties()) { |
| 1252 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | |
| 1253 if (obj->IsFailure()) return obj; | |
| 1254 return AddSlowProperty(name, value, attributes); | 1275 return AddSlowProperty(name, value, attributes); |
| 1255 } | 1276 } |
| 1256 // Make room for the new value | 1277 // Make room for the new value |
| 1257 Object* values = | 1278 Object* values; |
| 1258 properties()->CopySize(properties()->length() + kFieldsAdded); | 1279 { TryAllocation t = |
| 1259 if (values->IsFailure()) return values; | 1280 properties()->CopySize(properties()->length() + kFieldsAdded); |
| 1281 if (!t->ToObject(&values)) return t; |
| 1282 } |
| 1260 set_properties(FixedArray::cast(values)); | 1283 set_properties(FixedArray::cast(values)); |
| 1261 new_map->set_unused_property_fields(kFieldsAdded - 1); | 1284 new_map->set_unused_property_fields(kFieldsAdded - 1); |
| 1262 } else { | 1285 } else { |
| 1263 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); | 1286 new_map->set_unused_property_fields(map()->unused_property_fields() - 1); |
| 1264 } | 1287 } |
| 1265 // We have now allocated all the necessary objects. | 1288 // We have now allocated all the necessary objects. |
| 1266 // All the changes can be applied at once, so they are atomic. | 1289 // All the changes can be applied at once, so they are atomic. |
| 1267 map()->set_instance_descriptors(old_descriptors); | 1290 map()->set_instance_descriptors(old_descriptors); |
| 1268 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | 1291 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
| 1269 set_map(new_map); | 1292 set_map(new_map); |
| 1270 return FastPropertyAtPut(index, value); | 1293 return FastPropertyAtPut(index, value); |
| 1271 } | 1294 } |
| 1272 | 1295 |
| 1273 | 1296 |
| 1274 Object* JSObject::AddConstantFunctionProperty(String* name, | 1297 Object* JSObject::AddConstantFunctionProperty(String* name, |
| 1275 JSFunction* function, | 1298 JSFunction* function, |
| 1276 PropertyAttributes attributes) { | 1299 PropertyAttributes attributes) { |
| 1277 ASSERT(!Heap::InNewSpace(function)); | 1300 ASSERT(!Heap::InNewSpace(function)); |
| 1278 | 1301 |
| 1279 // Allocate new instance descriptors with (name, function) added | 1302 // Allocate new instance descriptors with (name, function) added |
| 1280 ConstantFunctionDescriptor d(name, function, attributes); | 1303 ConstantFunctionDescriptor d(name, function, attributes); |
| 1281 Object* new_descriptors = | 1304 Object* new_descriptors; |
| 1282 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS); | 1305 { TryAllocation t = |
| 1283 if (new_descriptors->IsFailure()) return new_descriptors; | 1306 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS); |
| 1307 if (!t->ToObject(&new_descriptors)) return t; |
| 1308 } |
| 1284 | 1309 |
| 1310 Object* new_map; |
| 1311 { TryAllocation t = map()->CopyDropDescriptors(); |
| 1312 if (!t->ToObject(&new_map)) return t; |
| 1313 } |
| 1285 // Allocate a new map for the object. | 1314 // Allocate a new map for the object. |
| 1286 Object* new_map = map()->CopyDropDescriptors(); | |
| 1287 if (new_map->IsFailure()) return new_map; | |
| 1288 | 1315 |
| 1289 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors); | 1316 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors); |
| 1290 Map::cast(new_map)->set_instance_descriptors(descriptors); | 1317 Map::cast(new_map)->set_instance_descriptors(descriptors); |
| 1291 Map* old_map = map(); | 1318 Map* old_map = map(); |
| 1292 set_map(Map::cast(new_map)); | 1319 set_map(Map::cast(new_map)); |
| 1293 | 1320 |
| 1294 // If the old map is the global object map (from new Object()), | 1321 // If the old map is the global object map (from new Object()), |
| 1295 // then transitions are not added to it, so we are done. | 1322 // then transitions are not added to it, so we are done. |
| 1296 if (old_map == Top::context()->global_context()->object_function()->map()) { | 1323 if (old_map == Top::context()->global_context()->object_function()->map()) { |
| 1297 return function; | 1324 return function; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1334 if (entry != StringDictionary::kNotFound) { | 1361 if (entry != StringDictionary::kNotFound) { |
| 1335 store_value = dict->ValueAt(entry); | 1362 store_value = dict->ValueAt(entry); |
| 1336 JSGlobalPropertyCell::cast(store_value)->set_value(value); | 1363 JSGlobalPropertyCell::cast(store_value)->set_value(value); |
| 1337 // Assign an enumeration index to the property and update | 1364 // Assign an enumeration index to the property and update |
| 1338 // SetNextEnumerationIndex. | 1365 // SetNextEnumerationIndex. |
| 1339 int index = dict->NextEnumerationIndex(); | 1366 int index = dict->NextEnumerationIndex(); |
| 1340 PropertyDetails details = PropertyDetails(attributes, NORMAL, index); | 1367 PropertyDetails details = PropertyDetails(attributes, NORMAL, index); |
| 1341 dict->SetNextEnumerationIndex(index + 1); | 1368 dict->SetNextEnumerationIndex(index + 1); |
| 1342 dict->SetEntry(entry, name, store_value, details); | 1369 dict->SetEntry(entry, name, store_value, details); |
| 1343 return value; | 1370 return value; |
| 1371 { TryAllocation t = Heap::AllocateJSGlobalPropertyCell(value); |
| 1372 if (!t->ToObject(&store_value)) return t; |
| 1344 } | 1373 } |
| 1345 store_value = Heap::AllocateJSGlobalPropertyCell(value); | 1374 } |
| 1346 if (store_value->IsFailure()) return store_value; | |
| 1347 JSGlobalPropertyCell::cast(store_value)->set_value(value); | 1375 JSGlobalPropertyCell::cast(store_value)->set_value(value); |
| 1348 } | 1376 } |
| 1377 Object* result; |
| 1378 { TryAllocation t = dict->Add(name, store_value, details); |
| 1379 if (!t->ToObject(&result)) return t; |
| 1380 } |
| 1349 PropertyDetails details = PropertyDetails(attributes, NORMAL); | 1381 PropertyDetails details = PropertyDetails(attributes, NORMAL); |
| 1350 Object* result = dict->Add(name, store_value, details); | |
| 1351 if (result->IsFailure()) return result; | |
| 1352 if (dict != result) set_properties(StringDictionary::cast(result)); | 1382 if (dict != result) set_properties(StringDictionary::cast(result)); |
| 1353 return value; | 1383 return value; |
| 1354 } | 1384 } |
| 1355 | 1385 |
| 1356 | 1386 |
| 1357 Object* JSObject::AddProperty(String* name, | 1387 Object* JSObject::AddProperty(String* name, |
| 1358 Object* value, | 1388 Object* value, |
| 1359 PropertyAttributes attributes) { | 1389 PropertyAttributes attributes) { |
| 1360 ASSERT(!IsJSGlobalProxy()); | 1390 ASSERT(!IsJSGlobalProxy()); |
| 1361 if (!map()->is_extensible()) { | 1391 if (!map()->is_extensible()) { |
| 1362 Handle<Object> args[1] = {Handle<String>(name)}; | 1392 Handle<Object> args[1] = {Handle<String>(name)}; |
| 1363 return Top::Throw(*Factory::NewTypeError("object_not_extensible", | 1393 return Top::Throw(*Factory::NewTypeError("object_not_extensible", |
| 1364 HandleVector(args, 1))); | 1394 HandleVector(args, 1))); |
| 1365 } | 1395 } |
| 1366 if (HasFastProperties()) { | 1396 if (HasFastProperties()) { |
| 1367 // Ensure the descriptor array does not get too big. | 1397 // Ensure the descriptor array does not get too big. |
| 1368 if (map()->instance_descriptors()->number_of_descriptors() < | 1398 if (map()->instance_descriptors()->number_of_descriptors() < |
| 1369 DescriptorArray::kMaxNumberOfDescriptors) { | 1399 DescriptorArray::kMaxNumberOfDescriptors) { |
| 1370 if (value->IsJSFunction() && !Heap::InNewSpace(value)) { | 1400 if (value->IsJSFunction() && !Heap::InNewSpace(value)) { |
| 1371 return AddConstantFunctionProperty(name, | 1401 return AddConstantFunctionProperty(name, |
| 1372 JSFunction::cast(value), | 1402 JSFunction::cast(value), |
| 1373 attributes); | 1403 attributes); |
| 1374 } else { | 1404 } else { |
| 1375 return AddFastProperty(name, value, attributes); | 1405 return AddFastProperty(name, value, attributes); |
| 1376 } | 1406 } |
| 1377 } else { | 1407 } else { |
| 1378 // Normalize the object to prevent very large instance descriptors. | 1408 // Normalize the object to prevent very large instance descriptors. |
| 1409 Object* obj; |
| 1410 { TryAllocation t = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 1411 if (!t->ToObject(&obj)) return t; |
| 1412 } |
| 1379 // This eliminates unwanted N^2 allocation and lookup behavior. | 1413 // This eliminates unwanted N^2 allocation and lookup behavior. |
| 1380 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | |
| 1381 if (obj->IsFailure()) return obj; | |
| 1382 } | 1414 } |
| 1383 } | 1415 } |
| 1384 return AddSlowProperty(name, value, attributes); | 1416 return AddSlowProperty(name, value, attributes); |
| 1385 } | 1417 } |
| 1386 | 1418 |
| 1387 | 1419 |
| 1388 Object* JSObject::SetPropertyPostInterceptor(String* name, | 1420 Object* JSObject::SetPropertyPostInterceptor(String* name, |
| 1389 Object* value, | 1421 Object* value, |
| 1390 PropertyAttributes attributes) { | 1422 PropertyAttributes attributes) { |
| 1391 // Check local property, ignore interceptor. | 1423 // Check local property, ignore interceptor. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1415 | 1447 |
| 1416 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index); | 1448 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index); |
| 1417 return SetNormalizedProperty(name, value, new_details); | 1449 return SetNormalizedProperty(name, value, new_details); |
| 1418 } | 1450 } |
| 1419 | 1451 |
| 1420 | 1452 |
| 1421 Object* JSObject::ConvertDescriptorToFieldAndMapTransition( | 1453 Object* JSObject::ConvertDescriptorToFieldAndMapTransition( |
| 1422 String* name, | 1454 String* name, |
| 1423 Object* new_value, | 1455 Object* new_value, |
| 1424 PropertyAttributes attributes) { | 1456 PropertyAttributes attributes) { |
| 1457 Object* result; |
| 1458 { TryAllocation t = ConvertDescriptorToField(name, new_value, attributes); |
| 1459 if (!t->ToObject(&result)) return t; |
| 1460 } |
| 1425 Map* old_map = map(); | 1461 Map* old_map = map(); |
| 1426 Object* result = ConvertDescriptorToField(name, new_value, attributes); | |
| 1427 if (result->IsFailure()) return result; | |
| 1428 // If we get to this point we have succeeded - do not return failure | 1462 // If we get to this point we have succeeded - do not return failure |
| 1429 // after this point. Later stuff is optional. | 1463 // after this point. Later stuff is optional. |
| 1430 if (!HasFastProperties()) { | 1464 if (!HasFastProperties()) { |
| 1431 return result; | 1465 return result; |
| 1432 } | 1466 } |
| 1433 // Do not add transitions to the map of "new Object()". | 1467 // Do not add transitions to the map of "new Object()". |
| 1434 if (map() == Top::context()->global_context()->object_function()->map()) { | 1468 if (map() == Top::context()->global_context()->object_function()->map()) { |
| 1435 return result; | 1469 return result; |
| 1436 } | 1470 } |
| 1437 | 1471 |
| 1438 MapTransitionDescriptor transition(name, | 1472 MapTransitionDescriptor transition(name, |
| 1439 map(), | 1473 map(), |
| 1440 attributes); | 1474 attributes); |
| 1441 Object* new_descriptors = | 1475 Object* new_descriptors = |
| 1442 old_map->instance_descriptors()-> | 1476 old_map->instance_descriptors()-> |
| 1443 CopyInsert(&transition, KEEP_TRANSITIONS); | 1477 CopyInsert(&transition, KEEP_TRANSITIONS); |
| 1444 if (new_descriptors->IsFailure()) return result; // Yes, return _result_. | 1478 if (new_descriptors->IsFailure()) return result; // Yes, return _result_. |
| 1445 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); | 1479 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
| 1446 return result; | 1480 return result; |
| 1447 } | 1481 } |
| 1448 | 1482 |
| 1449 | 1483 |
| 1450 Object* JSObject::ConvertDescriptorToField(String* name, | 1484 Object* JSObject::ConvertDescriptorToField(String* name, |
| 1451 Object* new_value, | 1485 Object* new_value, |
| 1452 PropertyAttributes attributes) { | 1486 PropertyAttributes attributes) { |
| 1453 if (map()->unused_property_fields() == 0 && | 1487 if (map()->unused_property_fields() == 0 && |
| 1488 Object* obj; |
| 1489 { TryAllocation t = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 1490 if (!t->ToObject(&obj)) return t; |
| 1491 } |
| 1454 properties()->length() > MaxFastProperties()) { | 1492 properties()->length() > MaxFastProperties()) { |
| 1455 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | |
| 1456 if (obj->IsFailure()) return obj; | |
| 1457 return ReplaceSlowProperty(name, new_value, attributes); | 1493 return ReplaceSlowProperty(name, new_value, attributes); |
| 1458 } | 1494 } |
| 1459 | 1495 |
| 1460 int index = map()->NextFreePropertyIndex(); | 1496 int index = map()->NextFreePropertyIndex(); |
| 1461 FieldDescriptor new_field(name, index, attributes); | 1497 FieldDescriptor new_field(name, index, attributes); |
| 1462 // Make a new DescriptorArray replacing an entry with FieldDescriptor. | 1498 // Make a new DescriptorArray replacing an entry with FieldDescriptor. |
| 1463 Object* descriptors_unchecked = map()->instance_descriptors()-> | 1499 Object* descriptors_unchecked; |
| 1464 CopyInsert(&new_field, REMOVE_TRANSITIONS); | 1500 { TryAllocation t = map()->instance_descriptors()-> |
| 1465 if (descriptors_unchecked->IsFailure()) return descriptors_unchecked; | 1501 CopyInsert(&new_field, REMOVE_TRANSITIONS); |
| 1502 if (!t->ToObject(&descriptors_unchecked)) return t; |
| 1503 } |
| 1466 DescriptorArray* new_descriptors = | 1504 DescriptorArray* new_descriptors = |
| 1467 DescriptorArray::cast(descriptors_unchecked); | 1505 DescriptorArray::cast(descriptors_unchecked); |
| 1468 | 1506 |
| 1507 Object* new_map_unchecked; |
| 1508 { TryAllocation t = map()->CopyDropDescriptors(); |
| 1509 if (!t->ToObject(&new_map_unchecked)) return t; |
| 1510 } |
| 1469 // Make a new map for the object. | 1511 // Make a new map for the object. |
| 1470 Object* new_map_unchecked = map()->CopyDropDescriptors(); | |
| 1471 if (new_map_unchecked->IsFailure()) return new_map_unchecked; | |
| 1472 Map* new_map = Map::cast(new_map_unchecked); | 1512 Map* new_map = Map::cast(new_map_unchecked); |
| 1473 new_map->set_instance_descriptors(new_descriptors); | 1513 new_map->set_instance_descriptors(new_descriptors); |
| 1474 | 1514 |
| 1475 // Make new properties array if necessary. | 1515 // Make new properties array if necessary. |
| 1476 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer. | 1516 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer. |
| 1477 int new_unused_property_fields = map()->unused_property_fields() - 1; | 1517 int new_unused_property_fields = map()->unused_property_fields() - 1; |
| 1478 if (map()->unused_property_fields() == 0) { | 1518 if (map()->unused_property_fields() == 0) { |
| 1479 new_unused_property_fields = kFieldsAdded - 1; | 1519 new_unused_property_fields = kFieldsAdded - 1; |
| 1480 Object* new_properties_unchecked = | 1520 Object* new_properties_unchecked; |
| 1481 properties()->CopySize(properties()->length() + kFieldsAdded); | 1521 { TryAllocation t = |
| 1482 if (new_properties_unchecked->IsFailure()) return new_properties_unchecked; | 1522 properties()->CopySize(properties()->length() + kFieldsAdded); |
| 1523 if (!t->ToObject(&new_properties_unchecked)) return t; |
| 1524 } |
| 1483 new_properties = FixedArray::cast(new_properties_unchecked); | 1525 new_properties = FixedArray::cast(new_properties_unchecked); |
| 1484 } | 1526 } |
| 1485 | 1527 |
| 1486 // Update pointers to commit changes. | 1528 // Update pointers to commit changes. |
| 1487 // Object points to the new map. | 1529 // Object points to the new map. |
| 1488 new_map->set_unused_property_fields(new_unused_property_fields); | 1530 new_map->set_unused_property_fields(new_unused_property_fields); |
| 1489 set_map(new_map); | 1531 set_map(new_map); |
| 1490 if (new_properties) { | 1532 if (new_properties) { |
| 1491 set_properties(FixedArray::cast(new_properties)); | 1533 set_properties(FixedArray::cast(new_properties)); |
| 1492 } | 1534 } |
| (...skipping 617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2110 Object* fresh = fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); | 2152 Object* fresh = fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); |
| 2111 if (!fresh->IsFailure()) { | 2153 if (!fresh->IsFailure()) { |
| 2112 ASSERT(memcmp(Map::cast(fresh)->address(), | 2154 ASSERT(memcmp(Map::cast(fresh)->address(), |
| 2113 Map::cast(result)->address(), | 2155 Map::cast(result)->address(), |
| 2114 Map::kSize) == 0); | 2156 Map::kSize) == 0); |
| 2115 } | 2157 } |
| 2116 } | 2158 } |
| 2117 #endif | 2159 #endif |
| 2118 return result; | 2160 return result; |
| 2119 } | 2161 } |
| 2162 { TryAllocation t = fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); |
| 2163 if (!t->ToObject(&result)) return t; |
| 2164 } |
| 2120 | 2165 |
| 2121 result = fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); | |
| 2122 if (result->IsFailure()) return result; | |
| 2123 set(index, result); | 2166 set(index, result); |
| 2124 Counters::normalized_maps.Increment(); | 2167 Counters::normalized_maps.Increment(); |
| 2125 | 2168 |
| 2126 return result; | 2169 return result; |
| 2127 } | 2170 } |
| 2128 | 2171 |
| 2129 | 2172 |
| 2130 void NormalizedMapCache::Clear() { | 2173 void NormalizedMapCache::Clear() { |
| 2131 int entries = length(); | 2174 int entries = length(); |
| 2132 for (int i = 0; i != entries; i++) { | 2175 for (int i = 0; i != entries; i++) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2169 slow->bit_field() == fast->bit_field() && | 2212 slow->bit_field() == fast->bit_field() && |
| 2170 (slow->bit_field2() & ~(1<<Map::kIsShared)) == fast->bit_field2(); | 2213 (slow->bit_field2() & ~(1<<Map::kIsShared)) == fast->bit_field2(); |
| 2171 } | 2214 } |
| 2172 | 2215 |
| 2173 | 2216 |
| 2174 Object* JSObject::UpdateMapCodeCache(String* name, Code* code) { | 2217 Object* JSObject::UpdateMapCodeCache(String* name, Code* code) { |
| 2175 if (map()->is_shared()) { | 2218 if (map()->is_shared()) { |
| 2176 // Fast case maps are never marked as shared. | 2219 // Fast case maps are never marked as shared. |
| 2177 ASSERT(!HasFastProperties()); | 2220 ASSERT(!HasFastProperties()); |
| 2178 // Replace the map with an identical copy that can be safely modified. | 2221 // Replace the map with an identical copy that can be safely modified. |
| 2179 Object* obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, | 2222 Object* obj; |
| 2180 UNIQUE_NORMALIZED_MAP); | 2223 { TryAllocation t = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, |
| 2181 if (obj->IsFailure()) return obj; | 2224 UNIQUE_NORMALIZED_MAP); |
| 2225 if (!t->ToObject(&obj)) return t; |
| 2226 } |
| 2182 Counters::normalized_maps.Increment(); | 2227 Counters::normalized_maps.Increment(); |
| 2183 | 2228 |
| 2184 set_map(Map::cast(obj)); | 2229 set_map(Map::cast(obj)); |
| 2185 } | 2230 } |
| 2186 return map()->UpdateCodeCache(name, code); | 2231 return map()->UpdateCodeCache(name, code); |
| 2187 } | 2232 } |
| 2188 | 2233 |
| 2189 | 2234 |
| 2190 Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode, | 2235 Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode, |
| 2191 int expected_additional_properties) { | 2236 int expected_additional_properties) { |
| 2192 if (!HasFastProperties()) return this; | 2237 if (!HasFastProperties()) return this; |
| 2193 | 2238 |
| 2194 // The global object is always normalized. | 2239 // The global object is always normalized. |
| 2195 ASSERT(!IsGlobalObject()); | 2240 ASSERT(!IsGlobalObject()); |
| 2196 | 2241 |
| 2197 // Allocate new content. | 2242 // Allocate new content. |
| 2198 int property_count = map()->NumberOfDescribedProperties(); | 2243 int property_count = map()->NumberOfDescribedProperties(); |
| 2199 if (expected_additional_properties > 0) { | 2244 if (expected_additional_properties > 0) { |
| 2200 property_count += expected_additional_properties; | 2245 property_count += expected_additional_properties; |
| 2201 } else { | 2246 } else { |
| 2202 property_count += 2; // Make space for two more properties. | 2247 property_count += 2; // Make space for two more properties. |
| 2203 } | 2248 } |
| 2204 Object* obj = | 2249 Object* obj; |
| 2205 StringDictionary::Allocate(property_count); | 2250 { TryAllocation t = |
| 2206 if (obj->IsFailure()) return obj; | 2251 StringDictionary::Allocate(property_count); |
| 2252 if (!t->ToObject(&obj)) return t; |
| 2253 } |
| 2207 StringDictionary* dictionary = StringDictionary::cast(obj); | 2254 StringDictionary* dictionary = StringDictionary::cast(obj); |
| 2208 | 2255 |
| 2209 DescriptorArray* descs = map()->instance_descriptors(); | 2256 DescriptorArray* descs = map()->instance_descriptors(); |
| 2210 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 2257 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 2211 PropertyDetails details = descs->GetDetails(i); | 2258 PropertyDetails details = descs->GetDetails(i); |
| 2212 switch (details.type()) { | 2259 switch (details.type()) { |
| 2213 case CONSTANT_FUNCTION: { | 2260 case CONSTANT_FUNCTION: { |
| 2214 PropertyDetails d = | 2261 PropertyDetails d = |
| 2215 PropertyDetails(details.attributes(), NORMAL, details.index()); | 2262 PropertyDetails(details.attributes(), NORMAL, details.index()); |
| 2263 Object* result; |
| 2264 { TryAllocation t = dictionary->Add(descs->GetKey(i), value, d); |
| 2265 if (!t->ToObject(&result)) return t; |
| 2266 } |
| 2216 Object* value = descs->GetConstantFunction(i); | 2267 Object* value = descs->GetConstantFunction(i); |
| 2217 Object* result = dictionary->Add(descs->GetKey(i), value, d); | |
| 2218 if (result->IsFailure()) return result; | |
| 2219 dictionary = StringDictionary::cast(result); | 2268 dictionary = StringDictionary::cast(result); |
| 2220 break; | 2269 break; |
| 2221 } | 2270 } |
| 2222 case FIELD: { | 2271 case FIELD: { |
| 2223 PropertyDetails d = | 2272 PropertyDetails d = |
| 2224 PropertyDetails(details.attributes(), NORMAL, details.index()); | 2273 PropertyDetails(details.attributes(), NORMAL, details.index()); |
| 2274 Object* result; |
| 2275 { TryAllocation t = dictionary->Add(descs->GetKey(i), value, d); |
| 2276 if (!t->ToObject(&result)) return t; |
| 2277 } |
| 2225 Object* value = FastPropertyAt(descs->GetFieldIndex(i)); | 2278 Object* value = FastPropertyAt(descs->GetFieldIndex(i)); |
| 2226 Object* result = dictionary->Add(descs->GetKey(i), value, d); | |
| 2227 if (result->IsFailure()) return result; | |
| 2228 dictionary = StringDictionary::cast(result); | 2279 dictionary = StringDictionary::cast(result); |
| 2229 break; | 2280 break; |
| 2230 } | 2281 } |
| 2231 case CALLBACKS: { | 2282 case CALLBACKS: { |
| 2232 PropertyDetails d = | 2283 PropertyDetails d = |
| 2233 PropertyDetails(details.attributes(), CALLBACKS, details.index()); | 2284 PropertyDetails(details.attributes(), CALLBACKS, details.index()); |
| 2285 Object* result; |
| 2286 { TryAllocation t = dictionary->Add(descs->GetKey(i), value, d); |
| 2287 if (!t->ToObject(&result)) return t; |
| 2288 } |
| 2234 Object* value = descs->GetCallbacksObject(i); | 2289 Object* value = descs->GetCallbacksObject(i); |
| 2235 Object* result = dictionary->Add(descs->GetKey(i), value, d); | |
| 2236 if (result->IsFailure()) return result; | |
| 2237 dictionary = StringDictionary::cast(result); | 2290 dictionary = StringDictionary::cast(result); |
| 2238 break; | 2291 break; |
| 2239 } | 2292 } |
| 2240 case MAP_TRANSITION: | 2293 case MAP_TRANSITION: |
| 2241 case CONSTANT_TRANSITION: | 2294 case CONSTANT_TRANSITION: |
| 2242 case NULL_DESCRIPTOR: | 2295 case NULL_DESCRIPTOR: |
| 2243 case INTERCEPTOR: | 2296 case INTERCEPTOR: |
| 2244 break; | 2297 break; |
| 2245 default: | 2298 default: |
| 2246 UNREACHABLE(); | 2299 UNREACHABLE(); |
| 2247 } | 2300 } |
| 2248 } | 2301 } |
| 2249 | 2302 |
| 2250 // Copy the next enumeration index from instance descriptor. | 2303 // Copy the next enumeration index from instance descriptor. |
| 2251 int index = map()->instance_descriptors()->NextEnumerationIndex(); | 2304 int index = map()->instance_descriptors()->NextEnumerationIndex(); |
| 2252 dictionary->SetNextEnumerationIndex(index); | 2305 dictionary->SetNextEnumerationIndex(index); |
| 2253 | 2306 |
| 2254 obj = Top::context()->global_context()-> | 2307 { TryAllocation t = Top::context()->global_context()-> |
| 2255 normalized_map_cache()->Get(this, mode); | 2308 normalized_map_cache()->Get(this, mode); |
| 2256 if (obj->IsFailure()) return obj; | 2309 if (!t->ToObject(&obj)) return t; |
| 2310 } |
| 2257 Map* new_map = Map::cast(obj); | 2311 Map* new_map = Map::cast(obj); |
| 2258 | 2312 |
| 2259 // We have now successfully allocated all the necessary objects. | 2313 // We have now successfully allocated all the necessary objects. |
| 2260 // Changes can now be made with the guarantee that all of them take effect. | 2314 // Changes can now be made with the guarantee that all of them take effect. |
| 2261 | 2315 |
| 2262 // Resize the object in the heap if necessary. | 2316 // Resize the object in the heap if necessary. |
| 2263 int new_instance_size = new_map->instance_size(); | 2317 int new_instance_size = new_map->instance_size(); |
| 2264 int instance_size_delta = map()->instance_size() - new_instance_size; | 2318 int instance_size_delta = map()->instance_size() - new_instance_size; |
| 2265 ASSERT(instance_size_delta >= 0); | 2319 ASSERT(instance_size_delta >= 0); |
| 2266 Heap::CreateFillerObjectAt(this->address() + new_instance_size, | 2320 Heap::CreateFillerObjectAt(this->address() + new_instance_size, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2287 ASSERT(!IsGlobalObject()); | 2341 ASSERT(!IsGlobalObject()); |
| 2288 return property_dictionary()-> | 2342 return property_dictionary()-> |
| 2289 TransformPropertiesToFastFor(this, unused_property_fields); | 2343 TransformPropertiesToFastFor(this, unused_property_fields); |
| 2290 } | 2344 } |
| 2291 | 2345 |
| 2292 | 2346 |
| 2293 Object* JSObject::NormalizeElements() { | 2347 Object* JSObject::NormalizeElements() { |
| 2294 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); | 2348 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); |
| 2295 if (HasDictionaryElements()) return this; | 2349 if (HasDictionaryElements()) return this; |
| 2296 ASSERT(map()->has_fast_elements()); | 2350 ASSERT(map()->has_fast_elements()); |
| 2351 Object* obj; |
| 2352 { TryAllocation t = map()->GetSlowElementsMap(); |
| 2353 if (!t->ToObject(&obj)) return t; |
| 2354 } |
| 2297 | 2355 |
| 2298 Object* obj = map()->GetSlowElementsMap(); | |
| 2299 if (obj->IsFailure()) return obj; | |
| 2300 Map* new_map = Map::cast(obj); | 2356 Map* new_map = Map::cast(obj); |
| 2301 | 2357 |
| 2302 // Get number of entries. | 2358 // Get number of entries. |
| 2303 FixedArray* array = FixedArray::cast(elements()); | 2359 FixedArray* array = FixedArray::cast(elements()); |
| 2304 | 2360 |
| 2305 // Compute the effective length. | 2361 // Compute the effective length. |
| 2306 int length = IsJSArray() ? | 2362 int length = IsJSArray() ? |
| 2307 Smi::cast(JSArray::cast(this)->length())->value() : | 2363 Smi::cast(JSArray::cast(this)->length())->value() : |
| 2364 { TryAllocation t = NumberDictionary::Allocate(length); |
| 2365 if (!t->ToObject(&obj)) return t; |
| 2366 } |
| 2308 array->length(); | 2367 array->length(); |
| 2309 obj = NumberDictionary::Allocate(length); | |
| 2310 if (obj->IsFailure()) return obj; | |
| 2311 NumberDictionary* dictionary = NumberDictionary::cast(obj); | 2368 NumberDictionary* dictionary = NumberDictionary::cast(obj); |
| 2312 // Copy entries. | 2369 // Copy entries. |
| 2313 for (int i = 0; i < length; i++) { | 2370 for (int i = 0; i < length; i++) { |
| 2314 Object* value = array->get(i); | 2371 Object* value = array->get(i); |
| 2315 if (!value->IsTheHole()) { | 2372 if (!value->IsTheHole()) { |
| 2373 Object* result; |
| 2374 { TryAllocation t = dictionary->AddNumberEntry(i, array->get(i), details); |
| 2375 if (!t->ToObject(&result)) return t; |
| 2376 } |
| 2316 PropertyDetails details = PropertyDetails(NONE, NORMAL); | 2377 PropertyDetails details = PropertyDetails(NONE, NORMAL); |
| 2317 Object* result = dictionary->AddNumberEntry(i, array->get(i), details); | |
| 2318 if (result->IsFailure()) return result; | |
| 2319 dictionary = NumberDictionary::cast(result); | 2378 dictionary = NumberDictionary::cast(result); |
| 2320 } | 2379 } |
| 2321 } | 2380 } |
| 2322 // Switch to using the dictionary as the backing storage for | 2381 // Switch to using the dictionary as the backing storage for |
| 2323 // elements. Set the new map first to satify the elements type | 2382 // elements. Set the new map first to satify the elements type |
| 2324 // assert in set_elements(). | 2383 // assert in set_elements(). |
| 2325 set_map(new_map); | 2384 set_map(new_map); |
| 2326 set_elements(dictionary); | 2385 set_elements(dictionary); |
| 2327 | 2386 |
| 2328 Counters::elements_to_dictionary.Increment(); | 2387 Counters::elements_to_dictionary.Increment(); |
| 2329 | 2388 |
| 2330 #ifdef DEBUG | 2389 #ifdef DEBUG |
| 2331 if (FLAG_trace_normalization) { | 2390 if (FLAG_trace_normalization) { |
| 2332 PrintF("Object elements have been normalized:\n"); | 2391 PrintF("Object elements have been normalized:\n"); |
| 2333 Print(); | 2392 Print(); |
| 2334 } | 2393 } |
| 2335 #endif | 2394 #endif |
| 2336 | 2395 |
| 2337 return this; | 2396 return this; |
| 2338 } | 2397 } |
| 2339 | 2398 |
| 2340 | 2399 |
| 2341 Object* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) { | 2400 Object* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) { |
| 2342 // Check local property, ignore interceptor. | 2401 // Check local property, ignore interceptor. |
| 2343 LookupResult result; | 2402 LookupResult result; |
| 2344 LocalLookupRealNamedProperty(name, &result); | 2403 LocalLookupRealNamedProperty(name, &result); |
| 2345 if (!result.IsProperty()) return Heap::true_value(); | 2404 if (!result.IsProperty()) return Heap::true_value(); |
| 2346 | 2405 |
| 2406 Object* obj; |
| 2407 { TryAllocation t = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 2408 if (!t->ToObject(&obj)) return t; |
| 2409 } |
| 2347 // Normalize object if needed. | 2410 // Normalize object if needed. |
| 2348 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | |
| 2349 if (obj->IsFailure()) return obj; | |
| 2350 | 2411 |
| 2351 return DeleteNormalizedProperty(name, mode); | 2412 return DeleteNormalizedProperty(name, mode); |
| 2352 } | 2413 } |
| 2353 | 2414 |
| 2354 | 2415 |
| 2355 Object* JSObject::DeletePropertyWithInterceptor(String* name) { | 2416 Object* JSObject::DeletePropertyWithInterceptor(String* name) { |
| 2356 HandleScope scope; | 2417 HandleScope scope; |
| 2357 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); | 2418 Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); |
| 2358 Handle<String> name_handle(name); | 2419 Handle<String> name_handle(name); |
| 2359 Handle<JSObject> this_handle(this); | 2420 Handle<JSObject> this_handle(this); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2379 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); | 2440 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); |
| 2380 RETURN_IF_SCHEDULED_EXCEPTION(); | 2441 RETURN_IF_SCHEDULED_EXCEPTION(); |
| 2381 return raw_result; | 2442 return raw_result; |
| 2382 } | 2443 } |
| 2383 | 2444 |
| 2384 | 2445 |
| 2385 Object* JSObject::DeleteElementPostInterceptor(uint32_t index, | 2446 Object* JSObject::DeleteElementPostInterceptor(uint32_t index, |
| 2386 DeleteMode mode) { | 2447 DeleteMode mode) { |
| 2387 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); | 2448 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); |
| 2388 switch (GetElementsKind()) { | 2449 switch (GetElementsKind()) { |
| 2450 Object* obj; |
| 2451 { TryAllocation t = EnsureWritableFastElements(); |
| 2452 if (!t->ToObject(&obj)) return t; |
| 2453 } |
| 2389 case FAST_ELEMENTS: { | 2454 case FAST_ELEMENTS: { |
| 2390 Object* obj = EnsureWritableFastElements(); | |
| 2391 if (obj->IsFailure()) return obj; | |
| 2392 uint32_t length = IsJSArray() ? | 2455 uint32_t length = IsJSArray() ? |
| 2393 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : | 2456 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : |
| 2394 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 2457 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
| 2395 if (index < length) { | 2458 if (index < length) { |
| 2396 FixedArray::cast(elements())->set_the_hole(index); | 2459 FixedArray::cast(elements())->set_the_hole(index); |
| 2397 } | 2460 } |
| 2398 break; | 2461 break; |
| 2399 } | 2462 } |
| 2400 case DICTIONARY_ELEMENTS: { | 2463 case DICTIONARY_ELEMENTS: { |
| 2401 NumberDictionary* dictionary = element_dictionary(); | 2464 NumberDictionary* dictionary = element_dictionary(); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2461 | 2524 |
| 2462 if (HasIndexedInterceptor()) { | 2525 if (HasIndexedInterceptor()) { |
| 2463 // Skip interceptor if forcing deletion. | 2526 // Skip interceptor if forcing deletion. |
| 2464 if (mode == FORCE_DELETION) { | 2527 if (mode == FORCE_DELETION) { |
| 2465 return DeleteElementPostInterceptor(index, mode); | 2528 return DeleteElementPostInterceptor(index, mode); |
| 2466 } | 2529 } |
| 2467 return DeleteElementWithInterceptor(index); | 2530 return DeleteElementWithInterceptor(index); |
| 2468 } | 2531 } |
| 2469 | 2532 |
| 2470 switch (GetElementsKind()) { | 2533 switch (GetElementsKind()) { |
| 2534 Object* obj; |
| 2535 { TryAllocation t = EnsureWritableFastElements(); |
| 2536 if (!t->ToObject(&obj)) return t; |
| 2537 } |
| 2471 case FAST_ELEMENTS: { | 2538 case FAST_ELEMENTS: { |
| 2472 Object* obj = EnsureWritableFastElements(); | |
| 2473 if (obj->IsFailure()) return obj; | |
| 2474 uint32_t length = IsJSArray() ? | 2539 uint32_t length = IsJSArray() ? |
| 2475 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : | 2540 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : |
| 2476 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 2541 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
| 2477 if (index < length) { | 2542 if (index < length) { |
| 2478 FixedArray::cast(elements())->set_the_hole(index); | 2543 FixedArray::cast(elements())->set_the_hole(index); |
| 2479 } | 2544 } |
| 2480 break; | 2545 break; |
| 2481 } | 2546 } |
| 2482 case PIXEL_ELEMENTS: | 2547 case PIXEL_ELEMENTS: |
| 2483 case EXTERNAL_BYTE_ELEMENTS: | 2548 case EXTERNAL_BYTE_ELEMENTS: |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2536 return Heap::false_value(); | 2601 return Heap::false_value(); |
| 2537 } | 2602 } |
| 2538 // Check for interceptor. | 2603 // Check for interceptor. |
| 2539 if (result.type() == INTERCEPTOR) { | 2604 if (result.type() == INTERCEPTOR) { |
| 2540 // Skip interceptor if forcing a deletion. | 2605 // Skip interceptor if forcing a deletion. |
| 2541 if (mode == FORCE_DELETION) { | 2606 if (mode == FORCE_DELETION) { |
| 2542 return DeletePropertyPostInterceptor(name, mode); | 2607 return DeletePropertyPostInterceptor(name, mode); |
| 2543 } | 2608 } |
| 2544 return DeletePropertyWithInterceptor(name); | 2609 return DeletePropertyWithInterceptor(name); |
| 2545 } | 2610 } |
| 2611 Object* obj; |
| 2612 { TryAllocation t = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 2613 if (!t->ToObject(&obj)) return t; |
| 2614 } |
| 2546 // Normalize object if needed. | 2615 // Normalize object if needed. |
| 2547 Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | |
| 2548 if (obj->IsFailure()) return obj; | |
| 2549 // Make sure the properties are normalized before removing the entry. | 2616 // Make sure the properties are normalized before removing the entry. |
| 2550 return DeleteNormalizedProperty(name, mode); | 2617 return DeleteNormalizedProperty(name, mode); |
| 2551 } | 2618 } |
| 2552 } | 2619 } |
| 2553 | 2620 |
| 2554 | 2621 |
| 2555 // Check whether this object references another object. | 2622 // Check whether this object references another object. |
| 2556 bool JSObject::ReferencesObject(Object* obj) { | 2623 bool JSObject::ReferencesObject(Object* obj) { |
| 2557 AssertNoAllocation no_alloc; | 2624 AssertNoAllocation no_alloc; |
| 2558 | 2625 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2646 } | 2713 } |
| 2647 } | 2714 } |
| 2648 | 2715 |
| 2649 // No references to object. | 2716 // No references to object. |
| 2650 return false; | 2717 return false; |
| 2651 } | 2718 } |
| 2652 | 2719 |
| 2653 | 2720 |
| 2654 Object* JSObject::PreventExtensions() { | 2721 Object* JSObject::PreventExtensions() { |
| 2655 // If there are fast elements we normalize. | 2722 // If there are fast elements we normalize. |
| 2723 Object* ok; |
| 2724 { TryAllocation t = NormalizeElements(); |
| 2725 if (!t->ToObject(&ok)) return t; |
| 2726 } |
| 2656 if (HasFastElements()) { | 2727 if (HasFastElements()) { |
| 2657 Object* ok = NormalizeElements(); | |
| 2658 if (ok->IsFailure()) return ok; | |
| 2659 } | 2728 } |
| 2660 // Make sure that we never go back to fast case. | 2729 // Make sure that we never go back to fast case. |
| 2661 element_dictionary()->set_requires_slow_elements(); | 2730 element_dictionary()->set_requires_slow_elements(); |
| 2662 | 2731 |
| 2663 // Do a map transition, other objects with this map may still | 2732 // Do a map transition, other objects with this map may still |
| 2733 Object* new_map; |
| 2734 { TryAllocation t = map()->CopyDropTransitions(); |
| 2735 if (!t->ToObject(&new_map)) return t; |
| 2736 } |
| 2664 // be extensible. | 2737 // be extensible. |
| 2665 Object* new_map = map()->CopyDropTransitions(); | |
| 2666 if (new_map->IsFailure()) return new_map; | |
| 2667 Map::cast(new_map)->set_is_extensible(false); | 2738 Map::cast(new_map)->set_is_extensible(false); |
| 2668 set_map(Map::cast(new_map)); | 2739 set_map(Map::cast(new_map)); |
| 2669 ASSERT(!map()->is_extensible()); | 2740 ASSERT(!map()->is_extensible()); |
| 2670 return new_map; | 2741 return new_map; |
| 2671 } | 2742 } |
| 2672 | 2743 |
| 2673 | 2744 |
| 2674 // Tests for the fast common case for property enumeration: | 2745 // Tests for the fast common case for property enumeration: |
| 2675 // - This object and all prototypes has an enum cache (which means that it has | 2746 // - This object and all prototypes has an enum cache (which means that it has |
| 2676 // no interceptors and needs no access checks). | 2747 // no interceptors and needs no access checks). |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2860 Object* obj = result.GetCallbackObject(); | 2931 Object* obj = result.GetCallbackObject(); |
| 2861 // Need to preserve old getters/setters. | 2932 // Need to preserve old getters/setters. |
| 2862 if (obj->IsFixedArray()) { | 2933 if (obj->IsFixedArray()) { |
| 2863 // Use set to update attributes. | 2934 // Use set to update attributes. |
| 2864 return SetPropertyCallback(name, obj, attributes); | 2935 return SetPropertyCallback(name, obj, attributes); |
| 2865 } | 2936 } |
| 2866 } | 2937 } |
| 2867 } | 2938 } |
| 2868 } | 2939 } |
| 2869 | 2940 |
| 2941 Object* structure; |
| 2942 { TryAllocation t = Heap::AllocateFixedArray(2, TENURED); |
| 2943 if (!t->ToObject(&structure)) return t; |
| 2944 } |
| 2870 // Allocate the fixed array to hold getter and setter. | 2945 // Allocate the fixed array to hold getter and setter. |
| 2871 Object* structure = Heap::AllocateFixedArray(2, TENURED); | |
| 2872 if (structure->IsFailure()) return structure; | |
| 2873 | 2946 |
| 2874 if (is_element) { | 2947 if (is_element) { |
| 2875 return SetElementCallback(index, structure, attributes); | 2948 return SetElementCallback(index, structure, attributes); |
| 2876 } else { | 2949 } else { |
| 2877 return SetPropertyCallback(name, structure, attributes); | 2950 return SetPropertyCallback(name, structure, attributes); |
| 2878 } | 2951 } |
| 2879 } | 2952 } |
| 2880 | 2953 |
| 2881 | 2954 |
| 2882 bool JSObject::CanSetCallback(String* name) { | 2955 bool JSObject::CanSetCallback(String* name) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2901 | 2974 |
| 2902 return true; | 2975 return true; |
| 2903 } | 2976 } |
| 2904 | 2977 |
| 2905 | 2978 |
| 2906 Object* JSObject::SetElementCallback(uint32_t index, | 2979 Object* JSObject::SetElementCallback(uint32_t index, |
| 2907 Object* structure, | 2980 Object* structure, |
| 2908 PropertyAttributes attributes) { | 2981 PropertyAttributes attributes) { |
| 2909 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); | 2982 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); |
| 2910 | 2983 |
| 2984 Object* ok; |
| 2985 { TryAllocation t = NormalizeElements(); |
| 2986 if (!t->ToObject(&ok)) return t; |
| 2987 } |
| 2911 // Normalize elements to make this operation simple. | 2988 // Normalize elements to make this operation simple. |
| 2912 Object* ok = NormalizeElements(); | |
| 2913 if (ok->IsFailure()) return ok; | |
| 2914 | 2989 |
| 2915 // Update the dictionary with the new CALLBACKS property. | 2990 // Update the dictionary with the new CALLBACKS property. |
| 2916 Object* dict = | 2991 Object* dict; |
| 2917 element_dictionary()->Set(index, structure, details); | 2992 { TryAllocation t = |
| 2918 if (dict->IsFailure()) return dict; | 2993 element_dictionary()->Set(index, structure, details); |
| 2994 if (!t->ToObject(&dict)) return t; |
| 2995 } |
| 2919 | 2996 |
| 2920 NumberDictionary* elements = NumberDictionary::cast(dict); | 2997 NumberDictionary* elements = NumberDictionary::cast(dict); |
| 2921 elements->set_requires_slow_elements(); | 2998 elements->set_requires_slow_elements(); |
| 2922 // Set the potential new dictionary on the object. | 2999 // Set the potential new dictionary on the object. |
| 2923 set_elements(elements); | 3000 set_elements(elements); |
| 2924 | 3001 |
| 2925 return structure; | 3002 return structure; |
| 2926 } | 3003 } |
| 2927 | 3004 |
| 2928 | 3005 |
| 2929 Object* JSObject::SetPropertyCallback(String* name, | 3006 Object* JSObject::SetPropertyCallback(String* name, |
| 2930 Object* structure, | 3007 Object* structure, |
| 2931 PropertyAttributes attributes) { | 3008 PropertyAttributes attributes) { |
| 2932 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); | 3009 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); |
| 2933 | 3010 |
| 2934 bool convert_back_to_fast = HasFastProperties() && | 3011 bool convert_back_to_fast = HasFastProperties() && |
| 2935 (map()->instance_descriptors()->number_of_descriptors() | 3012 (map()->instance_descriptors()->number_of_descriptors() |
| 2936 < DescriptorArray::kMaxNumberOfDescriptors); | 3013 < DescriptorArray::kMaxNumberOfDescriptors); |
| 2937 | 3014 |
| 3015 Object* ok; |
| 3016 { TryAllocation t = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 3017 if (!t->ToObject(&ok)) return t; |
| 3018 } |
| 2938 // Normalize object to make this operation simple. | 3019 // Normalize object to make this operation simple. |
| 2939 Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | |
| 2940 if (ok->IsFailure()) return ok; | |
| 2941 | 3020 |
| 2942 // For the global object allocate a new map to invalidate the global inline | 3021 // For the global object allocate a new map to invalidate the global inline |
| 2943 // caches which have a global property cell reference directly in the code. | 3022 // caches which have a global property cell reference directly in the code. |
| 3023 Object* new_map; |
| 3024 { TryAllocation t = map()->CopyDropDescriptors(); |
| 3025 if (!t->ToObject(&new_map)) return t; |
| 3026 } |
| 2944 if (IsGlobalObject()) { | 3027 if (IsGlobalObject()) { |
| 2945 Object* new_map = map()->CopyDropDescriptors(); | |
| 2946 if (new_map->IsFailure()) return new_map; | |
| 2947 set_map(Map::cast(new_map)); | 3028 set_map(Map::cast(new_map)); |
| 2948 } | 3029 } |
| 2949 | 3030 |
| 3031 Object* result; |
| 3032 { TryAllocation t = SetNormalizedProperty(name, structure, details); |
| 3033 if (!t->ToObject(&result)) return t; |
| 3034 } |
| 2950 // Update the dictionary with the new CALLBACKS property. | 3035 // Update the dictionary with the new CALLBACKS property. |
| 2951 Object* result = SetNormalizedProperty(name, structure, details); | |
| 2952 if (result->IsFailure()) return result; | |
| 2953 | 3036 |
| 3037 { TryAllocation t = TransformToFastProperties(0); |
| 3038 if (!t->ToObject(&ok)) return t; |
| 3039 } |
| 2954 if (convert_back_to_fast) { | 3040 if (convert_back_to_fast) { |
| 2955 ok = TransformToFastProperties(0); | |
| 2956 if (ok->IsFailure()) return ok; | |
| 2957 } | 3041 } |
| 2958 return result; | 3042 return result; |
| 2959 } | 3043 } |
| 2960 | 3044 |
| 2961 Object* JSObject::DefineAccessor(String* name, bool is_getter, JSFunction* fun, | 3045 Object* JSObject::DefineAccessor(String* name, bool is_getter, JSFunction* fun, |
| 2962 PropertyAttributes attributes) { | 3046 PropertyAttributes attributes) { |
| 2963 // Check access rights if needed. | 3047 // Check access rights if needed. |
| 2964 if (IsAccessCheckNeeded() && | 3048 if (IsAccessCheckNeeded() && |
| 2965 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { | 3049 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { |
| 2966 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); | 3050 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3029 case EXTERNAL_FLOAT_ELEMENTS: | 3113 case EXTERNAL_FLOAT_ELEMENTS: |
| 3030 // Ignore getters and setters on pixel and external array | 3114 // Ignore getters and setters on pixel and external array |
| 3031 // elements. | 3115 // elements. |
| 3032 return Heap::undefined_value(); | 3116 return Heap::undefined_value(); |
| 3033 case DICTIONARY_ELEMENTS: | 3117 case DICTIONARY_ELEMENTS: |
| 3034 break; | 3118 break; |
| 3035 default: | 3119 default: |
| 3036 UNREACHABLE(); | 3120 UNREACHABLE(); |
| 3037 break; | 3121 break; |
| 3038 } | 3122 } |
| 3123 Object* ok; |
| 3124 { TryAllocation t = |
| 3125 SetElementCallback(index, info, info->property_attributes()); |
| 3126 if (!t->ToObject(&ok)) return t; |
| 3127 } |
| 3039 | 3128 |
| 3040 Object* ok = SetElementCallback(index, info, info->property_attributes()); | |
| 3041 if (ok->IsFailure()) return ok; | |
| 3042 } else { | 3129 } else { |
| 3043 // Lookup the name. | 3130 // Lookup the name. |
| 3044 LookupResult result; | 3131 LookupResult result; |
| 3045 LocalLookup(name, &result); | 3132 LocalLookup(name, &result); |
| 3046 // ES5 forbids turning a property into an accessor if it's not | 3133 // ES5 forbids turning a property into an accessor if it's not |
| 3047 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5). | 3134 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5). |
| 3048 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) { | 3135 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) { |
| 3049 return Heap::undefined_value(); | 3136 return Heap::undefined_value(); |
| 3137 Object* ok; |
| 3138 { TryAllocation t = |
| 3139 SetPropertyCallback(name, info, info->property_attributes()); |
| 3140 if (!t->ToObject(&ok)) return t; |
| 3050 } | 3141 } |
| 3051 Object* ok = SetPropertyCallback(name, info, info->property_attributes()); | 3142 } |
| 3052 if (ok->IsFailure()) return ok; | |
| 3053 } | 3143 } |
| 3054 | 3144 |
| 3055 return this; | 3145 return this; |
| 3056 } | 3146 } |
| 3057 | 3147 |
| 3058 | 3148 |
| 3059 Object* JSObject::LookupAccessor(String* name, bool is_getter) { | 3149 Object* JSObject::LookupAccessor(String* name, bool is_getter) { |
| 3060 // Make sure that the top context does not change when doing callbacks or | 3150 // Make sure that the top context does not change when doing callbacks or |
| 3061 // interceptor calls. | 3151 // interceptor calls. |
| 3062 AssertNoContextChange ncc; | 3152 AssertNoContextChange ncc; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3125 } | 3215 } |
| 3126 } | 3216 } |
| 3127 } | 3217 } |
| 3128 return Heap::undefined_value(); | 3218 return Heap::undefined_value(); |
| 3129 } else { | 3219 } else { |
| 3130 return property_dictionary()->SlowReverseLookup(value); | 3220 return property_dictionary()->SlowReverseLookup(value); |
| 3131 } | 3221 } |
| 3132 } | 3222 } |
| 3133 | 3223 |
| 3134 | 3224 |
| 3225 Object* result; |
| 3226 { TryAllocation t = Heap::AllocateMap(instance_type(), instance_size()); |
| 3227 if (!t->ToObject(&result)) return t; |
| 3228 } |
| 3135 Object* Map::CopyDropDescriptors() { | 3229 Object* Map::CopyDropDescriptors() { |
| 3136 Object* result = Heap::AllocateMap(instance_type(), instance_size()); | |
| 3137 if (result->IsFailure()) return result; | |
| 3138 Map::cast(result)->set_prototype(prototype()); | 3230 Map::cast(result)->set_prototype(prototype()); |
| 3139 Map::cast(result)->set_constructor(constructor()); | 3231 Map::cast(result)->set_constructor(constructor()); |
| 3140 // Don't copy descriptors, so map transitions always remain a forest. | 3232 // Don't copy descriptors, so map transitions always remain a forest. |
| 3141 // If we retained the same descriptors we would have two maps | 3233 // If we retained the same descriptors we would have two maps |
| 3142 // pointing to the same transition which is bad because the garbage | 3234 // pointing to the same transition which is bad because the garbage |
| 3143 // collector relies on being able to reverse pointers from transitions | 3235 // collector relies on being able to reverse pointers from transitions |
| 3144 // to maps. If properties need to be retained use CopyDropTransitions. | 3236 // to maps. If properties need to be retained use CopyDropTransitions. |
| 3145 Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array()); | 3237 Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array()); |
| 3146 // Please note instance_type and instance_size are set when allocated. | 3238 // Please note instance_type and instance_size are set when allocated. |
| 3147 Map::cast(result)->set_inobject_properties(inobject_properties()); | 3239 Map::cast(result)->set_inobject_properties(inobject_properties()); |
| 3148 Map::cast(result)->set_unused_property_fields(unused_property_fields()); | 3240 Map::cast(result)->set_unused_property_fields(unused_property_fields()); |
| 3149 | 3241 |
| 3150 // If the map has pre-allocated properties always start out with a descriptor | 3242 // If the map has pre-allocated properties always start out with a descriptor |
| 3151 // array describing these properties. | 3243 // array describing these properties. |
| 3152 if (pre_allocated_property_fields() > 0) { | 3244 if (pre_allocated_property_fields() > 0) { |
| 3153 ASSERT(constructor()->IsJSFunction()); | 3245 ASSERT(constructor()->IsJSFunction()); |
| 3154 JSFunction* ctor = JSFunction::cast(constructor()); | 3246 JSFunction* ctor = JSFunction::cast(constructor()); |
| 3155 Object* descriptors = | 3247 Object* descriptors; |
| 3156 ctor->initial_map()->instance_descriptors()->RemoveTransitions(); | 3248 { TryAllocation t = |
| 3157 if (descriptors->IsFailure()) return descriptors; | 3249 ctor->initial_map()->instance_descriptors()->RemoveTransitions(); |
| 3250 if (!t->ToObject(&descriptors)) return t; |
| 3251 } |
| 3158 Map::cast(result)->set_instance_descriptors( | 3252 Map::cast(result)->set_instance_descriptors( |
| 3159 DescriptorArray::cast(descriptors)); | 3253 DescriptorArray::cast(descriptors)); |
| 3160 Map::cast(result)->set_pre_allocated_property_fields( | 3254 Map::cast(result)->set_pre_allocated_property_fields( |
| 3161 pre_allocated_property_fields()); | 3255 pre_allocated_property_fields()); |
| 3162 } | 3256 } |
| 3163 Map::cast(result)->set_bit_field(bit_field()); | 3257 Map::cast(result)->set_bit_field(bit_field()); |
| 3164 Map::cast(result)->set_bit_field2(bit_field2()); | 3258 Map::cast(result)->set_bit_field2(bit_field2()); |
| 3165 Map::cast(result)->set_is_shared(false); | 3259 Map::cast(result)->set_is_shared(false); |
| 3166 Map::cast(result)->ClearCodeCache(); | 3260 Map::cast(result)->ClearCodeCache(); |
| 3167 return result; | 3261 return result; |
| 3168 } | 3262 } |
| 3169 | 3263 |
| 3170 | 3264 |
| 3171 Object* Map::CopyNormalized(PropertyNormalizationMode mode, | 3265 Object* Map::CopyNormalized(PropertyNormalizationMode mode, |
| 3172 NormalizedMapSharingMode sharing) { | 3266 NormalizedMapSharingMode sharing) { |
| 3173 int new_instance_size = instance_size(); | 3267 int new_instance_size = instance_size(); |
| 3174 if (mode == CLEAR_INOBJECT_PROPERTIES) { | 3268 if (mode == CLEAR_INOBJECT_PROPERTIES) { |
| 3175 new_instance_size -= inobject_properties() * kPointerSize; | 3269 new_instance_size -= inobject_properties() * kPointerSize; |
| 3176 } | 3270 } |
| 3271 Object* result; |
| 3272 { TryAllocation t = Heap::AllocateMap(instance_type(), new_instance_size); |
| 3273 if (!t->ToObject(&result)) return t; |
| 3274 } |
| 3177 | 3275 |
| 3178 Object* result = Heap::AllocateMap(instance_type(), new_instance_size); | |
| 3179 if (result->IsFailure()) return result; | |
| 3180 | 3276 |
| 3181 if (mode != CLEAR_INOBJECT_PROPERTIES) { | 3277 if (mode != CLEAR_INOBJECT_PROPERTIES) { |
| 3182 Map::cast(result)->set_inobject_properties(inobject_properties()); | 3278 Map::cast(result)->set_inobject_properties(inobject_properties()); |
| 3183 } | 3279 } |
| 3184 | 3280 |
| 3185 Map::cast(result)->set_prototype(prototype()); | 3281 Map::cast(result)->set_prototype(prototype()); |
| 3186 Map::cast(result)->set_constructor(constructor()); | 3282 Map::cast(result)->set_constructor(constructor()); |
| 3187 | 3283 |
| 3188 Map::cast(result)->set_bit_field(bit_field()); | 3284 Map::cast(result)->set_bit_field(bit_field()); |
| 3189 Map::cast(result)->set_bit_field2(bit_field2()); | 3285 Map::cast(result)->set_bit_field2(bit_field2()); |
| 3190 | 3286 |
| 3191 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP); | 3287 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP); |
| 3192 | 3288 |
| 3193 #ifdef DEBUG | 3289 #ifdef DEBUG |
| 3194 if (Map::cast(result)->is_shared()) { | 3290 if (Map::cast(result)->is_shared()) { |
| 3195 Map::cast(result)->SharedMapVerify(); | 3291 Map::cast(result)->SharedMapVerify(); |
| 3196 } | 3292 } |
| 3197 #endif | 3293 #endif |
| 3198 | 3294 |
| 3199 return result; | 3295 return result; |
| 3200 } | 3296 } |
| 3201 | 3297 |
| 3202 | 3298 |
| 3299 Object* new_map; |
| 3300 { TryAllocation t = CopyDropDescriptors(); |
| 3301 if (!t->ToObject(&new_map)) return t; |
| 3302 } |
| 3203 Object* Map::CopyDropTransitions() { | 3303 Object* Map::CopyDropTransitions() { |
| 3204 Object* new_map = CopyDropDescriptors(); | 3304 Object* descriptors; |
| 3205 if (new_map->IsFailure()) return new_map; | 3305 { TryAllocation t = instance_descriptors()->RemoveTransitions(); |
| 3206 Object* descriptors = instance_descriptors()->RemoveTransitions(); | 3306 if (!t->ToObject(&descriptors)) return t; |
| 3207 if (descriptors->IsFailure()) return descriptors; | 3307 } |
| 3208 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); | 3308 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); |
| 3209 return new_map; | 3309 return new_map; |
| 3210 } | 3310 } |
| 3211 | 3311 |
| 3212 | 3312 |
| 3213 Object* Map::UpdateCodeCache(String* name, Code* code) { | 3313 Object* Map::UpdateCodeCache(String* name, Code* code) { |
| 3214 // Allocate the code cache if not present. | 3314 // Allocate the code cache if not present. |
| 3315 Object* result; |
| 3316 { TryAllocation t = Heap::AllocateCodeCache(); |
| 3317 if (!t->ToObject(&result)) return t; |
| 3318 } |
| 3215 if (code_cache()->IsFixedArray()) { | 3319 if (code_cache()->IsFixedArray()) { |
| 3216 Object* result = Heap::AllocateCodeCache(); | |
| 3217 if (result->IsFailure()) return result; | |
| 3218 set_code_cache(result); | 3320 set_code_cache(result); |
| 3219 } | 3321 } |
| 3220 | 3322 |
| 3221 // Update the code cache. | 3323 // Update the code cache. |
| 3222 return CodeCache::cast(code_cache())->Update(name, code); | 3324 return CodeCache::cast(code_cache())->Update(name, code); |
| 3223 } | 3325 } |
| 3224 | 3326 |
| 3225 | 3327 |
| 3226 Object* Map::FindInCodeCache(String* name, Code::Flags flags) { | 3328 Object* Map::FindInCodeCache(String* name, Code::Flags flags) { |
| 3227 // Do a lookup if a code cache exists. | 3329 // Do a lookup if a code cache exists. |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3293 | 3395 |
| 3294 Object* CodeCache::Update(String* name, Code* code) { | 3396 Object* CodeCache::Update(String* name, Code* code) { |
| 3295 ASSERT(code->ic_state() == MONOMORPHIC); | 3397 ASSERT(code->ic_state() == MONOMORPHIC); |
| 3296 | 3398 |
| 3297 // The number of monomorphic stubs for normal load/store/call IC's can grow to | 3399 // The number of monomorphic stubs for normal load/store/call IC's can grow to |
| 3298 // a large number and therefore they need to go into a hash table. They are | 3400 // a large number and therefore they need to go into a hash table. They are |
| 3299 // used to load global properties from cells. | 3401 // used to load global properties from cells. |
| 3300 if (code->type() == NORMAL) { | 3402 if (code->type() == NORMAL) { |
| 3301 // Make sure that a hash table is allocated for the normal load code cache. | 3403 // Make sure that a hash table is allocated for the normal load code cache. |
| 3302 if (normal_type_cache()->IsUndefined()) { | 3404 if (normal_type_cache()->IsUndefined()) { |
| 3303 Object* result = | 3405 Object* result; |
| 3304 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize); | 3406 { TryAllocation t = |
| 3305 if (result->IsFailure()) return result; | 3407 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize); |
| 3408 if (!t->ToObject(&result)) return t; |
| 3409 } |
| 3306 set_normal_type_cache(result); | 3410 set_normal_type_cache(result); |
| 3307 } | 3411 } |
| 3308 return UpdateNormalTypeCache(name, code); | 3412 return UpdateNormalTypeCache(name, code); |
| 3309 } else { | 3413 } else { |
| 3310 ASSERT(default_cache()->IsFixedArray()); | 3414 ASSERT(default_cache()->IsFixedArray()); |
| 3311 return UpdateDefaultCache(name, code); | 3415 return UpdateDefaultCache(name, code); |
| 3312 } | 3416 } |
| 3313 } | 3417 } |
| 3314 | 3418 |
| 3315 | 3419 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3351 if (deleted_index >= 0) { | 3455 if (deleted_index >= 0) { |
| 3352 cache->set(deleted_index + kCodeCacheEntryNameOffset, name); | 3456 cache->set(deleted_index + kCodeCacheEntryNameOffset, name); |
| 3353 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code); | 3457 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code); |
| 3354 return this; | 3458 return this; |
| 3355 } | 3459 } |
| 3356 | 3460 |
| 3357 // Extend the code cache with some new entries (at least one). Must be a | 3461 // Extend the code cache with some new entries (at least one). Must be a |
| 3358 // multiple of the entry size. | 3462 // multiple of the entry size. |
| 3359 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize; | 3463 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize; |
| 3360 new_length = new_length - new_length % kCodeCacheEntrySize; | 3464 new_length = new_length - new_length % kCodeCacheEntrySize; |
| 3465 Object* result; |
| 3466 { TryAllocation t = cache->CopySize(new_length); |
| 3467 if (!t->ToObject(&result)) return t; |
| 3468 } |
| 3361 ASSERT((new_length % kCodeCacheEntrySize) == 0); | 3469 ASSERT((new_length % kCodeCacheEntrySize) == 0); |
| 3362 Object* result = cache->CopySize(new_length); | |
| 3363 if (result->IsFailure()) return result; | |
| 3364 | 3470 |
| 3365 // Add the (name, code) pair to the new cache. | 3471 // Add the (name, code) pair to the new cache. |
| 3366 cache = FixedArray::cast(result); | 3472 cache = FixedArray::cast(result); |
| 3367 cache->set(length + kCodeCacheEntryNameOffset, name); | 3473 cache->set(length + kCodeCacheEntryNameOffset, name); |
| 3368 cache->set(length + kCodeCacheEntryCodeOffset, code); | 3474 cache->set(length + kCodeCacheEntryCodeOffset, code); |
| 3369 set_default_cache(cache); | 3475 set_default_cache(cache); |
| 3370 return this; | 3476 return this; |
| 3371 } | 3477 } |
| 3372 | 3478 |
| 3373 | 3479 |
| 3374 Object* CodeCache::UpdateNormalTypeCache(String* name, Code* code) { | 3480 Object* CodeCache::UpdateNormalTypeCache(String* name, Code* code) { |
| 3375 // Adding a new entry can cause a new cache to be allocated. | 3481 // Adding a new entry can cause a new cache to be allocated. |
| 3482 Object* new_cache; |
| 3483 { TryAllocation t = cache->Put(name, code); |
| 3484 if (!t->ToObject(&new_cache)) return t; |
| 3485 } |
| 3376 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache()); | 3486 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache()); |
| 3377 Object* new_cache = cache->Put(name, code); | |
| 3378 if (new_cache->IsFailure()) return new_cache; | |
| 3379 set_normal_type_cache(new_cache); | 3487 set_normal_type_cache(new_cache); |
| 3380 return this; | 3488 return this; |
| 3381 } | 3489 } |
| 3382 | 3490 |
| 3383 | 3491 |
| 3384 Object* CodeCache::Lookup(String* name, Code::Flags flags) { | 3492 Object* CodeCache::Lookup(String* name, Code::Flags flags) { |
| 3385 if (Code::ExtractTypeFromFlags(flags) == NORMAL) { | 3493 if (Code::ExtractTypeFromFlags(flags) == NORMAL) { |
| 3386 return LookupNormalTypeCache(name, flags); | 3494 return LookupNormalTypeCache(name, flags); |
| 3387 } else { | 3495 } else { |
| 3388 return LookupDefaultCache(name, flags); | 3496 return LookupDefaultCache(name, flags); |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3487 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); } | 3595 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); } |
| 3488 | 3596 |
| 3489 uint32_t HashForObject(Object* obj) { | 3597 uint32_t HashForObject(Object* obj) { |
| 3490 FixedArray* pair = FixedArray::cast(obj); | 3598 FixedArray* pair = FixedArray::cast(obj); |
| 3491 String* name = String::cast(pair->get(0)); | 3599 String* name = String::cast(pair->get(0)); |
| 3492 Code* code = Code::cast(pair->get(1)); | 3600 Code* code = Code::cast(pair->get(1)); |
| 3493 return NameFlagsHashHelper(name, code->flags()); | 3601 return NameFlagsHashHelper(name, code->flags()); |
| 3494 } | 3602 } |
| 3495 | 3603 |
| 3496 Object* AsObject() { | 3604 Object* AsObject() { |
| 3605 Object* obj; |
| 3606 { TryAllocation t = Heap::AllocateFixedArray(2); |
| 3607 if (!t->ToObject(&obj)) return t; |
| 3608 } |
| 3497 ASSERT(code_ != NULL); | 3609 ASSERT(code_ != NULL); |
| 3498 Object* obj = Heap::AllocateFixedArray(2); | |
| 3499 if (obj->IsFailure()) return obj; | |
| 3500 FixedArray* pair = FixedArray::cast(obj); | 3610 FixedArray* pair = FixedArray::cast(obj); |
| 3501 pair->set(0, name_); | 3611 pair->set(0, name_); |
| 3502 pair->set(1, code_); | 3612 pair->set(1, code_); |
| 3503 return pair; | 3613 return pair; |
| 3504 } | 3614 } |
| 3505 | 3615 |
| 3506 private: | 3616 private: |
| 3507 String* name_; | 3617 String* name_; |
| 3508 Code::Flags flags_; | 3618 Code::Flags flags_; |
| 3509 Code* code_; | 3619 Code* code_; |
| 3510 }; | 3620 }; |
| 3511 | 3621 |
| 3512 | 3622 |
| 3513 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { | 3623 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { |
| 3514 CodeCacheHashTableKey key(name, flags); | 3624 CodeCacheHashTableKey key(name, flags); |
| 3515 int entry = FindEntry(&key); | 3625 int entry = FindEntry(&key); |
| 3516 if (entry == kNotFound) return Heap::undefined_value(); | 3626 if (entry == kNotFound) return Heap::undefined_value(); |
| 3517 return get(EntryToIndex(entry) + 1); | 3627 return get(EntryToIndex(entry) + 1); |
| 3518 } | 3628 } |
| 3519 | 3629 |
| 3520 | 3630 |
| 3521 Object* CodeCacheHashTable::Put(String* name, Code* code) { | 3631 Object* CodeCacheHashTable::Put(String* name, Code* code) { |
| 3632 Object* obj; |
| 3633 { TryAllocation t = EnsureCapacity(1, &key); |
| 3634 if (!t->ToObject(&obj)) return t; |
| 3635 } |
| 3522 CodeCacheHashTableKey key(name, code); | 3636 CodeCacheHashTableKey key(name, code); |
| 3523 Object* obj = EnsureCapacity(1, &key); | |
| 3524 if (obj->IsFailure()) return obj; | |
| 3525 | 3637 |
| 3526 // Don't use this, as the table might have grown. | 3638 // Don't use this, as the table might have grown. |
| 3527 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); | 3639 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); |
| 3528 | 3640 |
| 3641 Object* k; |
| 3642 { TryAllocation t = key.AsObject(); |
| 3643 if (!t->ToObject(&k)) return t; |
| 3644 } |
| 3529 int entry = cache->FindInsertionEntry(key.Hash()); | 3645 int entry = cache->FindInsertionEntry(key.Hash()); |
| 3530 Object* k = key.AsObject(); | |
| 3531 if (k->IsFailure()) return k; | |
| 3532 | 3646 |
| 3533 cache->set(EntryToIndex(entry), k); | 3647 cache->set(EntryToIndex(entry), k); |
| 3534 cache->set(EntryToIndex(entry) + 1, code); | 3648 cache->set(EntryToIndex(entry) + 1, code); |
| 3535 cache->ElementAdded(); | 3649 cache->ElementAdded(); |
| 3536 return cache; | 3650 return cache; |
| 3537 } | 3651 } |
| 3538 | 3652 |
| 3539 | 3653 |
| 3540 int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) { | 3654 int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) { |
| 3541 CodeCacheHashTableKey key(name, flags); | 3655 CodeCacheHashTableKey key(name, flags); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3568 | 3682 |
| 3569 Object* FixedArray::AddKeysFromJSArray(JSArray* array) { | 3683 Object* FixedArray::AddKeysFromJSArray(JSArray* array) { |
| 3570 ASSERT(!array->HasPixelElements() && !array->HasExternalArrayElements()); | 3684 ASSERT(!array->HasPixelElements() && !array->HasExternalArrayElements()); |
| 3571 switch (array->GetElementsKind()) { | 3685 switch (array->GetElementsKind()) { |
| 3572 case JSObject::FAST_ELEMENTS: | 3686 case JSObject::FAST_ELEMENTS: |
| 3573 return UnionOfKeys(FixedArray::cast(array->elements())); | 3687 return UnionOfKeys(FixedArray::cast(array->elements())); |
| 3574 case JSObject::DICTIONARY_ELEMENTS: { | 3688 case JSObject::DICTIONARY_ELEMENTS: { |
| 3575 NumberDictionary* dict = array->element_dictionary(); | 3689 NumberDictionary* dict = array->element_dictionary(); |
| 3576 int size = dict->NumberOfElements(); | 3690 int size = dict->NumberOfElements(); |
| 3577 | 3691 |
| 3692 Object* object; |
| 3693 { TryAllocation t = Heap::AllocateFixedArray(size); |
| 3694 if (!t->ToObject(&object)) return t; |
| 3695 } |
| 3578 // Allocate a temporary fixed array. | 3696 // Allocate a temporary fixed array. |
| 3579 Object* object = Heap::AllocateFixedArray(size); | |
| 3580 if (object->IsFailure()) return object; | |
| 3581 FixedArray* key_array = FixedArray::cast(object); | 3697 FixedArray* key_array = FixedArray::cast(object); |
| 3582 | 3698 |
| 3583 int capacity = dict->Capacity(); | 3699 int capacity = dict->Capacity(); |
| 3584 int pos = 0; | 3700 int pos = 0; |
| 3585 // Copy the elements from the JSArray to the temporary fixed array. | 3701 // Copy the elements from the JSArray to the temporary fixed array. |
| 3586 for (int i = 0; i < capacity; i++) { | 3702 for (int i = 0; i < capacity; i++) { |
| 3587 if (dict->IsKey(dict->KeyAt(i))) { | 3703 if (dict->IsKey(dict->KeyAt(i))) { |
| 3588 key_array->set(pos++, dict->ValueAt(i)); | 3704 key_array->set(pos++, dict->ValueAt(i)); |
| 3589 } | 3705 } |
| 3590 } | 3706 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3608 | 3724 |
| 3609 // Compute how many elements are not in this. | 3725 // Compute how many elements are not in this. |
| 3610 int extra = 0; | 3726 int extra = 0; |
| 3611 for (int y = 0; y < len1; y++) { | 3727 for (int y = 0; y < len1; y++) { |
| 3612 Object* value = other->get(y); | 3728 Object* value = other->get(y); |
| 3613 if (!value->IsTheHole() && !HasKey(this, value)) extra++; | 3729 if (!value->IsTheHole() && !HasKey(this, value)) extra++; |
| 3614 } | 3730 } |
| 3615 | 3731 |
| 3616 if (extra == 0) return this; | 3732 if (extra == 0) return this; |
| 3617 | 3733 |
| 3734 Object* obj; |
| 3735 { TryAllocation t = Heap::AllocateFixedArray(len0 + extra); |
| 3736 if (!t->ToObject(&obj)) return t; |
| 3737 } |
| 3618 // Allocate the result | 3738 // Allocate the result |
| 3619 Object* obj = Heap::AllocateFixedArray(len0 + extra); | |
| 3620 if (obj->IsFailure()) return obj; | |
| 3621 // Fill in the content | 3739 // Fill in the content |
| 3622 AssertNoAllocation no_gc; | 3740 AssertNoAllocation no_gc; |
| 3623 FixedArray* result = FixedArray::cast(obj); | 3741 FixedArray* result = FixedArray::cast(obj); |
| 3624 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); | 3742 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); |
| 3625 for (int i = 0; i < len0; i++) { | 3743 for (int i = 0; i < len0; i++) { |
| 3626 result->set(i, get(i), mode); | 3744 result->set(i, get(i), mode); |
| 3627 } | 3745 } |
| 3628 // Fill in the extra keys. | 3746 // Fill in the extra keys. |
| 3629 int index = 0; | 3747 int index = 0; |
| 3630 for (int y = 0; y < len1; y++) { | 3748 for (int y = 0; y < len1; y++) { |
| 3631 Object* value = other->get(y); | 3749 Object* value = other->get(y); |
| 3632 if (!value->IsTheHole() && !HasKey(this, value)) { | 3750 if (!value->IsTheHole() && !HasKey(this, value)) { |
| 3633 result->set(len0 + index, other->get(y), mode); | 3751 result->set(len0 + index, other->get(y), mode); |
| 3634 index++; | 3752 index++; |
| 3635 } | 3753 } |
| 3636 } | 3754 } |
| 3637 ASSERT(extra == index); | 3755 ASSERT(extra == index); |
| 3638 return result; | 3756 return result; |
| 3639 } | 3757 } |
| 3640 | 3758 |
| 3641 | 3759 |
| 3642 Object* FixedArray::CopySize(int new_length) { | 3760 Object* FixedArray::CopySize(int new_length) { |
| 3761 Object* obj; |
| 3762 { TryAllocation t = Heap::AllocateFixedArray(new_length); |
| 3763 if (!t->ToObject(&obj)) return t; |
| 3764 } |
| 3643 if (new_length == 0) return Heap::empty_fixed_array(); | 3765 if (new_length == 0) return Heap::empty_fixed_array(); |
| 3644 Object* obj = Heap::AllocateFixedArray(new_length); | |
| 3645 if (obj->IsFailure()) return obj; | |
| 3646 FixedArray* result = FixedArray::cast(obj); | 3766 FixedArray* result = FixedArray::cast(obj); |
| 3647 // Copy the content | 3767 // Copy the content |
| 3648 AssertNoAllocation no_gc; | 3768 AssertNoAllocation no_gc; |
| 3649 int len = length(); | 3769 int len = length(); |
| 3650 if (new_length < len) len = new_length; | 3770 if (new_length < len) len = new_length; |
| 3651 result->set_map(map()); | 3771 result->set_map(map()); |
| 3652 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); | 3772 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); |
| 3653 for (int i = 0; i < len; i++) { | 3773 for (int i = 0; i < len; i++) { |
| 3654 result->set(i, get(i), mode); | 3774 result->set(i, get(i), mode); |
| 3655 } | 3775 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3675 return true; | 3795 return true; |
| 3676 } | 3796 } |
| 3677 #endif | 3797 #endif |
| 3678 | 3798 |
| 3679 | 3799 |
| 3680 Object* DescriptorArray::Allocate(int number_of_descriptors) { | 3800 Object* DescriptorArray::Allocate(int number_of_descriptors) { |
| 3681 if (number_of_descriptors == 0) { | 3801 if (number_of_descriptors == 0) { |
| 3682 return Heap::empty_descriptor_array(); | 3802 return Heap::empty_descriptor_array(); |
| 3683 } | 3803 } |
| 3684 // Allocate the array of keys. | 3804 // Allocate the array of keys. |
| 3685 Object* array = | 3805 Object* array; |
| 3686 Heap::AllocateFixedArray(ToKeyIndex(number_of_descriptors)); | 3806 { TryAllocation t = |
| 3687 if (array->IsFailure()) return array; | 3807 Heap::AllocateFixedArray(ToKeyIndex(number_of_descriptors)); |
| 3808 if (!t->ToObject(&array)) return t; |
| 3809 } |
| 3688 // Do not use DescriptorArray::cast on incomplete object. | 3810 // Do not use DescriptorArray::cast on incomplete object. |
| 3689 FixedArray* result = FixedArray::cast(array); | 3811 FixedArray* result = FixedArray::cast(array); |
| 3690 | 3812 |
| 3813 { TryAllocation t = Heap::AllocateFixedArray(number_of_descriptors << 1); |
| 3814 if (!t->ToObject(&array)) return t; |
| 3815 } |
| 3691 // Allocate the content array and set it in the descriptor array. | 3816 // Allocate the content array and set it in the descriptor array. |
| 3692 array = Heap::AllocateFixedArray(number_of_descriptors << 1); | |
| 3693 if (array->IsFailure()) return array; | |
| 3694 result->set(kContentArrayIndex, array); | 3817 result->set(kContentArrayIndex, array); |
| 3695 result->set(kEnumerationIndexIndex, | 3818 result->set(kEnumerationIndexIndex, |
| 3696 Smi::FromInt(PropertyDetails::kInitialIndex)); | 3819 Smi::FromInt(PropertyDetails::kInitialIndex)); |
| 3697 return result; | 3820 return result; |
| 3698 } | 3821 } |
| 3699 | 3822 |
| 3700 | 3823 |
| 3701 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, | 3824 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, |
| 3702 FixedArray* new_cache) { | 3825 FixedArray* new_cache) { |
| 3703 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); | 3826 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3720 TransitionFlag transition_flag) { | 3843 TransitionFlag transition_flag) { |
| 3721 // Transitions are only kept when inserting another transition. | 3844 // Transitions are only kept when inserting another transition. |
| 3722 // This precondition is not required by this function's implementation, but | 3845 // This precondition is not required by this function's implementation, but |
| 3723 // is currently required by the semantics of maps, so we check it. | 3846 // is currently required by the semantics of maps, so we check it. |
| 3724 // Conversely, we filter after replacing, so replacing a transition and | 3847 // Conversely, we filter after replacing, so replacing a transition and |
| 3725 // removing all other transitions is not supported. | 3848 // removing all other transitions is not supported. |
| 3726 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS; | 3849 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS; |
| 3727 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition()); | 3850 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition()); |
| 3728 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR); | 3851 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR); |
| 3729 | 3852 |
| 3853 Object* result; |
| 3854 { TryAllocation t = descriptor->KeyToSymbol(); |
| 3855 if (!t->ToObject(&result)) return t; |
| 3856 } |
| 3730 // Ensure the key is a symbol. | 3857 // Ensure the key is a symbol. |
| 3731 Object* result = descriptor->KeyToSymbol(); | |
| 3732 if (result->IsFailure()) return result; | |
| 3733 | 3858 |
| 3734 int transitions = 0; | 3859 int transitions = 0; |
| 3735 int null_descriptors = 0; | 3860 int null_descriptors = 0; |
| 3736 if (remove_transitions) { | 3861 if (remove_transitions) { |
| 3737 for (int i = 0; i < number_of_descriptors(); i++) { | 3862 for (int i = 0; i < number_of_descriptors(); i++) { |
| 3738 if (IsTransition(i)) transitions++; | 3863 if (IsTransition(i)) transitions++; |
| 3739 if (IsNullDescriptor(i)) null_descriptors++; | 3864 if (IsNullDescriptor(i)) null_descriptors++; |
| 3740 } | 3865 } |
| 3741 } else { | 3866 } else { |
| 3742 for (int i = 0; i < number_of_descriptors(); i++) { | 3867 for (int i = 0; i < number_of_descriptors(); i++) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3761 if (t == CONSTANT_FUNCTION || | 3886 if (t == CONSTANT_FUNCTION || |
| 3762 t == FIELD || | 3887 t == FIELD || |
| 3763 t == CALLBACKS || | 3888 t == CALLBACKS || |
| 3764 t == INTERCEPTOR) { | 3889 t == INTERCEPTOR) { |
| 3765 keep_enumeration_index = true; | 3890 keep_enumeration_index = true; |
| 3766 } else if (remove_transitions) { | 3891 } else if (remove_transitions) { |
| 3767 // Replaced descriptor has been counted as removed if it is | 3892 // Replaced descriptor has been counted as removed if it is |
| 3768 // a transition that will be replaced. Adjust count in this case. | 3893 // a transition that will be replaced. Adjust count in this case. |
| 3769 ++new_size; | 3894 ++new_size; |
| 3770 } | 3895 } |
| 3896 { TryAllocation t = Allocate(new_size); |
| 3897 if (!t->ToObject(&result)) return t; |
| 3771 } | 3898 } |
| 3772 result = Allocate(new_size); | 3899 } |
| 3773 if (result->IsFailure()) return result; | |
| 3774 DescriptorArray* new_descriptors = DescriptorArray::cast(result); | 3900 DescriptorArray* new_descriptors = DescriptorArray::cast(result); |
| 3775 // Set the enumeration index in the descriptors and set the enumeration index | 3901 // Set the enumeration index in the descriptors and set the enumeration index |
| 3776 // in the result. | 3902 // in the result. |
| 3777 int enumeration_index = NextEnumerationIndex(); | 3903 int enumeration_index = NextEnumerationIndex(); |
| 3778 if (!descriptor->GetDetails().IsTransition()) { | 3904 if (!descriptor->GetDetails().IsTransition()) { |
| 3779 if (keep_enumeration_index) { | 3905 if (keep_enumeration_index) { |
| 3780 descriptor->SetEnumerationIndex( | 3906 descriptor->SetEnumerationIndex( |
| 3781 PropertyDetails(GetDetails(index)).index()); | 3907 PropertyDetails(GetDetails(index)).index()); |
| 3782 } else { | 3908 } else { |
| 3783 descriptor->SetEnumerationIndex(enumeration_index); | 3909 descriptor->SetEnumerationIndex(enumeration_index); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3822 // Remove all transitions and null descriptors. Return a copy of the array | 3948 // Remove all transitions and null descriptors. Return a copy of the array |
| 3823 // with all transitions removed, or a Failure object if the new array could | 3949 // with all transitions removed, or a Failure object if the new array could |
| 3824 // not be allocated. | 3950 // not be allocated. |
| 3825 | 3951 |
| 3826 // Compute the size of the map transition entries to be removed. | 3952 // Compute the size of the map transition entries to be removed. |
| 3827 int num_removed = 0; | 3953 int num_removed = 0; |
| 3828 for (int i = 0; i < number_of_descriptors(); i++) { | 3954 for (int i = 0; i < number_of_descriptors(); i++) { |
| 3829 if (!IsProperty(i)) num_removed++; | 3955 if (!IsProperty(i)) num_removed++; |
| 3830 } | 3956 } |
| 3831 | 3957 |
| 3958 Object* result; |
| 3959 { TryAllocation t = Allocate(number_of_descriptors() - num_removed); |
| 3960 if (!t->ToObject(&result)) return t; |
| 3961 } |
| 3832 // Allocate the new descriptor array. | 3962 // Allocate the new descriptor array. |
| 3833 Object* result = Allocate(number_of_descriptors() - num_removed); | |
| 3834 if (result->IsFailure()) return result; | |
| 3835 DescriptorArray* new_descriptors = DescriptorArray::cast(result); | 3963 DescriptorArray* new_descriptors = DescriptorArray::cast(result); |
| 3836 | 3964 |
| 3837 // Copy the content. | 3965 // Copy the content. |
| 3838 int next_descriptor = 0; | 3966 int next_descriptor = 0; |
| 3839 for (int i = 0; i < number_of_descriptors(); i++) { | 3967 for (int i = 0; i < number_of_descriptors(); i++) { |
| 3840 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i); | 3968 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i); |
| 3841 } | 3969 } |
| 3842 ASSERT(next_descriptor == new_descriptors->number_of_descriptors()); | 3970 ASSERT(next_descriptor == new_descriptors->number_of_descriptors()); |
| 3843 | 3971 |
| 3844 return new_descriptors; | 3972 return new_descriptors; |
| (...skipping 1331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5176 ASSERT(should_have_prototype()); | 5304 ASSERT(should_have_prototype()); |
| 5177 Object* construct_prototype = value; | 5305 Object* construct_prototype = value; |
| 5178 | 5306 |
| 5179 // If the value is not a JSObject, store the value in the map's | 5307 // If the value is not a JSObject, store the value in the map's |
| 5180 // constructor field so it can be accessed. Also, set the prototype | 5308 // constructor field so it can be accessed. Also, set the prototype |
| 5181 // used for constructing objects to the original object prototype. | 5309 // used for constructing objects to the original object prototype. |
| 5182 // See ECMA-262 13.2.2. | 5310 // See ECMA-262 13.2.2. |
| 5183 if (!value->IsJSObject()) { | 5311 if (!value->IsJSObject()) { |
| 5184 // Copy the map so this does not affect unrelated functions. | 5312 // Copy the map so this does not affect unrelated functions. |
| 5185 // Remove map transitions because they point to maps with a | 5313 // Remove map transitions because they point to maps with a |
| 5314 Object* new_map; |
| 5315 { TryAllocation t = map()->CopyDropTransitions(); |
| 5316 if (!t->ToObject(&new_map)) return t; |
| 5317 } |
| 5186 // different prototype. | 5318 // different prototype. |
| 5187 Object* new_map = map()->CopyDropTransitions(); | |
| 5188 if (new_map->IsFailure()) return new_map; | |
| 5189 set_map(Map::cast(new_map)); | 5319 set_map(Map::cast(new_map)); |
| 5190 map()->set_constructor(value); | 5320 map()->set_constructor(value); |
| 5191 map()->set_non_instance_prototype(true); | 5321 map()->set_non_instance_prototype(true); |
| 5192 construct_prototype = | 5322 construct_prototype = |
| 5193 Top::context()->global_context()->initial_object_prototype(); | 5323 Top::context()->global_context()->initial_object_prototype(); |
| 5194 } else { | 5324 } else { |
| 5195 map()->set_non_instance_prototype(false); | 5325 map()->set_non_instance_prototype(false); |
| 5196 } | 5326 } |
| 5197 | 5327 |
| 5198 return SetInstancePrototype(construct_prototype); | 5328 return SetInstancePrototype(construct_prototype); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 5211 shared()->set_instance_class_name(name); | 5341 shared()->set_instance_class_name(name); |
| 5212 return this; | 5342 return this; |
| 5213 } | 5343 } |
| 5214 | 5344 |
| 5215 | 5345 |
| 5216 Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) { | 5346 Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) { |
| 5217 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex)); | 5347 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex)); |
| 5218 } | 5348 } |
| 5219 | 5349 |
| 5220 | 5350 |
| 5351 Object* symbol; |
| 5352 { TryAllocation t = Heap::LookupAsciiSymbol(to_string); |
| 5353 if (!t->ToObject(&symbol)) return t; |
| 5354 } |
| 5221 Object* Oddball::Initialize(const char* to_string, Object* to_number) { | 5355 Object* Oddball::Initialize(const char* to_string, Object* to_number) { |
| 5222 Object* symbol = Heap::LookupAsciiSymbol(to_string); | |
| 5223 if (symbol->IsFailure()) return symbol; | |
| 5224 set_to_string(String::cast(symbol)); | 5356 set_to_string(String::cast(symbol)); |
| 5225 set_to_number(to_number); | 5357 set_to_number(to_number); |
| 5226 return this; | 5358 return this; |
| 5227 } | 5359 } |
| 5228 | 5360 |
| 5229 | 5361 |
| 5230 bool SharedFunctionInfo::HasSourceCode() { | 5362 bool SharedFunctionInfo::HasSourceCode() { |
| 5231 return !script()->IsUndefined() && | 5363 return !script()->IsUndefined() && |
| 5232 !reinterpret_cast<Script*>(script())->source()->IsUndefined(); | 5364 !reinterpret_cast<Script*>(script())->source()->IsUndefined(); |
| 5233 } | 5365 } |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5698 for (RelocIterator it(this); !it.done(); it.next()) | 5830 for (RelocIterator it(this); !it.done(); it.next()) |
| 5699 it.rinfo()->Print(); | 5831 it.rinfo()->Print(); |
| 5700 PrintF("\n"); | 5832 PrintF("\n"); |
| 5701 } | 5833 } |
| 5702 #endif // ENABLE_DISASSEMBLER | 5834 #endif // ENABLE_DISASSEMBLER |
| 5703 | 5835 |
| 5704 | 5836 |
| 5705 Object* JSObject::SetFastElementsCapacityAndLength(int capacity, int length) { | 5837 Object* JSObject::SetFastElementsCapacityAndLength(int capacity, int length) { |
| 5706 // We should never end in here with a pixel or external array. | 5838 // We should never end in here with a pixel or external array. |
| 5707 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); | 5839 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); |
| 5840 Object* obj; |
| 5841 { TryAllocation t = Heap::AllocateFixedArrayWithHoles(capacity); |
| 5842 if (!t->ToObject(&obj)) return t; |
| 5843 } |
| 5708 | 5844 |
| 5709 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); | |
| 5710 if (obj->IsFailure()) return obj; | |
| 5711 FixedArray* elems = FixedArray::cast(obj); | 5845 FixedArray* elems = FixedArray::cast(obj); |
| 5846 { TryAllocation t = map()->GetFastElementsMap(); |
| 5847 if (!t->ToObject(&obj)) return t; |
| 5848 } |
| 5712 | 5849 |
| 5713 obj = map()->GetFastElementsMap(); | |
| 5714 if (obj->IsFailure()) return obj; | |
| 5715 Map* new_map = Map::cast(obj); | 5850 Map* new_map = Map::cast(obj); |
| 5716 | 5851 |
| 5717 AssertNoAllocation no_gc; | 5852 AssertNoAllocation no_gc; |
| 5718 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); | 5853 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); |
| 5719 switch (GetElementsKind()) { | 5854 switch (GetElementsKind()) { |
| 5720 case FAST_ELEMENTS: { | 5855 case FAST_ELEMENTS: { |
| 5721 FixedArray* old_elements = FixedArray::cast(elements()); | 5856 FixedArray* old_elements = FixedArray::cast(elements()); |
| 5722 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); | 5857 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); |
| 5723 // Fill out the new array with this content and array holes. | 5858 // Fill out the new array with this content and array holes. |
| 5724 for (uint32_t i = 0; i < old_length; i++) { | 5859 for (uint32_t i = 0; i < old_length; i++) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5756 Object* JSObject::SetSlowElements(Object* len) { | 5891 Object* JSObject::SetSlowElements(Object* len) { |
| 5757 // We should never end in here with a pixel or external array. | 5892 // We should never end in here with a pixel or external array. |
| 5758 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); | 5893 ASSERT(!HasPixelElements() && !HasExternalArrayElements()); |
| 5759 | 5894 |
| 5760 uint32_t new_length = static_cast<uint32_t>(len->Number()); | 5895 uint32_t new_length = static_cast<uint32_t>(len->Number()); |
| 5761 | 5896 |
| 5762 switch (GetElementsKind()) { | 5897 switch (GetElementsKind()) { |
| 5763 case FAST_ELEMENTS: { | 5898 case FAST_ELEMENTS: { |
| 5764 // Make sure we never try to shrink dense arrays into sparse arrays. | 5899 // Make sure we never try to shrink dense arrays into sparse arrays. |
| 5765 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= | 5900 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= |
| 5901 Object* obj; |
| 5902 { TryAllocation t = NormalizeElements(); |
| 5903 if (!t->ToObject(&obj)) return t; |
| 5904 } |
| 5766 new_length); | 5905 new_length); |
| 5767 Object* obj = NormalizeElements(); | |
| 5768 if (obj->IsFailure()) return obj; | |
| 5769 | 5906 |
| 5770 // Update length for JSArrays. | 5907 // Update length for JSArrays. |
| 5771 if (IsJSArray()) JSArray::cast(this)->set_length(len); | 5908 if (IsJSArray()) JSArray::cast(this)->set_length(len); |
| 5772 break; | 5909 break; |
| 5773 } | 5910 } |
| 5774 case DICTIONARY_ELEMENTS: { | 5911 case DICTIONARY_ELEMENTS: { |
| 5775 if (IsJSArray()) { | 5912 if (IsJSArray()) { |
| 5776 uint32_t old_length = | 5913 uint32_t old_length = |
| 5777 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); | 5914 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); |
| 5778 element_dictionary()->RemoveNumberEntries(new_length, old_length), | 5915 element_dictionary()->RemoveNumberEntries(new_length, old_length), |
| 5779 JSArray::cast(this)->set_length(len); | 5916 JSArray::cast(this)->set_length(len); |
| 5780 } | 5917 } |
| 5781 break; | 5918 break; |
| 5782 } | 5919 } |
| 5783 default: | 5920 default: |
| 5784 UNREACHABLE(); | 5921 UNREACHABLE(); |
| 5785 break; | 5922 break; |
| 5786 } | 5923 } |
| 5787 return this; | 5924 return this; |
| 5788 } | 5925 } |
| 5789 | 5926 |
| 5790 | 5927 |
| 5791 Object* JSArray::Initialize(int capacity) { | 5928 Object* JSArray::Initialize(int capacity) { |
| 5792 ASSERT(capacity >= 0); | 5929 ASSERT(capacity >= 0); |
| 5793 set_length(Smi::FromInt(0)); | 5930 set_length(Smi::FromInt(0)); |
| 5794 FixedArray* new_elements; | 5931 FixedArray* new_elements; |
| 5795 if (capacity == 0) { | 5932 if (capacity == 0) { |
| 5796 new_elements = Heap::empty_fixed_array(); | 5933 new_elements = Heap::empty_fixed_array(); |
| 5934 Object* obj; |
| 5935 { TryAllocation t = Heap::AllocateFixedArrayWithHoles(capacity); |
| 5936 if (!t->ToObject(&obj)) return t; |
| 5937 } |
| 5797 } else { | 5938 } else { |
| 5798 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity); | |
| 5799 if (obj->IsFailure()) return obj; | |
| 5800 new_elements = FixedArray::cast(obj); | 5939 new_elements = FixedArray::cast(obj); |
| 5801 } | 5940 } |
| 5802 set_elements(new_elements); | 5941 set_elements(new_elements); |
| 5803 return this; | 5942 return this; |
| 5804 } | 5943 } |
| 5805 | 5944 |
| 5806 | 5945 |
| 5807 void JSArray::Expand(int required_size) { | 5946 void JSArray::Expand(int required_size) { |
| 5808 Handle<JSArray> self(this); | 5947 Handle<JSArray> self(this); |
| 5809 Handle<FixedArray> old_backing(FixedArray::cast(elements())); | 5948 Handle<FixedArray> old_backing(FixedArray::cast(elements())); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 5835 ASSERT(AllowsSetElementsLength()); | 5974 ASSERT(AllowsSetElementsLength()); |
| 5836 | 5975 |
| 5837 Object* smi_length = len->ToSmi(); | 5976 Object* smi_length = len->ToSmi(); |
| 5838 if (smi_length->IsSmi()) { | 5977 if (smi_length->IsSmi()) { |
| 5839 const int value = Smi::cast(smi_length)->value(); | 5978 const int value = Smi::cast(smi_length)->value(); |
| 5840 if (value < 0) return ArrayLengthRangeError(); | 5979 if (value < 0) return ArrayLengthRangeError(); |
| 5841 switch (GetElementsKind()) { | 5980 switch (GetElementsKind()) { |
| 5842 case FAST_ELEMENTS: { | 5981 case FAST_ELEMENTS: { |
| 5843 int old_capacity = FixedArray::cast(elements())->length(); | 5982 int old_capacity = FixedArray::cast(elements())->length(); |
| 5844 if (value <= old_capacity) { | 5983 if (value <= old_capacity) { |
| 5984 Object* obj; |
| 5985 { TryAllocation t = EnsureWritableFastElements(); |
| 5986 if (!t->ToObject(&obj)) return t; |
| 5987 } |
| 5845 if (IsJSArray()) { | 5988 if (IsJSArray()) { |
| 5846 Object* obj = EnsureWritableFastElements(); | |
| 5847 if (obj->IsFailure()) return obj; | |
| 5848 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); | 5989 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); |
| 5849 // NOTE: We may be able to optimize this by removing the | 5990 // NOTE: We may be able to optimize this by removing the |
| 5850 // last part of the elements backing storage array and | 5991 // last part of the elements backing storage array and |
| 5851 // setting the capacity to the new size. | 5992 // setting the capacity to the new size. |
| 5852 for (int i = value; i < old_length; i++) { | 5993 for (int i = value; i < old_length; i++) { |
| 5853 FixedArray::cast(elements())->set_the_hole(i); | 5994 FixedArray::cast(elements())->set_the_hole(i); |
| 5854 } | 5995 } |
| 5855 JSArray::cast(this)->set_length(Smi::cast(smi_length)); | 5996 JSArray::cast(this)->set_length(Smi::cast(smi_length)); |
| 5856 } | 5997 } |
| 5857 return this; | 5998 return this; |
| 5858 } | 5999 } |
| 5859 int min = NewElementsCapacity(old_capacity); | 6000 int min = NewElementsCapacity(old_capacity); |
| 5860 int new_capacity = value > min ? value : min; | 6001 int new_capacity = value > min ? value : min; |
| 5861 if (new_capacity <= kMaxFastElementsLength || | 6002 if (new_capacity <= kMaxFastElementsLength || |
| 6003 Object* obj; |
| 6004 { TryAllocation t = |
| 6005 SetFastElementsCapacityAndLength(new_capacity, value); |
| 6006 if (!t->ToObject(&obj)) return t; |
| 6007 } |
| 5862 !ShouldConvertToSlowElements(new_capacity)) { | 6008 !ShouldConvertToSlowElements(new_capacity)) { |
| 5863 Object* obj = SetFastElementsCapacityAndLength(new_capacity, value); | |
| 5864 if (obj->IsFailure()) return obj; | |
| 5865 return this; | 6009 return this; |
| 5866 } | 6010 } |
| 5867 break; | 6011 break; |
| 5868 } | 6012 } |
| 5869 case DICTIONARY_ELEMENTS: { | 6013 case DICTIONARY_ELEMENTS: { |
| 5870 if (IsJSArray()) { | 6014 if (IsJSArray()) { |
| 5871 if (value == 0) { | 6015 if (value == 0) { |
| 5872 // If the length of a slow array is reset to zero, we clear | 6016 // If the length of a slow array is reset to zero, we clear |
| 5873 // the array and flush backing storage. This has the added | 6017 // the array and flush backing storage. This has the added |
| 6018 Object* obj; |
| 6019 { TryAllocation t = ResetElements(); |
| 6020 if (!t->ToObject(&obj)) return t; |
| 6021 } |
| 5874 // benefit that the array returns to fast mode. | 6022 // benefit that the array returns to fast mode. |
| 5875 Object* obj = ResetElements(); | |
| 5876 if (obj->IsFailure()) return obj; | |
| 5877 } else { | 6023 } else { |
| 5878 // Remove deleted elements. | 6024 // Remove deleted elements. |
| 5879 uint32_t old_length = | 6025 uint32_t old_length = |
| 5880 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); | 6026 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); |
| 5881 element_dictionary()->RemoveNumberEntries(value, old_length); | 6027 element_dictionary()->RemoveNumberEntries(value, old_length); |
| 5882 } | 6028 } |
| 5883 JSArray::cast(this)->set_length(Smi::cast(smi_length)); | 6029 JSArray::cast(this)->set_length(Smi::cast(smi_length)); |
| 5884 } | 6030 } |
| 5885 return this; | 6031 return this; |
| 5886 } | 6032 } |
| 5887 default: | 6033 default: |
| 5888 UNREACHABLE(); | 6034 UNREACHABLE(); |
| 5889 break; | 6035 break; |
| 5890 } | 6036 } |
| 5891 } | 6037 } |
| 5892 | 6038 |
| 5893 // General slow case. | 6039 // General slow case. |
| 5894 if (len->IsNumber()) { | 6040 if (len->IsNumber()) { |
| 5895 uint32_t length; | 6041 uint32_t length; |
| 5896 if (len->ToArrayIndex(&length)) { | 6042 if (len->ToArrayIndex(&length)) { |
| 5897 return SetSlowElements(len); | 6043 return SetSlowElements(len); |
| 5898 } else { | 6044 } else { |
| 5899 return ArrayLengthRangeError(); | 6045 return ArrayLengthRangeError(); |
| 5900 } | 6046 } |
| 5901 } | 6047 } |
| 5902 | 6048 |
| 5903 // len is not a number so make the array size one and | 6049 // len is not a number so make the array size one and |
| 6050 Object* obj; |
| 6051 { TryAllocation t = Heap::AllocateFixedArray(1); |
| 6052 if (!t->ToObject(&obj)) return t; |
| 6053 } |
| 5904 // set only element to len. | 6054 // set only element to len. |
| 5905 Object* obj = Heap::AllocateFixedArray(1); | |
| 5906 if (obj->IsFailure()) return obj; | |
| 5907 FixedArray::cast(obj)->set(0, len); | 6055 FixedArray::cast(obj)->set(0, len); |
| 5908 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); | 6056 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); |
| 5909 set_elements(FixedArray::cast(obj)); | 6057 set_elements(FixedArray::cast(obj)); |
| 5910 return this; | 6058 return this; |
| 5911 } | 6059 } |
| 5912 | 6060 |
| 5913 | 6061 |
| 5914 Object* JSObject::SetPrototype(Object* value, | 6062 Object* JSObject::SetPrototype(Object* value, |
| 5915 bool skip_hidden_prototypes) { | 6063 bool skip_hidden_prototypes) { |
| 5916 // Silently ignore the change if value is not a JSObject or null. | 6064 // Silently ignore the change if value is not a JSObject or null. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 5936 // Find the first object in the chain whose prototype object is not | 6084 // Find the first object in the chain whose prototype object is not |
| 5937 // hidden and set the new prototype on that object. | 6085 // hidden and set the new prototype on that object. |
| 5938 Object* current_proto = real_receiver->GetPrototype(); | 6086 Object* current_proto = real_receiver->GetPrototype(); |
| 5939 while (current_proto->IsJSObject() && | 6087 while (current_proto->IsJSObject() && |
| 5940 JSObject::cast(current_proto)->map()->is_hidden_prototype()) { | 6088 JSObject::cast(current_proto)->map()->is_hidden_prototype()) { |
| 5941 real_receiver = JSObject::cast(current_proto); | 6089 real_receiver = JSObject::cast(current_proto); |
| 5942 current_proto = current_proto->GetPrototype(); | 6090 current_proto = current_proto->GetPrototype(); |
| 5943 } | 6091 } |
| 5944 } | 6092 } |
| 5945 | 6093 |
| 6094 Object* new_map; |
| 6095 { TryAllocation t = real_receiver->map()->CopyDropTransitions(); |
| 6096 if (!t->ToObject(&new_map)) return t; |
| 6097 } |
| 5946 // Set the new prototype of the object. | 6098 // Set the new prototype of the object. |
| 5947 Object* new_map = real_receiver->map()->CopyDropTransitions(); | |
| 5948 if (new_map->IsFailure()) return new_map; | |
| 5949 Map::cast(new_map)->set_prototype(value); | 6099 Map::cast(new_map)->set_prototype(value); |
| 5950 real_receiver->set_map(Map::cast(new_map)); | 6100 real_receiver->set_map(Map::cast(new_map)); |
| 5951 | 6101 |
| 5952 Heap::ClearInstanceofCache(); | 6102 Heap::ClearInstanceofCache(); |
| 5953 | 6103 |
| 5954 return value; | 6104 return value; |
| 5955 } | 6105 } |
| 5956 | 6106 |
| 5957 | 6107 |
| 5958 bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) { | 6108 bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) { |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6308 UNREACHABLE(); | 6458 UNREACHABLE(); |
| 6309 return NULL; | 6459 return NULL; |
| 6310 } | 6460 } |
| 6311 | 6461 |
| 6312 | 6462 |
| 6313 // Adding n elements in fast case is O(n*n). | 6463 // Adding n elements in fast case is O(n*n). |
| 6314 // Note: revisit design to have dual undefined values to capture absent | 6464 // Note: revisit design to have dual undefined values to capture absent |
| 6315 // elements. | 6465 // elements. |
| 6316 Object* JSObject::SetFastElement(uint32_t index, Object* value) { | 6466 Object* JSObject::SetFastElement(uint32_t index, Object* value) { |
| 6317 ASSERT(HasFastElements()); | 6467 ASSERT(HasFastElements()); |
| 6468 Object* elms_obj; |
| 6469 { TryAllocation t = EnsureWritableFastElements(); |
| 6470 if (!t->ToObject(&elms_obj)) return t; |
| 6471 } |
| 6318 | 6472 |
| 6319 Object* elms_obj = EnsureWritableFastElements(); | |
| 6320 if (elms_obj->IsFailure()) return elms_obj; | |
| 6321 FixedArray* elms = FixedArray::cast(elms_obj); | 6473 FixedArray* elms = FixedArray::cast(elms_obj); |
| 6322 uint32_t elms_length = static_cast<uint32_t>(elms->length()); | 6474 uint32_t elms_length = static_cast<uint32_t>(elms->length()); |
| 6323 | 6475 |
| 6324 if (!IsJSArray() && (index >= elms_length || elms->get(index)->IsTheHole())) { | 6476 if (!IsJSArray() && (index >= elms_length || elms->get(index)->IsTheHole())) { |
| 6325 if (SetElementWithCallbackSetterInPrototypes(index, value)) { | 6477 if (SetElementWithCallbackSetterInPrototypes(index, value)) { |
| 6326 return value; | 6478 return value; |
| 6327 } | 6479 } |
| 6328 } | 6480 } |
| 6329 | 6481 |
| 6330 // Check whether there is extra space in fixed array.. | 6482 // Check whether there is extra space in fixed array.. |
| 6331 if (index < elms_length) { | 6483 if (index < elms_length) { |
| 6332 elms->set(index, value); | 6484 elms->set(index, value); |
| 6333 if (IsJSArray()) { | 6485 if (IsJSArray()) { |
| 6334 // Update the length of the array if needed. | 6486 // Update the length of the array if needed. |
| 6335 uint32_t array_length = 0; | 6487 uint32_t array_length = 0; |
| 6336 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); | 6488 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); |
| 6337 if (index >= array_length) { | 6489 if (index >= array_length) { |
| 6338 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); | 6490 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); |
| 6339 } | 6491 } |
| 6340 } | 6492 } |
| 6341 return value; | 6493 return value; |
| 6342 } | 6494 } |
| 6343 | 6495 |
| 6344 // Allow gap in fast case. | 6496 // Allow gap in fast case. |
| 6345 if ((index - elms_length) < kMaxGap) { | 6497 if ((index - elms_length) < kMaxGap) { |
| 6346 // Try allocating extra space. | 6498 // Try allocating extra space. |
| 6347 int new_capacity = NewElementsCapacity(index+1); | 6499 int new_capacity = NewElementsCapacity(index+1); |
| 6348 if (new_capacity <= kMaxFastElementsLength || | 6500 if (new_capacity <= kMaxFastElementsLength || |
| 6349 !ShouldConvertToSlowElements(new_capacity)) { | 6501 !ShouldConvertToSlowElements(new_capacity)) { |
| 6502 Object* obj; |
| 6503 { TryAllocation t = |
| 6504 SetFastElementsCapacityAndLength(new_capacity, index + 1); |
| 6505 if (!t->ToObject(&obj)) return t; |
| 6506 } |
| 6350 ASSERT(static_cast<uint32_t>(new_capacity) > index); | 6507 ASSERT(static_cast<uint32_t>(new_capacity) > index); |
| 6351 Object* obj = SetFastElementsCapacityAndLength(new_capacity, index + 1); | |
| 6352 if (obj->IsFailure()) return obj; | |
| 6353 FixedArray::cast(elements())->set(index, value); | 6508 FixedArray::cast(elements())->set(index, value); |
| 6354 return value; | 6509 return value; |
| 6355 } | 6510 } |
| 6356 } | 6511 } |
| 6357 | 6512 |
| 6513 Object* obj; |
| 6514 { TryAllocation t = NormalizeElements(); |
| 6515 if (!t->ToObject(&obj)) return t; |
| 6516 } |
| 6358 // Otherwise default to slow case. | 6517 // Otherwise default to slow case. |
| 6359 Object* obj = NormalizeElements(); | |
| 6360 if (obj->IsFailure()) return obj; | |
| 6361 ASSERT(HasDictionaryElements()); | 6518 ASSERT(HasDictionaryElements()); |
| 6362 return SetElement(index, value); | 6519 return SetElement(index, value); |
| 6363 } | 6520 } |
| 6364 | 6521 |
| 6365 | 6522 |
| 6366 Object* JSObject::SetElement(uint32_t index, Object* value) { | 6523 Object* JSObject::SetElement(uint32_t index, Object* value) { |
| 6367 // Check access rights if needed. | 6524 // Check access rights if needed. |
| 6368 if (IsAccessCheckNeeded() && | 6525 if (IsAccessCheckNeeded() && |
| 6369 !Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) { | 6526 !Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) { |
| 6370 HandleScope scope; | 6527 HandleScope scope; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6452 } | 6609 } |
| 6453 } | 6610 } |
| 6454 // When we set the is_extensible flag to false we always force | 6611 // When we set the is_extensible flag to false we always force |
| 6455 // the element into dictionary mode (and force them to stay there). | 6612 // the element into dictionary mode (and force them to stay there). |
| 6456 if (!map()->is_extensible()) { | 6613 if (!map()->is_extensible()) { |
| 6457 Handle<Object> number(Heap::NumberFromUint32(index)); | 6614 Handle<Object> number(Heap::NumberFromUint32(index)); |
| 6458 Handle<String> index_string(Factory::NumberToString(number)); | 6615 Handle<String> index_string(Factory::NumberToString(number)); |
| 6459 Handle<Object> args[1] = { index_string }; | 6616 Handle<Object> args[1] = { index_string }; |
| 6460 return Top::Throw(*Factory::NewTypeError("object_not_extensible", | 6617 return Top::Throw(*Factory::NewTypeError("object_not_extensible", |
| 6461 HandleVector(args, 1))); | 6618 HandleVector(args, 1))); |
| 6619 Object* result; |
| 6620 { TryAllocation t = dictionary->AtNumberPut(index, value); |
| 6621 if (!t->ToObject(&result)) return t; |
| 6462 } | 6622 } |
| 6463 Object* result = dictionary->AtNumberPut(index, value); | 6623 } |
| 6464 if (result->IsFailure()) return result; | |
| 6465 if (elms != FixedArray::cast(result)) { | 6624 if (elms != FixedArray::cast(result)) { |
| 6466 set_elements(FixedArray::cast(result)); | 6625 set_elements(FixedArray::cast(result)); |
| 6467 } | 6626 } |
| 6468 } | 6627 } |
| 6469 | 6628 |
| 6470 // Update the array length if this JSObject is an array. | 6629 // Update the array length if this JSObject is an array. |
| 6471 if (IsJSArray()) { | 6630 if (IsJSArray()) { |
| 6472 JSArray* array = JSArray::cast(this); | 6631 JSArray* array = JSArray::cast(this); |
| 6473 Object* return_value = array->JSArrayUpdateLengthFromIndex(index, | 6632 Object* return_value; |
| 6474 value); | 6633 { TryAllocation t = array->JSArrayUpdateLengthFromIndex(index, |
| 6475 if (return_value->IsFailure()) return return_value; | 6634 value); |
| 6635 if (!t->ToObject(&return_value)) return t; |
| 6636 } |
| 6476 } | 6637 } |
| 6477 | 6638 |
| 6478 // Attempt to put this object back in fast case. | 6639 // Attempt to put this object back in fast case. |
| 6479 if (ShouldConvertToFastElements()) { | 6640 if (ShouldConvertToFastElements()) { |
| 6480 uint32_t new_length = 0; | 6641 uint32_t new_length = 0; |
| 6481 if (IsJSArray()) { | 6642 if (IsJSArray()) { |
| 6482 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); | 6643 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); |
| 6483 } else { | 6644 } else { |
| 6484 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; | 6645 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; |
| 6646 Object* obj; |
| 6647 { TryAllocation t = |
| 6648 SetFastElementsCapacityAndLength(new_length, new_length); |
| 6649 if (!t->ToObject(&obj)) return t; |
| 6485 } | 6650 } |
| 6486 Object* obj = SetFastElementsCapacityAndLength(new_length, new_length); | 6651 } |
| 6487 if (obj->IsFailure()) return obj; | |
| 6488 #ifdef DEBUG | 6652 #ifdef DEBUG |
| 6489 if (FLAG_trace_normalization) { | 6653 if (FLAG_trace_normalization) { |
| 6490 PrintF("Object elements are fast case again:\n"); | 6654 PrintF("Object elements are fast case again:\n"); |
| 6491 Print(); | 6655 Print(); |
| 6492 } | 6656 } |
| 6493 #endif | 6657 #endif |
| 6494 } | 6658 } |
| 6495 | 6659 |
| 6496 return value; | 6660 return value; |
| 6497 } | 6661 } |
| 6498 default: | 6662 default: |
| 6499 UNREACHABLE(); | 6663 UNREACHABLE(); |
| 6500 break; | 6664 break; |
| 6501 } | 6665 } |
| 6502 // All possible cases have been handled above. Add a return to avoid the | 6666 // All possible cases have been handled above. Add a return to avoid the |
| 6503 // complaints from the compiler. | 6667 // complaints from the compiler. |
| 6504 UNREACHABLE(); | 6668 UNREACHABLE(); |
| 6505 return Heap::null_value(); | 6669 return Heap::null_value(); |
| 6506 } | 6670 } |
| 6507 | 6671 |
| 6508 | 6672 |
| 6509 Object* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, Object* value) { | 6673 Object* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, Object* value) { |
| 6510 uint32_t old_len = 0; | 6674 uint32_t old_len = 0; |
| 6511 CHECK(length()->ToArrayIndex(&old_len)); | 6675 CHECK(length()->ToArrayIndex(&old_len)); |
| 6512 // Check to see if we need to update the length. For now, we make | 6676 // Check to see if we need to update the length. For now, we make |
| 6513 // sure that the length stays within 32-bits (unsigned). | 6677 // sure that the length stays within 32-bits (unsigned). |
| 6514 if (index >= old_len && index != 0xffffffff) { | 6678 if (index >= old_len && index != 0xffffffff) { |
| 6515 Object* len = | 6679 Object* len; |
| 6516 Heap::NumberFromDouble(static_cast<double>(index) + 1); | 6680 { TryAllocation t = |
| 6517 if (len->IsFailure()) return len; | 6681 Heap::NumberFromDouble(static_cast<double>(index) + 1); |
| 6682 if (!t->ToObject(&len)) return t; |
| 6683 } |
| 6518 set_length(len); | 6684 set_length(len); |
| 6519 } | 6685 } |
| 6520 return value; | 6686 return value; |
| 6521 } | 6687 } |
| 6522 | 6688 |
| 6523 | 6689 |
| 6524 Object* JSObject::GetElementPostInterceptor(JSObject* receiver, | 6690 Object* JSObject::GetElementPostInterceptor(JSObject* receiver, |
| 6525 uint32_t index) { | 6691 uint32_t index) { |
| 6526 // Get element works for both JSObject and JSArray since | 6692 // Get element works for both JSObject and JSArray since |
| 6527 // JSArray::length cannot change. | 6693 // JSArray::length cannot change. |
| (...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7367 return StringSharedHashHelper(source_, shared_); | 7533 return StringSharedHashHelper(source_, shared_); |
| 7368 } | 7534 } |
| 7369 | 7535 |
| 7370 uint32_t HashForObject(Object* obj) { | 7536 uint32_t HashForObject(Object* obj) { |
| 7371 FixedArray* pair = FixedArray::cast(obj); | 7537 FixedArray* pair = FixedArray::cast(obj); |
| 7372 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0)); | 7538 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0)); |
| 7373 String* source = String::cast(pair->get(1)); | 7539 String* source = String::cast(pair->get(1)); |
| 7374 return StringSharedHashHelper(source, shared); | 7540 return StringSharedHashHelper(source, shared); |
| 7375 } | 7541 } |
| 7376 | 7542 |
| 7543 Object* obj; |
| 7544 { TryAllocation t = Heap::AllocateFixedArray(2); |
| 7545 if (!t->ToObject(&obj)) return t; |
| 7546 } |
| 7377 Object* AsObject() { | 7547 Object* AsObject() { |
| 7378 Object* obj = Heap::AllocateFixedArray(2); | |
| 7379 if (obj->IsFailure()) return obj; | |
| 7380 FixedArray* pair = FixedArray::cast(obj); | 7548 FixedArray* pair = FixedArray::cast(obj); |
| 7381 pair->set(0, shared_); | 7549 pair->set(0, shared_); |
| 7382 pair->set(1, source_); | 7550 pair->set(1, source_); |
| 7383 return pair; | 7551 return pair; |
| 7384 } | 7552 } |
| 7385 | 7553 |
| 7386 private: | 7554 private: |
| 7387 String* source_; | 7555 String* source_; |
| 7388 SharedFunctionInfo* shared_; | 7556 SharedFunctionInfo* shared_; |
| 7389 }; | 7557 }; |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7606 // Return if: | 7774 // Return if: |
| 7607 // 50% is still free after adding n elements and | 7775 // 50% is still free after adding n elements and |
| 7608 // at most 50% of the free elements are deleted elements. | 7776 // at most 50% of the free elements are deleted elements. |
| 7609 if (nod <= (capacity - nof) >> 1) { | 7777 if (nod <= (capacity - nof) >> 1) { |
| 7610 int needed_free = nof >> 1; | 7778 int needed_free = nof >> 1; |
| 7611 if (nof + needed_free <= capacity) return this; | 7779 if (nof + needed_free <= capacity) return this; |
| 7612 } | 7780 } |
| 7613 | 7781 |
| 7614 const int kMinCapacityForPretenure = 256; | 7782 const int kMinCapacityForPretenure = 256; |
| 7615 bool pretenure = | 7783 bool pretenure = |
| 7784 Object* obj; |
| 7785 { TryAllocation t = Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED); |
| 7786 if (!t->ToObject(&obj)) return t; |
| 7787 } |
| 7616 (capacity > kMinCapacityForPretenure) && !Heap::InNewSpace(this); | 7788 (capacity > kMinCapacityForPretenure) && !Heap::InNewSpace(this); |
| 7617 Object* obj = Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED); | |
| 7618 if (obj->IsFailure()) return obj; | |
| 7619 | 7789 |
| 7620 AssertNoAllocation no_gc; | 7790 AssertNoAllocation no_gc; |
| 7621 HashTable* table = HashTable::cast(obj); | 7791 HashTable* table = HashTable::cast(obj); |
| 7622 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc); | 7792 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc); |
| 7623 | 7793 |
| 7624 // Copy prefix to new array. | 7794 // Copy prefix to new array. |
| 7625 for (int i = kPrefixStartIndex; | 7795 for (int i = kPrefixStartIndex; |
| 7626 i < kPrefixStartIndex + Shape::kPrefixSize; | 7796 i < kPrefixStartIndex + Shape::kPrefixSize; |
| 7627 i++) { | 7797 i++) { |
| 7628 table->set(i, get(i), mode); | 7798 table->set(i, get(i), mode); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7742 // Collates undefined and unexisting elements below limit from position | 7912 // Collates undefined and unexisting elements below limit from position |
| 7743 // zero of the elements. The object stays in Dictionary mode. | 7913 // zero of the elements. The object stays in Dictionary mode. |
| 7744 Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) { | 7914 Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) { |
| 7745 ASSERT(HasDictionaryElements()); | 7915 ASSERT(HasDictionaryElements()); |
| 7746 // Must stay in dictionary mode, either because of requires_slow_elements, | 7916 // Must stay in dictionary mode, either because of requires_slow_elements, |
| 7747 // or because we are not going to sort (and therefore compact) all of the | 7917 // or because we are not going to sort (and therefore compact) all of the |
| 7748 // elements. | 7918 // elements. |
| 7749 NumberDictionary* dict = element_dictionary(); | 7919 NumberDictionary* dict = element_dictionary(); |
| 7750 HeapNumber* result_double = NULL; | 7920 HeapNumber* result_double = NULL; |
| 7751 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { | 7921 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { |
| 7922 Object* new_double; |
| 7923 { TryAllocation t = Heap::AllocateHeapNumber(0.0); |
| 7924 if (!t->ToObject(&new_double)) return t; |
| 7925 } |
| 7752 // Allocate space for result before we start mutating the object. | 7926 // Allocate space for result before we start mutating the object. |
| 7753 Object* new_double = Heap::AllocateHeapNumber(0.0); | |
| 7754 if (new_double->IsFailure()) return new_double; | |
| 7755 result_double = HeapNumber::cast(new_double); | 7927 result_double = HeapNumber::cast(new_double); |
| 7756 } | 7928 } |
| 7929 Object* obj; |
| 7930 { TryAllocation t = NumberDictionary::Allocate(dict->NumberOfElements()); |
| 7931 if (!t->ToObject(&obj)) return t; |
| 7932 } |
| 7757 | 7933 |
| 7758 Object* obj = NumberDictionary::Allocate(dict->NumberOfElements()); | |
| 7759 if (obj->IsFailure()) return obj; | |
| 7760 NumberDictionary* new_dict = NumberDictionary::cast(obj); | 7934 NumberDictionary* new_dict = NumberDictionary::cast(obj); |
| 7761 | 7935 |
| 7762 AssertNoAllocation no_alloc; | 7936 AssertNoAllocation no_alloc; |
| 7763 | 7937 |
| 7764 uint32_t pos = 0; | 7938 uint32_t pos = 0; |
| 7765 uint32_t undefs = 0; | 7939 uint32_t undefs = 0; |
| 7766 int capacity = dict->Capacity(); | 7940 int capacity = dict->Capacity(); |
| 7767 for (int i = 0; i < capacity; i++) { | 7941 for (int i = 0; i < capacity; i++) { |
| 7768 Object* k = dict->KeyAt(i); | 7942 Object* k = dict->KeyAt(i); |
| 7769 if (dict->IsKey(k)) { | 7943 if (dict->IsKey(k)) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7820 | 7994 |
| 7821 if (HasDictionaryElements()) { | 7995 if (HasDictionaryElements()) { |
| 7822 // Convert to fast elements containing only the existing properties. | 7996 // Convert to fast elements containing only the existing properties. |
| 7823 // Ordering is irrelevant, since we are going to sort anyway. | 7997 // Ordering is irrelevant, since we are going to sort anyway. |
| 7824 NumberDictionary* dict = element_dictionary(); | 7998 NumberDictionary* dict = element_dictionary(); |
| 7825 if (IsJSArray() || dict->requires_slow_elements() || | 7999 if (IsJSArray() || dict->requires_slow_elements() || |
| 7826 dict->max_number_key() >= limit) { | 8000 dict->max_number_key() >= limit) { |
| 7827 return PrepareSlowElementsForSort(limit); | 8001 return PrepareSlowElementsForSort(limit); |
| 7828 } | 8002 } |
| 7829 // Convert to fast elements. | 8003 // Convert to fast elements. |
| 8004 Object* obj; |
| 8005 { TryAllocation t = map()->GetFastElementsMap(); |
| 8006 if (!t->ToObject(&obj)) return t; |
| 8007 } |
| 7830 | 8008 |
| 7831 Object* obj = map()->GetFastElementsMap(); | |
| 7832 if (obj->IsFailure()) return obj; | |
| 7833 Map* new_map = Map::cast(obj); | 8009 Map* new_map = Map::cast(obj); |
| 7834 | 8010 |
| 7835 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED; | 8011 PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED; |
| 7836 Object* new_array = | 8012 Object* new_array; |
| 7837 Heap::AllocateFixedArray(dict->NumberOfElements(), tenure); | 8013 { TryAllocation t = |
| 7838 if (new_array->IsFailure()) return new_array; | 8014 Heap::AllocateFixedArray(dict->NumberOfElements(), tenure); |
| 8015 if (!t->ToObject(&new_array)) return t; |
| 8016 } |
| 7839 FixedArray* fast_elements = FixedArray::cast(new_array); | 8017 FixedArray* fast_elements = FixedArray::cast(new_array); |
| 7840 dict->CopyValuesTo(fast_elements); | 8018 dict->CopyValuesTo(fast_elements); |
| 7841 | 8019 |
| 7842 set_map(new_map); | 8020 set_map(new_map); |
| 7843 set_elements(fast_elements); | 8021 set_elements(fast_elements); |
| 8022 Object* obj; |
| 8023 { TryAllocation t = EnsureWritableFastElements(); |
| 8024 if (!t->ToObject(&obj)) return t; |
| 8025 } |
| 7844 } else { | 8026 } else { |
| 7845 Object* obj = EnsureWritableFastElements(); | |
| 7846 if (obj->IsFailure()) return obj; | |
| 7847 } | 8027 } |
| 7848 ASSERT(HasFastElements()); | 8028 ASSERT(HasFastElements()); |
| 7849 | 8029 |
| 7850 // Collect holes at the end, undefined before that and the rest at the | 8030 // Collect holes at the end, undefined before that and the rest at the |
| 7851 // start, and return the number of non-hole, non-undefined values. | 8031 // start, and return the number of non-hole, non-undefined values. |
| 7852 | 8032 |
| 7853 FixedArray* elements = FixedArray::cast(this->elements()); | 8033 FixedArray* elements = FixedArray::cast(this->elements()); |
| 7854 uint32_t elements_length = static_cast<uint32_t>(elements->length()); | 8034 uint32_t elements_length = static_cast<uint32_t>(elements->length()); |
| 7855 if (limit > elements_length) { | 8035 if (limit > elements_length) { |
| 7856 limit = elements_length ; | 8036 limit = elements_length ; |
| 7857 } | 8037 } |
| 7858 if (limit == 0) { | 8038 if (limit == 0) { |
| 7859 return Smi::FromInt(0); | 8039 return Smi::FromInt(0); |
| 7860 } | 8040 } |
| 7861 | 8041 |
| 7862 HeapNumber* result_double = NULL; | 8042 HeapNumber* result_double = NULL; |
| 7863 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { | 8043 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { |
| 7864 // Pessimistically allocate space for return value before | 8044 // Pessimistically allocate space for return value before |
| 8045 Object* new_double; |
| 8046 { TryAllocation t = Heap::AllocateHeapNumber(0.0); |
| 8047 if (!t->ToObject(&new_double)) return t; |
| 8048 } |
| 7865 // we start mutating the array. | 8049 // we start mutating the array. |
| 7866 Object* new_double = Heap::AllocateHeapNumber(0.0); | |
| 7867 if (new_double->IsFailure()) return new_double; | |
| 7868 result_double = HeapNumber::cast(new_double); | 8050 result_double = HeapNumber::cast(new_double); |
| 7869 } | 8051 } |
| 7870 | 8052 |
| 7871 AssertNoAllocation no_alloc; | 8053 AssertNoAllocation no_alloc; |
| 7872 | 8054 |
| 7873 // Split elements into defined, undefined and the_hole, in that order. | 8055 // Split elements into defined, undefined and the_hole, in that order. |
| 7874 // Only count locations for undefined and the hole, and fill them afterwards. | 8056 // Only count locations for undefined and the hole, and fill them afterwards. |
| 7875 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc); | 8057 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc); |
| 7876 unsigned int undefs = limit; | 8058 unsigned int undefs = limit; |
| 7877 unsigned int holes = limit; | 8059 unsigned int holes = limit; |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8052 ASSERT(!HasFastProperties()); | 8234 ASSERT(!HasFastProperties()); |
| 8053 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); | 8235 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); |
| 8054 ASSERT(value->IsJSGlobalPropertyCell()); | 8236 ASSERT(value->IsJSGlobalPropertyCell()); |
| 8055 return value; | 8237 return value; |
| 8056 } | 8238 } |
| 8057 | 8239 |
| 8058 | 8240 |
| 8059 Object* GlobalObject::EnsurePropertyCell(String* name) { | 8241 Object* GlobalObject::EnsurePropertyCell(String* name) { |
| 8060 ASSERT(!HasFastProperties()); | 8242 ASSERT(!HasFastProperties()); |
| 8061 int entry = property_dictionary()->FindEntry(name); | 8243 int entry = property_dictionary()->FindEntry(name); |
| 8244 Object* cell; |
| 8245 { TryAllocation t = |
| 8246 Heap::AllocateJSGlobalPropertyCell(Heap::the_hole_value()); |
| 8247 if (!t->ToObject(&cell)) return t; |
| 8248 } |
| 8062 if (entry == StringDictionary::kNotFound) { | 8249 if (entry == StringDictionary::kNotFound) { |
| 8063 Object* cell = Heap::AllocateJSGlobalPropertyCell(Heap::the_hole_value()); | |
| 8064 if (cell->IsFailure()) return cell; | |
| 8065 PropertyDetails details(NONE, NORMAL); | 8250 PropertyDetails details(NONE, NORMAL); |
| 8251 Object* dictionary; |
| 8252 { TryAllocation t = property_dictionary()->Add(name, cell, details); |
| 8253 if (!t->ToObject(&dictionary)) return t; |
| 8254 } |
| 8066 details = details.AsDeleted(); | 8255 details = details.AsDeleted(); |
| 8067 Object* dictionary = property_dictionary()->Add(name, cell, details); | |
| 8068 if (dictionary->IsFailure()) return dictionary; | |
| 8069 set_properties(StringDictionary::cast(dictionary)); | 8256 set_properties(StringDictionary::cast(dictionary)); |
| 8070 return cell; | 8257 return cell; |
| 8071 } else { | 8258 } else { |
| 8072 Object* value = property_dictionary()->ValueAt(entry); | 8259 Object* value = property_dictionary()->ValueAt(entry); |
| 8073 ASSERT(value->IsJSGlobalPropertyCell()); | 8260 ASSERT(value->IsJSGlobalPropertyCell()); |
| 8074 return value; | 8261 return value; |
| 8075 } | 8262 } |
| 8076 } | 8263 } |
| 8077 | 8264 |
| 8078 | 8265 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8181 | 8368 |
| 8182 Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) { | 8369 Object* SymbolTable::LookupKey(HashTableKey* key, Object** s) { |
| 8183 int entry = FindEntry(key); | 8370 int entry = FindEntry(key); |
| 8184 | 8371 |
| 8185 // Symbol already in table. | 8372 // Symbol already in table. |
| 8186 if (entry != kNotFound) { | 8373 if (entry != kNotFound) { |
| 8187 *s = KeyAt(entry); | 8374 *s = KeyAt(entry); |
| 8188 return this; | 8375 return this; |
| 8189 } | 8376 } |
| 8190 | 8377 |
| 8378 Object* obj; |
| 8379 { TryAllocation t = EnsureCapacity(1, key); |
| 8380 if (!t->ToObject(&obj)) return t; |
| 8381 } |
| 8191 // Adding new symbol. Grow table if needed. | 8382 // Adding new symbol. Grow table if needed. |
| 8192 Object* obj = EnsureCapacity(1, key); | |
| 8193 if (obj->IsFailure()) return obj; | |
| 8194 | 8383 |
| 8384 Object* symbol; |
| 8385 { TryAllocation t = key->AsObject(); |
| 8386 if (!t->ToObject(&symbol)) return t; |
| 8387 } |
| 8195 // Create symbol object. | 8388 // Create symbol object. |
| 8196 Object* symbol = key->AsObject(); | |
| 8197 if (symbol->IsFailure()) return symbol; | |
| 8198 | 8389 |
| 8199 // If the symbol table grew as part of EnsureCapacity, obj is not | 8390 // If the symbol table grew as part of EnsureCapacity, obj is not |
| 8200 // the current symbol table and therefore we cannot use | 8391 // the current symbol table and therefore we cannot use |
| 8201 // SymbolTable::cast here. | 8392 // SymbolTable::cast here. |
| 8202 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj); | 8393 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj); |
| 8203 | 8394 |
| 8204 // Add the new symbol and return it along with the symbol table. | 8395 // Add the new symbol and return it along with the symbol table. |
| 8205 entry = table->FindInsertionEntry(key->Hash()); | 8396 entry = table->FindInsertionEntry(key->Hash()); |
| 8206 table->set(EntryToIndex(entry), symbol); | 8397 table->set(EntryToIndex(entry), symbol); |
| 8207 table->ElementAdded(); | 8398 table->ElementAdded(); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 8229 Object* CompilationCacheTable::LookupRegExp(String* src, | 8420 Object* CompilationCacheTable::LookupRegExp(String* src, |
| 8230 JSRegExp::Flags flags) { | 8421 JSRegExp::Flags flags) { |
| 8231 RegExpKey key(src, flags); | 8422 RegExpKey key(src, flags); |
| 8232 int entry = FindEntry(&key); | 8423 int entry = FindEntry(&key); |
| 8233 if (entry == kNotFound) return Heap::undefined_value(); | 8424 if (entry == kNotFound) return Heap::undefined_value(); |
| 8234 return get(EntryToIndex(entry) + 1); | 8425 return get(EntryToIndex(entry) + 1); |
| 8235 } | 8426 } |
| 8236 | 8427 |
| 8237 | 8428 |
| 8238 Object* CompilationCacheTable::Put(String* src, Object* value) { | 8429 Object* CompilationCacheTable::Put(String* src, Object* value) { |
| 8430 Object* obj; |
| 8431 { TryAllocation t = EnsureCapacity(1, &key); |
| 8432 if (!t->ToObject(&obj)) return t; |
| 8433 } |
| 8239 StringKey key(src); | 8434 StringKey key(src); |
| 8240 Object* obj = EnsureCapacity(1, &key); | |
| 8241 if (obj->IsFailure()) return obj; | |
| 8242 | 8435 |
| 8243 CompilationCacheTable* cache = | 8436 CompilationCacheTable* cache = |
| 8244 reinterpret_cast<CompilationCacheTable*>(obj); | 8437 reinterpret_cast<CompilationCacheTable*>(obj); |
| 8245 int entry = cache->FindInsertionEntry(key.Hash()); | 8438 int entry = cache->FindInsertionEntry(key.Hash()); |
| 8246 cache->set(EntryToIndex(entry), src); | 8439 cache->set(EntryToIndex(entry), src); |
| 8247 cache->set(EntryToIndex(entry) + 1, value); | 8440 cache->set(EntryToIndex(entry) + 1, value); |
| 8248 cache->ElementAdded(); | 8441 cache->ElementAdded(); |
| 8249 return cache; | 8442 return cache; |
| 8250 } | 8443 } |
| 8251 | 8444 |
| 8252 | 8445 |
| 8253 Object* CompilationCacheTable::PutEval(String* src, | 8446 Object* CompilationCacheTable::PutEval(String* src, |
| 8254 Context* context, | 8447 Context* context, |
| 8255 Object* value) { | 8448 Object* value) { |
| 8449 Object* obj; |
| 8450 { TryAllocation t = EnsureCapacity(1, &key); |
| 8451 if (!t->ToObject(&obj)) return t; |
| 8452 } |
| 8256 StringSharedKey key(src, context->closure()->shared()); | 8453 StringSharedKey key(src, context->closure()->shared()); |
| 8257 Object* obj = EnsureCapacity(1, &key); | |
| 8258 if (obj->IsFailure()) return obj; | |
| 8259 | 8454 |
| 8260 CompilationCacheTable* cache = | 8455 CompilationCacheTable* cache = |
| 8261 reinterpret_cast<CompilationCacheTable*>(obj); | 8456 reinterpret_cast<CompilationCacheTable*>(obj); |
| 8262 int entry = cache->FindInsertionEntry(key.Hash()); | 8457 int entry = cache->FindInsertionEntry(key.Hash()); |
| 8458 Object* k; |
| 8459 { TryAllocation t = key.AsObject(); |
| 8460 if (!t->ToObject(&k)) return t; |
| 8461 } |
| 8263 | 8462 |
| 8264 Object* k = key.AsObject(); | |
| 8265 if (k->IsFailure()) return k; | |
| 8266 | 8463 |
| 8267 cache->set(EntryToIndex(entry), k); | 8464 cache->set(EntryToIndex(entry), k); |
| 8268 cache->set(EntryToIndex(entry) + 1, value); | 8465 cache->set(EntryToIndex(entry) + 1, value); |
| 8269 cache->ElementAdded(); | 8466 cache->ElementAdded(); |
| 8270 return cache; | 8467 return cache; |
| 8271 } | 8468 } |
| 8272 | 8469 |
| 8273 | 8470 |
| 8274 Object* CompilationCacheTable::PutRegExp(String* src, | 8471 Object* CompilationCacheTable::PutRegExp(String* src, |
| 8275 JSRegExp::Flags flags, | 8472 JSRegExp::Flags flags, |
| 8276 FixedArray* value) { | 8473 FixedArray* value) { |
| 8474 Object* obj; |
| 8475 { TryAllocation t = EnsureCapacity(1, &key); |
| 8476 if (!t->ToObject(&obj)) return t; |
| 8477 } |
| 8277 RegExpKey key(src, flags); | 8478 RegExpKey key(src, flags); |
| 8278 Object* obj = EnsureCapacity(1, &key); | |
| 8279 if (obj->IsFailure()) return obj; | |
| 8280 | 8479 |
| 8281 CompilationCacheTable* cache = | 8480 CompilationCacheTable* cache = |
| 8282 reinterpret_cast<CompilationCacheTable*>(obj); | 8481 reinterpret_cast<CompilationCacheTable*>(obj); |
| 8283 int entry = cache->FindInsertionEntry(key.Hash()); | 8482 int entry = cache->FindInsertionEntry(key.Hash()); |
| 8284 // We store the value in the key slot, and compare the search key | 8483 // We store the value in the key slot, and compare the search key |
| 8285 // to the stored value with a custon IsMatch function during lookups. | 8484 // to the stored value with a custon IsMatch function during lookups. |
| 8286 cache->set(EntryToIndex(entry), value); | 8485 cache->set(EntryToIndex(entry), value); |
| 8287 cache->set(EntryToIndex(entry) + 1, value); | 8486 cache->set(EntryToIndex(entry) + 1, value); |
| 8288 cache->ElementAdded(); | 8487 cache->ElementAdded(); |
| 8289 return cache; | 8488 return cache; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8326 | 8525 |
| 8327 Object* MapCache::Lookup(FixedArray* array) { | 8526 Object* MapCache::Lookup(FixedArray* array) { |
| 8328 SymbolsKey key(array); | 8527 SymbolsKey key(array); |
| 8329 int entry = FindEntry(&key); | 8528 int entry = FindEntry(&key); |
| 8330 if (entry == kNotFound) return Heap::undefined_value(); | 8529 if (entry == kNotFound) return Heap::undefined_value(); |
| 8331 return get(EntryToIndex(entry) + 1); | 8530 return get(EntryToIndex(entry) + 1); |
| 8332 } | 8531 } |
| 8333 | 8532 |
| 8334 | 8533 |
| 8335 Object* MapCache::Put(FixedArray* array, Map* value) { | 8534 Object* MapCache::Put(FixedArray* array, Map* value) { |
| 8535 Object* obj; |
| 8536 { TryAllocation t = EnsureCapacity(1, &key); |
| 8537 if (!t->ToObject(&obj)) return t; |
| 8538 } |
| 8336 SymbolsKey key(array); | 8539 SymbolsKey key(array); |
| 8337 Object* obj = EnsureCapacity(1, &key); | |
| 8338 if (obj->IsFailure()) return obj; | |
| 8339 | 8540 |
| 8340 MapCache* cache = reinterpret_cast<MapCache*>(obj); | 8541 MapCache* cache = reinterpret_cast<MapCache*>(obj); |
| 8341 int entry = cache->FindInsertionEntry(key.Hash()); | 8542 int entry = cache->FindInsertionEntry(key.Hash()); |
| 8342 cache->set(EntryToIndex(entry), array); | 8543 cache->set(EntryToIndex(entry), array); |
| 8343 cache->set(EntryToIndex(entry) + 1, value); | 8544 cache->set(EntryToIndex(entry) + 1, value); |
| 8344 cache->ElementAdded(); | 8545 cache->ElementAdded(); |
| 8345 return cache; | 8546 return cache; |
| 8346 } | 8547 } |
| 8347 | 8548 |
| 8348 | 8549 |
| 8349 template<typename Shape, typename Key> | 8550 template<typename Shape, typename Key> |
| 8350 Object* Dictionary<Shape, Key>::Allocate(int at_least_space_for) { | 8551 Object* Dictionary<Shape, Key>::Allocate(int at_least_space_for) { |
| 8351 Object* obj = HashTable<Shape, Key>::Allocate(at_least_space_for); | 8552 Object* obj = HashTable<Shape, Key>::Allocate(at_least_space_for); |
| 8352 // Initialize the next enumeration index. | 8553 // Initialize the next enumeration index. |
| 8353 if (!obj->IsFailure()) { | 8554 if (!obj->IsFailure()) { |
| 8354 Dictionary<Shape, Key>::cast(obj)-> | 8555 Dictionary<Shape, Key>::cast(obj)-> |
| 8355 SetNextEnumerationIndex(PropertyDetails::kInitialIndex); | 8556 SetNextEnumerationIndex(PropertyDetails::kInitialIndex); |
| 8356 } | 8557 } |
| 8357 return obj; | 8558 return obj; |
| 8358 } | 8559 } |
| 8359 | 8560 |
| 8360 | 8561 |
| 8361 template<typename Shape, typename Key> | 8562 template<typename Shape, typename Key> |
| 8362 Object* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() { | 8563 Object* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() { |
| 8363 int length = HashTable<Shape, Key>::NumberOfElements(); | 8564 int length = HashTable<Shape, Key>::NumberOfElements(); |
| 8364 | 8565 |
| 8566 Object* obj; |
| 8567 { TryAllocation t = Heap::AllocateFixedArray(length); |
| 8568 if (!t->ToObject(&obj)) return t; |
| 8569 } |
| 8365 // Allocate and initialize iteration order array. | 8570 // Allocate and initialize iteration order array. |
| 8366 Object* obj = Heap::AllocateFixedArray(length); | |
| 8367 if (obj->IsFailure()) return obj; | |
| 8368 FixedArray* iteration_order = FixedArray::cast(obj); | 8571 FixedArray* iteration_order = FixedArray::cast(obj); |
| 8369 for (int i = 0; i < length; i++) { | 8572 for (int i = 0; i < length; i++) { |
| 8370 iteration_order->set(i, Smi::FromInt(i)); | 8573 iteration_order->set(i, Smi::FromInt(i)); |
| 8371 } | 8574 } |
| 8372 | 8575 |
| 8576 { TryAllocation t = Heap::AllocateFixedArray(length); |
| 8577 if (!t->ToObject(&obj)) return t; |
| 8578 } |
| 8373 // Allocate array with enumeration order. | 8579 // Allocate array with enumeration order. |
| 8374 obj = Heap::AllocateFixedArray(length); | |
| 8375 if (obj->IsFailure()) return obj; | |
| 8376 FixedArray* enumeration_order = FixedArray::cast(obj); | 8580 FixedArray* enumeration_order = FixedArray::cast(obj); |
| 8377 | 8581 |
| 8378 // Fill the enumeration order array with property details. | 8582 // Fill the enumeration order array with property details. |
| 8379 int capacity = HashTable<Shape, Key>::Capacity(); | 8583 int capacity = HashTable<Shape, Key>::Capacity(); |
| 8380 int pos = 0; | 8584 int pos = 0; |
| 8381 for (int i = 0; i < capacity; i++) { | 8585 for (int i = 0; i < capacity; i++) { |
| 8382 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) { | 8586 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) { |
| 8383 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index())); | 8587 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index())); |
| 8384 } | 8588 } |
| 8385 } | 8589 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 8410 // Set the next enumeration index. | 8614 // Set the next enumeration index. |
| 8411 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length); | 8615 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length); |
| 8412 return this; | 8616 return this; |
| 8413 } | 8617 } |
| 8414 | 8618 |
| 8415 template<typename Shape, typename Key> | 8619 template<typename Shape, typename Key> |
| 8416 Object* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) { | 8620 Object* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) { |
| 8417 // Check whether there are enough enumeration indices to add n elements. | 8621 // Check whether there are enough enumeration indices to add n elements. |
| 8418 if (Shape::kIsEnumerable && | 8622 if (Shape::kIsEnumerable && |
| 8419 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) { | 8623 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) { |
| 8624 Object* result; |
| 8625 { TryAllocation t = GenerateNewEnumerationIndices(); |
| 8626 if (!t->ToObject(&result)) return t; |
| 8627 } |
| 8420 // If not, we generate new indices for the properties. | 8628 // If not, we generate new indices for the properties. |
| 8421 Object* result = GenerateNewEnumerationIndices(); | |
| 8422 if (result->IsFailure()) return result; | |
| 8423 } | 8629 } |
| 8424 return HashTable<Shape, Key>::EnsureCapacity(n, key); | 8630 return HashTable<Shape, Key>::EnsureCapacity(n, key); |
| 8425 } | 8631 } |
| 8426 | 8632 |
| 8427 | 8633 |
| 8428 void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) { | 8634 void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) { |
| 8429 // Do nothing if the interval [from, to) is empty. | 8635 // Do nothing if the interval [from, to) is empty. |
| 8430 if (from >= to) return; | 8636 if (from >= to) return; |
| 8431 | 8637 |
| 8432 int removed_entries = 0; | 8638 int removed_entries = 0; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8465 template<typename Shape, typename Key> | 8671 template<typename Shape, typename Key> |
| 8466 Object* Dictionary<Shape, Key>::AtPut(Key key, Object* value) { | 8672 Object* Dictionary<Shape, Key>::AtPut(Key key, Object* value) { |
| 8467 int entry = this->FindEntry(key); | 8673 int entry = this->FindEntry(key); |
| 8468 | 8674 |
| 8469 // If the entry is present set the value; | 8675 // If the entry is present set the value; |
| 8470 if (entry != Dictionary<Shape, Key>::kNotFound) { | 8676 if (entry != Dictionary<Shape, Key>::kNotFound) { |
| 8471 ValueAtPut(entry, value); | 8677 ValueAtPut(entry, value); |
| 8472 return this; | 8678 return this; |
| 8473 } | 8679 } |
| 8474 | 8680 |
| 8681 Object* obj; |
| 8682 { TryAllocation t = EnsureCapacity(1, key); |
| 8683 if (!t->ToObject(&obj)) return t; |
| 8684 } |
| 8475 // Check whether the dictionary should be extended. | 8685 // Check whether the dictionary should be extended. |
| 8476 Object* obj = EnsureCapacity(1, key); | 8686 Object* k; |
| 8477 if (obj->IsFailure()) return obj; | 8687 { TryAllocation t = Shape::AsObject(key); |
| 8688 if (!t->ToObject(&k)) return t; |
| 8689 } |
| 8478 | 8690 |
| 8479 Object* k = Shape::AsObject(key); | |
| 8480 if (k->IsFailure()) return k; | |
| 8481 PropertyDetails details = PropertyDetails(NONE, NORMAL); | 8691 PropertyDetails details = PropertyDetails(NONE, NORMAL); |
| 8482 return Dictionary<Shape, Key>::cast(obj)-> | 8692 return Dictionary<Shape, Key>::cast(obj)-> |
| 8483 AddEntry(key, value, details, Shape::Hash(key)); | 8693 AddEntry(key, value, details, Shape::Hash(key)); |
| 8484 } | 8694 } |
| 8485 | 8695 |
| 8486 | 8696 |
| 8487 template<typename Shape, typename Key> | 8697 template<typename Shape, typename Key> |
| 8488 Object* Dictionary<Shape, Key>::Add(Key key, | 8698 Object* Dictionary<Shape, Key>::Add(Key key, |
| 8489 Object* value, | 8699 Object* value, |
| 8490 PropertyDetails details) { | 8700 PropertyDetails details) { |
| 8491 // Valdate key is absent. | 8701 // Valdate key is absent. |
| 8492 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound)); | 8702 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound)); |
| 8703 Object* obj; |
| 8704 { TryAllocation t = EnsureCapacity(1, key); |
| 8705 if (!t->ToObject(&obj)) return t; |
| 8706 } |
| 8493 // Check whether the dictionary should be extended. | 8707 // Check whether the dictionary should be extended. |
| 8494 Object* obj = EnsureCapacity(1, key); | |
| 8495 if (obj->IsFailure()) return obj; | |
| 8496 return Dictionary<Shape, Key>::cast(obj)-> | 8708 return Dictionary<Shape, Key>::cast(obj)-> |
| 8497 AddEntry(key, value, details, Shape::Hash(key)); | 8709 AddEntry(key, value, details, Shape::Hash(key)); |
| 8498 } | 8710 } |
| 8499 | 8711 |
| 8500 | 8712 |
| 8501 // Add a key, value pair to the dictionary. | 8713 // Add a key, value pair to the dictionary. |
| 8502 template<typename Shape, typename Key> | 8714 template<typename Shape, typename Key> |
| 8503 Object* Dictionary<Shape, Key>::AddEntry(Key key, | 8715 Object* Dictionary<Shape, Key>::AddEntry(Key key, |
| 8504 Object* value, | 8716 Object* value, |
| 8505 PropertyDetails details, | 8717 PropertyDetails details, |
| 8506 uint32_t hash) { | 8718 uint32_t hash) { |
| 8719 Object* k; |
| 8720 { TryAllocation t = Shape::AsObject(key); |
| 8721 if (!t->ToObject(&k)) return t; |
| 8722 } |
| 8507 // Compute the key object. | 8723 // Compute the key object. |
| 8508 Object* k = Shape::AsObject(key); | |
| 8509 if (k->IsFailure()) return k; | |
| 8510 | 8724 |
| 8511 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash); | 8725 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash); |
| 8512 // Insert element at empty or deleted entry | 8726 // Insert element at empty or deleted entry |
| 8513 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) { | 8727 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) { |
| 8514 // Assign an enumeration index to the property and update | 8728 // Assign an enumeration index to the property and update |
| 8515 // SetNextEnumerationIndex. | 8729 // SetNextEnumerationIndex. |
| 8516 int index = NextEnumerationIndex(); | 8730 int index = NextEnumerationIndex(); |
| 8517 details = PropertyDetails(details.attributes(), details.type(), index); | 8731 details = PropertyDetails(details.attributes(), details.type(), index); |
| 8518 SetNextEnumerationIndex(index + 1); | 8732 SetNextEnumerationIndex(index + 1); |
| 8519 } | 8733 } |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8679 JSObject* obj, int unused_property_fields) { | 8893 JSObject* obj, int unused_property_fields) { |
| 8680 // Make sure we preserve dictionary representation if there are too many | 8894 // Make sure we preserve dictionary representation if there are too many |
| 8681 // descriptors. | 8895 // descriptors. |
| 8682 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj; | 8896 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj; |
| 8683 | 8897 |
| 8684 // Figure out if it is necessary to generate new enumeration indices. | 8898 // Figure out if it is necessary to generate new enumeration indices. |
| 8685 int max_enumeration_index = | 8899 int max_enumeration_index = |
| 8686 NextEnumerationIndex() + | 8900 NextEnumerationIndex() + |
| 8687 (DescriptorArray::kMaxNumberOfDescriptors - | 8901 (DescriptorArray::kMaxNumberOfDescriptors - |
| 8688 NumberOfElements()); | 8902 NumberOfElements()); |
| 8903 Object* result; |
| 8904 { TryAllocation t = GenerateNewEnumerationIndices(); |
| 8905 if (!t->ToObject(&result)) return t; |
| 8906 } |
| 8689 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) { | 8907 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) { |
| 8690 Object* result = GenerateNewEnumerationIndices(); | |
| 8691 if (result->IsFailure()) return result; | |
| 8692 } | 8908 } |
| 8693 | 8909 |
| 8694 int instance_descriptor_length = 0; | 8910 int instance_descriptor_length = 0; |
| 8695 int number_of_fields = 0; | 8911 int number_of_fields = 0; |
| 8696 | 8912 |
| 8697 // Compute the length of the instance descriptor. | 8913 // Compute the length of the instance descriptor. |
| 8698 int capacity = Capacity(); | 8914 int capacity = Capacity(); |
| 8699 for (int i = 0; i < capacity; i++) { | 8915 for (int i = 0; i < capacity; i++) { |
| 8700 Object* k = KeyAt(i); | 8916 Object* k = KeyAt(i); |
| 8701 if (IsKey(k)) { | 8917 if (IsKey(k)) { |
| 8702 Object* value = ValueAt(i); | 8918 Object* value = ValueAt(i); |
| 8703 PropertyType type = DetailsAt(i).type(); | 8919 PropertyType type = DetailsAt(i).type(); |
| 8704 ASSERT(type != FIELD); | 8920 ASSERT(type != FIELD); |
| 8705 instance_descriptor_length++; | 8921 instance_descriptor_length++; |
| 8706 if (type == NORMAL && | 8922 if (type == NORMAL && |
| 8707 (!value->IsJSFunction() || Heap::InNewSpace(value))) { | 8923 (!value->IsJSFunction() || Heap::InNewSpace(value))) { |
| 8708 number_of_fields += 1; | 8924 number_of_fields += 1; |
| 8709 } | 8925 } |
| 8710 } | 8926 } |
| 8711 } | 8927 } |
| 8712 | 8928 |
| 8713 // Allocate the instance descriptor. | 8929 // Allocate the instance descriptor. |
| 8714 Object* descriptors_unchecked = | 8930 Object* descriptors_unchecked; |
| 8715 DescriptorArray::Allocate(instance_descriptor_length); | 8931 { TryAllocation t = |
| 8716 if (descriptors_unchecked->IsFailure()) return descriptors_unchecked; | 8932 DescriptorArray::Allocate(instance_descriptor_length); |
| 8933 if (!t->ToObject(&descriptors_unchecked)) return t; |
| 8934 } |
| 8717 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked); | 8935 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked); |
| 8718 | 8936 |
| 8719 int inobject_props = obj->map()->inobject_properties(); | 8937 int inobject_props = obj->map()->inobject_properties(); |
| 8720 int number_of_allocated_fields = | 8938 int number_of_allocated_fields = |
| 8721 number_of_fields + unused_property_fields - inobject_props; | 8939 number_of_fields + unused_property_fields - inobject_props; |
| 8722 | 8940 |
| 8941 Object* fields; |
| 8942 { TryAllocation t = Heap::AllocateFixedArray(number_of_allocated_fields); |
| 8943 if (!t->ToObject(&fields)) return t; |
| 8944 } |
| 8723 // Allocate the fixed array for the fields. | 8945 // Allocate the fixed array for the fields. |
| 8724 Object* fields = Heap::AllocateFixedArray(number_of_allocated_fields); | |
| 8725 if (fields->IsFailure()) return fields; | |
| 8726 | 8946 |
| 8727 // Fill in the instance descriptor and the fields. | 8947 // Fill in the instance descriptor and the fields. |
| 8728 int next_descriptor = 0; | 8948 int next_descriptor = 0; |
| 8729 int current_offset = 0; | 8949 int current_offset = 0; |
| 8730 for (int i = 0; i < capacity; i++) { | 8950 for (int i = 0; i < capacity; i++) { |
| 8731 Object* k = KeyAt(i); | 8951 Object* k = KeyAt(i); |
| 8732 if (IsKey(k)) { | 8952 if (IsKey(k)) { |
| 8733 Object* value = ValueAt(i); | 8953 Object* value = ValueAt(i); |
| 8954 Object* key; |
| 8955 { TryAllocation t = Heap::LookupSymbol(String::cast(k)); |
| 8956 if (!t->ToObject(&key)) return t; |
| 8957 } |
| 8734 // Ensure the key is a symbol before writing into the instance descriptor. | 8958 // Ensure the key is a symbol before writing into the instance descriptor. |
| 8735 Object* key = Heap::LookupSymbol(String::cast(k)); | |
| 8736 if (key->IsFailure()) return key; | |
| 8737 PropertyDetails details = DetailsAt(i); | 8959 PropertyDetails details = DetailsAt(i); |
| 8738 PropertyType type = details.type(); | 8960 PropertyType type = details.type(); |
| 8739 | 8961 |
| 8740 if (value->IsJSFunction() && !Heap::InNewSpace(value)) { | 8962 if (value->IsJSFunction() && !Heap::InNewSpace(value)) { |
| 8741 ConstantFunctionDescriptor d(String::cast(key), | 8963 ConstantFunctionDescriptor d(String::cast(key), |
| 8742 JSFunction::cast(value), | 8964 JSFunction::cast(value), |
| 8743 details.attributes(), | 8965 details.attributes(), |
| 8744 details.index()); | 8966 details.index()); |
| 8745 descriptors->Set(next_descriptor++, &d); | 8967 descriptors->Set(next_descriptor++, &d); |
| 8746 } else if (type == NORMAL) { | 8968 } else if (type == NORMAL) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 8764 details.index()); | 8986 details.index()); |
| 8765 descriptors->Set(next_descriptor++, &d); | 8987 descriptors->Set(next_descriptor++, &d); |
| 8766 } else { | 8988 } else { |
| 8767 UNREACHABLE(); | 8989 UNREACHABLE(); |
| 8768 } | 8990 } |
| 8769 } | 8991 } |
| 8770 } | 8992 } |
| 8771 ASSERT(current_offset == number_of_fields); | 8993 ASSERT(current_offset == number_of_fields); |
| 8772 | 8994 |
| 8773 descriptors->Sort(); | 8995 descriptors->Sort(); |
| 8996 Object* new_map; |
| 8997 { TryAllocation t = obj->map()->CopyDropDescriptors(); |
| 8998 if (!t->ToObject(&new_map)) return t; |
| 8999 } |
| 8774 // Allocate new map. | 9000 // Allocate new map. |
| 8775 Object* new_map = obj->map()->CopyDropDescriptors(); | |
| 8776 if (new_map->IsFailure()) return new_map; | |
| 8777 | 9001 |
| 8778 // Transform the object. | 9002 // Transform the object. |
| 8779 obj->set_map(Map::cast(new_map)); | 9003 obj->set_map(Map::cast(new_map)); |
| 8780 obj->map()->set_instance_descriptors(descriptors); | 9004 obj->map()->set_instance_descriptors(descriptors); |
| 8781 obj->map()->set_unused_property_fields(unused_property_fields); | 9005 obj->map()->set_unused_property_fields(unused_property_fields); |
| 8782 | 9006 |
| 8783 obj->set_properties(FixedArray::cast(fields)); | 9007 obj->set_properties(FixedArray::cast(fields)); |
| 8784 ASSERT(obj->IsJSObject()); | 9008 ASSERT(obj->IsJSObject()); |
| 8785 | 9009 |
| 8786 descriptors->SetNextEnumerationIndex(NextEnumerationIndex()); | 9010 descriptors->SetNextEnumerationIndex(NextEnumerationIndex()); |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9032 if (break_point_objects()->IsUndefined()) return 0; | 9256 if (break_point_objects()->IsUndefined()) return 0; |
| 9033 // Single beak point. | 9257 // Single beak point. |
| 9034 if (!break_point_objects()->IsFixedArray()) return 1; | 9258 if (!break_point_objects()->IsFixedArray()) return 1; |
| 9035 // Multiple break points. | 9259 // Multiple break points. |
| 9036 return FixedArray::cast(break_point_objects())->length(); | 9260 return FixedArray::cast(break_point_objects())->length(); |
| 9037 } | 9261 } |
| 9038 #endif | 9262 #endif |
| 9039 | 9263 |
| 9040 | 9264 |
| 9041 } } // namespace v8::internal | 9265 } } // namespace v8::internal |
| OLD | NEW |