| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 #endif | 53 #endif |
| 54 | 54 |
| 55 namespace v8 { | 55 namespace v8 { |
| 56 namespace internal { | 56 namespace internal { |
| 57 | 57 |
| 58 // Getters and setters are stored in a fixed array property. These are | 58 // Getters and setters are stored in a fixed array property. These are |
| 59 // constants for their indices. | 59 // constants for their indices. |
| 60 const int kGetterIndex = 0; | 60 const int kGetterIndex = 0; |
| 61 const int kSetterIndex = 1; | 61 const int kSetterIndex = 1; |
| 62 | 62 |
| 63 uint64_t FixedDoubleArray::kHoleNanInt64 = -1; |
| 64 uint64_t FixedDoubleArray::kCanonicalNonHoleNanLower32 = 0x7FF00000; |
| 65 uint64_t FixedDoubleArray::kCanonicalNonHoleNanInt64 = |
| 66 kCanonicalNonHoleNanLower32 << 32; |
| 63 | 67 |
| 64 MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor, | 68 MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor, |
| 65 Object* value) { | 69 Object* value) { |
| 66 Object* result; | 70 Object* result; |
| 67 { MaybeObject* maybe_result = | 71 { MaybeObject* maybe_result = |
| 68 constructor->GetHeap()->AllocateJSObject(constructor); | 72 constructor->GetHeap()->AllocateJSObject(constructor); |
| 69 if (!maybe_result->ToObject(&result)) return maybe_result; | 73 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 70 } | 74 } |
| 71 JSValue::cast(result)->set_value(value); | 75 JSValue::cast(result)->set_value(value); |
| 72 return result; | 76 return result; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 | 139 |
| 136 void Object::Lookup(String* name, LookupResult* result) { | 140 void Object::Lookup(String* name, LookupResult* result) { |
| 137 Object* holder = NULL; | 141 Object* holder = NULL; |
| 138 if (IsSmi()) { | 142 if (IsSmi()) { |
| 139 Context* global_context = Isolate::Current()->context()->global_context(); | 143 Context* global_context = Isolate::Current()->context()->global_context(); |
| 140 holder = global_context->number_function()->instance_prototype(); | 144 holder = global_context->number_function()->instance_prototype(); |
| 141 } else { | 145 } else { |
| 142 HeapObject* heap_object = HeapObject::cast(this); | 146 HeapObject* heap_object = HeapObject::cast(this); |
| 143 if (heap_object->IsJSObject()) { | 147 if (heap_object->IsJSObject()) { |
| 144 return JSObject::cast(this)->Lookup(name, result); | 148 return JSObject::cast(this)->Lookup(name, result); |
| 149 } else if (heap_object->IsJSProxy()) { |
| 150 return result->HandlerResult(); |
| 145 } | 151 } |
| 146 Context* global_context = Isolate::Current()->context()->global_context(); | 152 Context* global_context = Isolate::Current()->context()->global_context(); |
| 147 if (heap_object->IsString()) { | 153 if (heap_object->IsString()) { |
| 148 holder = global_context->string_function()->instance_prototype(); | 154 holder = global_context->string_function()->instance_prototype(); |
| 149 } else if (heap_object->IsHeapNumber()) { | 155 } else if (heap_object->IsHeapNumber()) { |
| 150 holder = global_context->number_function()->instance_prototype(); | 156 holder = global_context->number_function()->instance_prototype(); |
| 151 } else if (heap_object->IsBoolean()) { | 157 } else if (heap_object->IsBoolean()) { |
| 152 holder = global_context->boolean_function()->instance_prototype(); | 158 holder = global_context->boolean_function()->instance_prototype(); |
| 153 } else if (heap_object->IsJSProxy()) { | |
| 154 return result->HandlerResult(); | |
| 155 } | 159 } |
| 156 } | 160 } |
| 157 ASSERT(holder != NULL); // Cannot handle null or undefined. | 161 ASSERT(holder != NULL); // Cannot handle null or undefined. |
| 158 JSObject::cast(holder)->Lookup(name, result); | 162 JSObject::cast(holder)->Lookup(name, result); |
| 159 } | 163 } |
| 160 | 164 |
| 161 | 165 |
| 162 MaybeObject* Object::GetPropertyWithReceiver(Object* receiver, | 166 MaybeObject* Object::GetPropertyWithReceiver(Object* receiver, |
| 163 String* name, | 167 String* name, |
| 164 PropertyAttributes* attributes) { | 168 PropertyAttributes* attributes) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw, | 235 MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw, |
| 232 String* name_raw, | 236 String* name_raw, |
| 233 Object* handler_raw) { | 237 Object* handler_raw) { |
| 234 Isolate* isolate = name_raw->GetIsolate(); | 238 Isolate* isolate = name_raw->GetIsolate(); |
| 235 HandleScope scope; | 239 HandleScope scope; |
| 236 Handle<Object> receiver(receiver_raw); | 240 Handle<Object> receiver(receiver_raw); |
| 237 Handle<Object> name(name_raw); | 241 Handle<Object> name(name_raw); |
| 238 Handle<Object> handler(handler_raw); | 242 Handle<Object> handler(handler_raw); |
| 239 | 243 |
| 240 // Extract trap function. | 244 // Extract trap function. |
| 241 LookupResult lookup; | 245 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("get"); |
| 242 Handle<Object> trap(v8::internal::GetProperty(handler, "get", &lookup)); | 246 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name)); |
| 243 if (!lookup.IsFound()) { | 247 if (trap->IsUndefined()) { |
| 244 // Get the derived `get' property. | 248 // Get the derived `get' property. |
| 245 trap = isolate->derived_get_trap(); | 249 trap = isolate->derived_get_trap(); |
| 246 } | 250 } |
| 247 | 251 |
| 248 // Call trap function. | 252 // Call trap function. |
| 249 Object** args[] = { receiver.location(), name.location() }; | 253 Object** args[] = { receiver.location(), name.location() }; |
| 250 bool has_exception; | 254 bool has_exception; |
| 251 Handle<Object> result = | 255 Handle<Object> result = |
| 252 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception); | 256 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception); |
| 253 if (has_exception) return Failure::Exception(); | 257 if (has_exception) return Failure::Exception(); |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); | 488 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); |
| 485 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 489 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
| 486 } | 490 } |
| 487 set_map(Map::cast(new_map)); | 491 set_map(Map::cast(new_map)); |
| 488 } | 492 } |
| 489 JSGlobalPropertyCell* cell = | 493 JSGlobalPropertyCell* cell = |
| 490 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); | 494 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); |
| 491 cell->set_value(cell->GetHeap()->the_hole_value()); | 495 cell->set_value(cell->GetHeap()->the_hole_value()); |
| 492 dictionary->DetailsAtPut(entry, details.AsDeleted()); | 496 dictionary->DetailsAtPut(entry, details.AsDeleted()); |
| 493 } else { | 497 } else { |
| 494 return dictionary->DeleteProperty(entry, mode); | 498 Object* deleted = dictionary->DeleteProperty(entry, mode); |
| 499 if (deleted == GetHeap()->true_value()) { |
| 500 FixedArray* new_properties = NULL; |
| 501 MaybeObject* maybe_properties = dictionary->Shrink(name); |
| 502 if (!maybe_properties->To(&new_properties)) { |
| 503 return maybe_properties; |
| 504 } |
| 505 set_properties(new_properties); |
| 506 } |
| 507 return deleted; |
| 495 } | 508 } |
| 496 } | 509 } |
| 497 return GetHeap()->true_value(); | 510 return GetHeap()->true_value(); |
| 498 } | 511 } |
| 499 | 512 |
| 500 | 513 |
| 501 bool JSObject::IsDirty() { | 514 bool JSObject::IsDirty() { |
| 502 Object* cons_obj = map()->constructor(); | 515 Object* cons_obj = map()->constructor(); |
| 503 if (!cons_obj->IsJSFunction()) | 516 if (!cons_obj->IsJSFunction()) |
| 504 return true; | 517 return true; |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 633 if (IsSmi()) { | 646 if (IsSmi()) { |
| 634 Heap* heap = Isolate::Current()->heap(); | 647 Heap* heap = Isolate::Current()->heap(); |
| 635 Context* context = heap->isolate()->context()->global_context(); | 648 Context* context = heap->isolate()->context()->global_context(); |
| 636 return context->number_function()->instance_prototype(); | 649 return context->number_function()->instance_prototype(); |
| 637 } | 650 } |
| 638 | 651 |
| 639 HeapObject* heap_object = HeapObject::cast(this); | 652 HeapObject* heap_object = HeapObject::cast(this); |
| 640 | 653 |
| 641 // The object is either a number, a string, a boolean, | 654 // The object is either a number, a string, a boolean, |
| 642 // a real JS object, or a Harmony proxy. | 655 // a real JS object, or a Harmony proxy. |
| 643 if (heap_object->IsJSObject() || heap_object->IsJSProxy()) { | 656 if (heap_object->IsJSReceiver()) { |
| 644 return heap_object->map()->prototype(); | 657 return heap_object->map()->prototype(); |
| 645 } | 658 } |
| 646 Heap* heap = heap_object->GetHeap(); | 659 Heap* heap = heap_object->GetHeap(); |
| 647 Context* context = heap->isolate()->context()->global_context(); | 660 Context* context = heap->isolate()->context()->global_context(); |
| 648 | 661 |
| 649 if (heap_object->IsHeapNumber()) { | 662 if (heap_object->IsHeapNumber()) { |
| 650 return context->number_function()->instance_prototype(); | 663 return context->number_function()->instance_prototype(); |
| 651 } | 664 } |
| 652 if (heap_object->IsString()) { | 665 if (heap_object->IsString()) { |
| 653 return context->string_function()->instance_prototype(); | 666 return context->string_function()->instance_prototype(); |
| (...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1183 } | 1196 } |
| 1184 break; | 1197 break; |
| 1185 } | 1198 } |
| 1186 return; | 1199 return; |
| 1187 } | 1200 } |
| 1188 | 1201 |
| 1189 switch (type) { | 1202 switch (type) { |
| 1190 case FIXED_ARRAY_TYPE: | 1203 case FIXED_ARRAY_TYPE: |
| 1191 FixedArray::BodyDescriptor::IterateBody(this, object_size, v); | 1204 FixedArray::BodyDescriptor::IterateBody(this, object_size, v); |
| 1192 break; | 1205 break; |
| 1206 case FIXED_DOUBLE_ARRAY_TYPE: |
| 1207 break; |
| 1193 case JS_OBJECT_TYPE: | 1208 case JS_OBJECT_TYPE: |
| 1194 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: | 1209 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: |
| 1195 case JS_VALUE_TYPE: | 1210 case JS_VALUE_TYPE: |
| 1196 case JS_ARRAY_TYPE: | 1211 case JS_ARRAY_TYPE: |
| 1197 case JS_REGEXP_TYPE: | 1212 case JS_REGEXP_TYPE: |
| 1198 case JS_GLOBAL_PROXY_TYPE: | 1213 case JS_GLOBAL_PROXY_TYPE: |
| 1199 case JS_GLOBAL_OBJECT_TYPE: | 1214 case JS_GLOBAL_OBJECT_TYPE: |
| 1200 case JS_BUILTINS_OBJECT_TYPE: | 1215 case JS_BUILTINS_OBJECT_TYPE: |
| 1201 case JS_MESSAGE_OBJECT_TYPE: | 1216 case JS_MESSAGE_OBJECT_TYPE: |
| 1202 JSObject::BodyDescriptor::IterateBody(this, object_size, v); | 1217 JSObject::BodyDescriptor::IterateBody(this, object_size, v); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1287 // allocation when producing post-crash stack traces, so we print into a | 1302 // allocation when producing post-crash stack traces, so we print into a |
| 1288 // buffer that is plenty big enough for any floating point number, then | 1303 // buffer that is plenty big enough for any floating point number, then |
| 1289 // print that using vsnprintf (which may truncate but never allocate if | 1304 // print that using vsnprintf (which may truncate but never allocate if |
| 1290 // there is no more space in the buffer). | 1305 // there is no more space in the buffer). |
| 1291 EmbeddedVector<char, 100> buffer; | 1306 EmbeddedVector<char, 100> buffer; |
| 1292 OS::SNPrintF(buffer, "%.16g", Number()); | 1307 OS::SNPrintF(buffer, "%.16g", Number()); |
| 1293 accumulator->Add("%s", buffer.start()); | 1308 accumulator->Add("%s", buffer.start()); |
| 1294 } | 1309 } |
| 1295 | 1310 |
| 1296 | 1311 |
| 1297 String* JSObject::class_name() { | 1312 String* JSReceiver::class_name() { |
| 1298 if (IsJSFunction()) { | 1313 if (IsJSFunction() && IsJSFunctionProxy()) { |
| 1299 return GetHeap()->function_class_symbol(); | 1314 return GetHeap()->function_class_symbol(); |
| 1300 } | 1315 } |
| 1301 if (map()->constructor()->IsJSFunction()) { | 1316 if (map()->constructor()->IsJSFunction()) { |
| 1302 JSFunction* constructor = JSFunction::cast(map()->constructor()); | 1317 JSFunction* constructor = JSFunction::cast(map()->constructor()); |
| 1303 return String::cast(constructor->shared()->instance_class_name()); | 1318 return String::cast(constructor->shared()->instance_class_name()); |
| 1304 } | 1319 } |
| 1305 // If the constructor is not present, return "Object". | 1320 // If the constructor is not present, return "Object". |
| 1306 return GetHeap()->Object_symbol(); | 1321 return GetHeap()->Object_symbol(); |
| 1307 } | 1322 } |
| 1308 | 1323 |
| 1309 | 1324 |
| 1310 String* JSObject::constructor_name() { | 1325 String* JSReceiver::constructor_name() { |
| 1311 if (map()->constructor()->IsJSFunction()) { | 1326 if (map()->constructor()->IsJSFunction()) { |
| 1312 JSFunction* constructor = JSFunction::cast(map()->constructor()); | 1327 JSFunction* constructor = JSFunction::cast(map()->constructor()); |
| 1313 String* name = String::cast(constructor->shared()->name()); | 1328 String* name = String::cast(constructor->shared()->name()); |
| 1314 if (name->length() > 0) return name; | 1329 if (name->length() > 0) return name; |
| 1315 String* inferred_name = constructor->shared()->inferred_name(); | 1330 String* inferred_name = constructor->shared()->inferred_name(); |
| 1316 if (inferred_name->length() > 0) return inferred_name; | 1331 if (inferred_name->length() > 0) return inferred_name; |
| 1317 Object* proto = GetPrototype(); | 1332 Object* proto = GetPrototype(); |
| 1318 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name(); | 1333 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name(); |
| 1319 } | 1334 } |
| 1335 // TODO(rossberg): what about proxies? |
| 1320 // If the constructor is not present, return "Object". | 1336 // If the constructor is not present, return "Object". |
| 1321 return GetHeap()->Object_symbol(); | 1337 return GetHeap()->Object_symbol(); |
| 1322 } | 1338 } |
| 1323 | 1339 |
| 1324 | 1340 |
| 1325 MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, | 1341 MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, |
| 1326 String* name, | 1342 String* name, |
| 1327 Object* value) { | 1343 Object* value) { |
| 1328 int index = new_map->PropertyIndexFor(name); | 1344 int index = new_map->PropertyIndexFor(name); |
| 1329 if (map()->unused_property_fields() == 0) { | 1345 if (map()->unused_property_fields() == 0) { |
| (...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1764 MaybeObject* raw_result = | 1780 MaybeObject* raw_result = |
| 1765 this_handle->SetPropertyPostInterceptor(*name_handle, | 1781 this_handle->SetPropertyPostInterceptor(*name_handle, |
| 1766 *value_handle, | 1782 *value_handle, |
| 1767 attributes, | 1783 attributes, |
| 1768 strict_mode); | 1784 strict_mode); |
| 1769 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 1785 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
| 1770 return raw_result; | 1786 return raw_result; |
| 1771 } | 1787 } |
| 1772 | 1788 |
| 1773 | 1789 |
| 1774 MaybeObject* JSObject::SetProperty(String* name, | 1790 MaybeObject* JSReceiver::SetProperty(String* name, |
| 1775 Object* value, | 1791 Object* value, |
| 1776 PropertyAttributes attributes, | 1792 PropertyAttributes attributes, |
| 1777 StrictModeFlag strict_mode) { | 1793 StrictModeFlag strict_mode) { |
| 1778 LookupResult result; | 1794 LookupResult result; |
| 1779 LocalLookup(name, &result); | 1795 LocalLookup(name, &result); |
| 1780 return SetProperty(&result, name, value, attributes, strict_mode); | 1796 return SetProperty(&result, name, value, attributes, strict_mode); |
| 1781 } | 1797 } |
| 1782 | 1798 |
| 1783 | 1799 |
| 1784 MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, | 1800 MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, |
| 1785 String* name, | 1801 String* name, |
| 1786 Object* value, | 1802 Object* value, |
| 1787 JSObject* holder, | 1803 JSObject* holder, |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1896 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( | 1912 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( |
| 1897 uint32_t index, | 1913 uint32_t index, |
| 1898 Object* value, | 1914 Object* value, |
| 1899 bool* found, | 1915 bool* found, |
| 1900 StrictModeFlag strict_mode) { | 1916 StrictModeFlag strict_mode) { |
| 1901 Heap* heap = GetHeap(); | 1917 Heap* heap = GetHeap(); |
| 1902 for (Object* pt = GetPrototype(); | 1918 for (Object* pt = GetPrototype(); |
| 1903 pt != heap->null_value(); | 1919 pt != heap->null_value(); |
| 1904 pt = pt->GetPrototype()) { | 1920 pt = pt->GetPrototype()) { |
| 1905 if (!JSObject::cast(pt)->HasDictionaryElements()) { | 1921 if (!JSObject::cast(pt)->HasDictionaryElements()) { |
| 1906 continue; | 1922 continue; |
| 1907 } | 1923 } |
| 1908 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); | 1924 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); |
| 1909 int entry = dictionary->FindEntry(index); | 1925 int entry = dictionary->FindEntry(index); |
| 1910 if (entry != NumberDictionary::kNotFound) { | 1926 if (entry != NumberDictionary::kNotFound) { |
| 1911 PropertyDetails details = dictionary->DetailsAt(entry); | 1927 PropertyDetails details = dictionary->DetailsAt(entry); |
| 1912 if (details.type() == CALLBACKS) { | 1928 if (details.type() == CALLBACKS) { |
| 1913 *found = true; | 1929 *found = true; |
| 1914 return SetElementWithCallback(dictionary->ValueAt(entry), | 1930 return SetElementWithCallback(dictionary->ValueAt(entry), |
| 1915 index, | 1931 index, |
| 1916 value, | 1932 value, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1947 cache->Update(descriptors, name, number); | 1963 cache->Update(descriptors, name, number); |
| 1948 } | 1964 } |
| 1949 if (number != DescriptorArray::kNotFound) { | 1965 if (number != DescriptorArray::kNotFound) { |
| 1950 result->DescriptorResult(holder, descriptors->GetDetails(number), number); | 1966 result->DescriptorResult(holder, descriptors->GetDetails(number), number); |
| 1951 } else { | 1967 } else { |
| 1952 result->NotFound(); | 1968 result->NotFound(); |
| 1953 } | 1969 } |
| 1954 } | 1970 } |
| 1955 | 1971 |
| 1956 | 1972 |
| 1973 static JSObject::ElementsKind GetElementsKindFromExternalArrayType( |
| 1974 ExternalArrayType array_type) { |
| 1975 switch (array_type) { |
| 1976 case kExternalByteArray: |
| 1977 return JSObject::EXTERNAL_BYTE_ELEMENTS; |
| 1978 break; |
| 1979 case kExternalUnsignedByteArray: |
| 1980 return JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS; |
| 1981 break; |
| 1982 case kExternalShortArray: |
| 1983 return JSObject::EXTERNAL_SHORT_ELEMENTS; |
| 1984 break; |
| 1985 case kExternalUnsignedShortArray: |
| 1986 return JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS; |
| 1987 break; |
| 1988 case kExternalIntArray: |
| 1989 return JSObject::EXTERNAL_INT_ELEMENTS; |
| 1990 break; |
| 1991 case kExternalUnsignedIntArray: |
| 1992 return JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS; |
| 1993 break; |
| 1994 case kExternalFloatArray: |
| 1995 return JSObject::EXTERNAL_FLOAT_ELEMENTS; |
| 1996 break; |
| 1997 case kExternalDoubleArray: |
| 1998 return JSObject::EXTERNAL_DOUBLE_ELEMENTS; |
| 1999 break; |
| 2000 case kExternalPixelArray: |
| 2001 return JSObject::EXTERNAL_PIXEL_ELEMENTS; |
| 2002 break; |
| 2003 } |
| 2004 UNREACHABLE(); |
| 2005 return JSObject::DICTIONARY_ELEMENTS; |
| 2006 } |
| 2007 |
| 2008 |
| 1957 MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type, | 2009 MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type, |
| 1958 bool safe_to_add_transition) { | 2010 bool safe_to_add_transition) { |
| 1959 Heap* current_heap = GetHeap(); | 2011 Heap* current_heap = GetHeap(); |
| 1960 DescriptorArray* descriptors = instance_descriptors(); | 2012 DescriptorArray* descriptors = instance_descriptors(); |
| 1961 String* external_array_sentinel_name = current_heap->empty_symbol(); | 2013 String* external_array_sentinel_name = current_heap->empty_symbol(); |
| 1962 | 2014 |
| 1963 if (safe_to_add_transition) { | 2015 if (safe_to_add_transition) { |
| 1964 // It's only safe to manipulate the descriptor array if it would be | 2016 // It's only safe to manipulate the descriptor array if it would be |
| 1965 // safe to add a transition. | 2017 // safe to add a transition. |
| 1966 | 2018 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1989 } | 2041 } |
| 1990 } | 2042 } |
| 1991 | 2043 |
| 1992 // No transition to an existing external array map. Make a new one. | 2044 // No transition to an existing external array map. Make a new one. |
| 1993 Object* obj; | 2045 Object* obj; |
| 1994 { MaybeObject* maybe_map = CopyDropTransitions(); | 2046 { MaybeObject* maybe_map = CopyDropTransitions(); |
| 1995 if (!maybe_map->ToObject(&obj)) return maybe_map; | 2047 if (!maybe_map->ToObject(&obj)) return maybe_map; |
| 1996 } | 2048 } |
| 1997 Map* new_map = Map::cast(obj); | 2049 Map* new_map = Map::cast(obj); |
| 1998 | 2050 |
| 1999 new_map->set_has_fast_elements(false); | 2051 new_map->set_elements_kind(GetElementsKindFromExternalArrayType(array_type)); |
| 2000 new_map->set_has_external_array_elements(true); | |
| 2001 GetIsolate()->counters()->map_to_external_array_elements()->Increment(); | 2052 GetIsolate()->counters()->map_to_external_array_elements()->Increment(); |
| 2002 | 2053 |
| 2003 // Only remember the map transition if the object's map is NOT equal to the | 2054 // Only remember the map transition if the object's map is NOT equal to the |
| 2004 // global object_function's map and there is not an already existing | 2055 // global object_function's map and there is not an already existing |
| 2005 // non-matching external array transition. | 2056 // non-matching external array transition. |
| 2006 bool allow_map_transition = | 2057 bool allow_map_transition = |
| 2007 safe_to_add_transition && | 2058 safe_to_add_transition && |
| 2008 (GetIsolate()->context()->global_context()->object_function()->map() != | 2059 (GetIsolate()->context()->global_context()->object_function()->map() != |
| 2009 map()); | 2060 map()); |
| 2010 if (allow_map_transition) { | 2061 if (allow_map_transition) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2146 } | 2197 } |
| 2147 | 2198 |
| 2148 HandleScope scope; | 2199 HandleScope scope; |
| 2149 Handle<Object> value_handle(value); | 2200 Handle<Object> value_handle(value); |
| 2150 Heap* heap = GetHeap(); | 2201 Heap* heap = GetHeap(); |
| 2151 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); | 2202 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); |
| 2152 return *value_handle; | 2203 return *value_handle; |
| 2153 } | 2204 } |
| 2154 | 2205 |
| 2155 | 2206 |
| 2156 MaybeObject* JSObject::SetProperty(LookupResult* result, | 2207 MaybeObject* JSReceiver::SetProperty(LookupResult* result, |
| 2208 String* key, |
| 2209 Object* value, |
| 2210 PropertyAttributes attributes, |
| 2211 StrictModeFlag strict_mode) { |
| 2212 if (result->IsFound() && result->type() == HANDLER) { |
| 2213 return JSProxy::cast(this)->SetPropertyWithHandler( |
| 2214 key, value, attributes, strict_mode); |
| 2215 } else { |
| 2216 return JSObject::cast(this)->SetPropertyForResult( |
| 2217 result, key, value, attributes, strict_mode); |
| 2218 } |
| 2219 } |
| 2220 |
| 2221 |
| 2222 MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler( |
| 2223 String* name_raw, |
| 2224 Object* value_raw, |
| 2225 PropertyAttributes attributes, |
| 2226 StrictModeFlag strict_mode) { |
| 2227 Isolate* isolate = GetIsolate(); |
| 2228 HandleScope scope; |
| 2229 Handle<Object> receiver(this); |
| 2230 Handle<Object> name(name_raw); |
| 2231 Handle<Object> value(value_raw); |
| 2232 Handle<Object> handler(this->handler()); |
| 2233 |
| 2234 // Extract trap function. |
| 2235 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set"); |
| 2236 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name)); |
| 2237 if (trap->IsUndefined()) { |
| 2238 trap = isolate->derived_set_trap(); |
| 2239 } |
| 2240 |
| 2241 // Call trap function. |
| 2242 Object** args[] = { |
| 2243 receiver.location(), name.location(), value.location() |
| 2244 }; |
| 2245 bool has_exception; |
| 2246 Handle<Object> result = |
| 2247 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception); |
| 2248 if (has_exception) return Failure::Exception(); |
| 2249 |
| 2250 return *value; |
| 2251 } |
| 2252 |
| 2253 |
| 2254 MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler( |
| 2255 JSReceiver* receiver_raw, |
| 2256 String* name_raw, |
| 2257 bool* has_exception) { |
| 2258 Isolate* isolate = GetIsolate(); |
| 2259 HandleScope scope; |
| 2260 Handle<JSReceiver> receiver(receiver_raw); |
| 2261 Handle<Object> name(name_raw); |
| 2262 Handle<Object> handler(this->handler()); |
| 2263 |
| 2264 // Extract trap function. |
| 2265 Handle<String> trap_name = |
| 2266 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor"); |
| 2267 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name)); |
| 2268 if (trap->IsUndefined()) { |
| 2269 Handle<Object> args[] = { handler, trap_name }; |
| 2270 Handle<Object> error = isolate->factory()->NewTypeError( |
| 2271 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args))); |
| 2272 isolate->Throw(*error); |
| 2273 *has_exception = true; |
| 2274 return NONE; |
| 2275 } |
| 2276 |
| 2277 // Call trap function. |
| 2278 Object** args[] = { name.location() }; |
| 2279 Handle<Object> result = |
| 2280 Execution::Call(trap, handler, ARRAY_SIZE(args), args, has_exception); |
| 2281 if (has_exception) return NONE; |
| 2282 |
| 2283 // TODO(rossberg): convert result to PropertyAttributes |
| 2284 USE(result); |
| 2285 return NONE; |
| 2286 } |
| 2287 |
| 2288 |
| 2289 MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, |
| 2157 String* name, | 2290 String* name, |
| 2158 Object* value, | 2291 Object* value, |
| 2159 PropertyAttributes attributes, | 2292 PropertyAttributes attributes, |
| 2160 StrictModeFlag strict_mode) { | 2293 StrictModeFlag strict_mode) { |
| 2161 Heap* heap = GetHeap(); | 2294 Heap* heap = GetHeap(); |
| 2162 // Make sure that the top context does not change when doing callbacks or | 2295 // Make sure that the top context does not change when doing callbacks or |
| 2163 // interceptor calls. | 2296 // interceptor calls. |
| 2164 AssertNoContextChange ncc; | 2297 AssertNoContextChange ncc; |
| 2165 | 2298 |
| 2166 // Optimization for 2-byte strings often used as keys in a decompression | 2299 // Optimization for 2-byte strings often used as keys in a decompression |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2431 result = getter(v8::Utils::ToLocal(name_handle), info); | 2564 result = getter(v8::Utils::ToLocal(name_handle), info); |
| 2432 } | 2565 } |
| 2433 if (!result.IsEmpty()) return DONT_ENUM; | 2566 if (!result.IsEmpty()) return DONT_ENUM; |
| 2434 } | 2567 } |
| 2435 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle, | 2568 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle, |
| 2436 *name_handle, | 2569 *name_handle, |
| 2437 continue_search); | 2570 continue_search); |
| 2438 } | 2571 } |
| 2439 | 2572 |
| 2440 | 2573 |
| 2441 PropertyAttributes JSObject::GetPropertyAttributeWithReceiver( | 2574 PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver( |
| 2442 JSObject* receiver, | 2575 JSReceiver* receiver, |
| 2443 String* key) { | 2576 String* key) { |
| 2444 uint32_t index = 0; | 2577 uint32_t index = 0; |
| 2445 if (key->AsArrayIndex(&index)) { | 2578 if (IsJSObject() && key->AsArrayIndex(&index)) { |
| 2446 if (HasElementWithReceiver(receiver, index)) return NONE; | 2579 if (JSObject::cast(this)->HasElementWithReceiver(receiver, index)) |
| 2580 return NONE; |
| 2447 return ABSENT; | 2581 return ABSENT; |
| 2448 } | 2582 } |
| 2449 // Named property. | 2583 // Named property. |
| 2450 LookupResult result; | 2584 LookupResult result; |
| 2451 Lookup(key, &result); | 2585 Lookup(key, &result); |
| 2452 return GetPropertyAttribute(receiver, &result, key, true); | 2586 return GetPropertyAttribute(receiver, &result, key, true); |
| 2453 } | 2587 } |
| 2454 | 2588 |
| 2455 | 2589 |
| 2456 PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver, | 2590 PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver, |
| 2457 LookupResult* result, | 2591 LookupResult* result, |
| 2458 String* name, | 2592 String* name, |
| 2459 bool continue_search) { | 2593 bool continue_search) { |
| 2460 // Check access rights if needed. | 2594 // Check access rights if needed. |
| 2461 if (IsAccessCheckNeeded()) { | 2595 if (IsAccessCheckNeeded()) { |
| 2596 JSObject* this_obj = JSObject::cast(this); |
| 2462 Heap* heap = GetHeap(); | 2597 Heap* heap = GetHeap(); |
| 2463 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) { | 2598 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) { |
| 2464 return GetPropertyAttributeWithFailedAccessCheck(receiver, | 2599 return this_obj->GetPropertyAttributeWithFailedAccessCheck( |
| 2465 result, | 2600 receiver, result, name, continue_search); |
| 2466 name, | |
| 2467 continue_search); | |
| 2468 } | 2601 } |
| 2469 } | 2602 } |
| 2470 if (result->IsProperty()) { | 2603 if (result->IsProperty()) { |
| 2471 switch (result->type()) { | 2604 switch (result->type()) { |
| 2472 case NORMAL: // fall through | 2605 case NORMAL: // fall through |
| 2473 case FIELD: | 2606 case FIELD: |
| 2474 case CONSTANT_FUNCTION: | 2607 case CONSTANT_FUNCTION: |
| 2475 case CALLBACKS: | 2608 case CALLBACKS: |
| 2476 return result->GetAttributes(); | 2609 return result->GetAttributes(); |
| 2610 case HANDLER: { |
| 2611 // TODO(rossberg): propagate exceptions properly. |
| 2612 bool has_exception = false; |
| 2613 return JSProxy::cast(this)->GetPropertyAttributeWithHandler( |
| 2614 receiver, name, &has_exception); |
| 2615 } |
| 2477 case INTERCEPTOR: | 2616 case INTERCEPTOR: |
| 2478 return result->holder()-> | 2617 return result->holder()->GetPropertyAttributeWithInterceptor( |
| 2479 GetPropertyAttributeWithInterceptor(receiver, name, continue_search); | 2618 JSObject::cast(receiver), name, continue_search); |
| 2480 default: | 2619 default: |
| 2481 UNREACHABLE(); | 2620 UNREACHABLE(); |
| 2482 } | 2621 } |
| 2483 } | 2622 } |
| 2484 return ABSENT; | 2623 return ABSENT; |
| 2485 } | 2624 } |
| 2486 | 2625 |
| 2487 | 2626 |
| 2488 PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) { | 2627 PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) { |
| 2489 // Check whether the name is an array index. | 2628 // Check whether the name is an array index. |
| 2490 uint32_t index = 0; | 2629 uint32_t index = 0; |
| 2491 if (name->AsArrayIndex(&index)) { | 2630 if (IsJSObject() && name->AsArrayIndex(&index)) { |
| 2492 if (HasLocalElement(index)) return NONE; | 2631 if (JSObject::cast(this)->HasLocalElement(index)) return NONE; |
| 2493 return ABSENT; | 2632 return ABSENT; |
| 2494 } | 2633 } |
| 2495 // Named property. | 2634 // Named property. |
| 2496 LookupResult result; | 2635 LookupResult result; |
| 2497 LocalLookup(name, &result); | 2636 LocalLookup(name, &result); |
| 2498 return GetPropertyAttribute(this, &result, name, false); | 2637 return GetPropertyAttribute(this, &result, name, false); |
| 2499 } | 2638 } |
| 2500 | 2639 |
| 2501 | 2640 |
| 2502 MaybeObject* NormalizedMapCache::Get(JSObject* obj, | 2641 MaybeObject* NormalizedMapCache::Get(JSObject* obj, |
| 2503 PropertyNormalizationMode mode) { | 2642 PropertyNormalizationMode mode) { |
| 2504 Isolate* isolate = obj->GetIsolate(); | 2643 Isolate* isolate = obj->GetIsolate(); |
| 2505 Map* fast = obj->map(); | 2644 Map* fast = obj->map(); |
| 2506 int index = Hash(fast) % kEntries; | 2645 int index = fast->Hash() % kEntries; |
| 2507 Object* result = get(index); | 2646 Object* result = get(index); |
| 2508 if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) { | 2647 if (result->IsMap() && |
| 2648 Map::cast(result)->EquivalentToForNormalization(fast, mode)) { |
| 2509 #ifdef DEBUG | 2649 #ifdef DEBUG |
| 2650 Map::cast(result)->SharedMapVerify(); |
| 2510 if (FLAG_enable_slow_asserts) { | 2651 if (FLAG_enable_slow_asserts) { |
| 2511 // The cached map should match newly created normalized map bit-by-bit. | 2652 // The cached map should match newly created normalized map bit-by-bit. |
| 2512 Object* fresh; | 2653 Object* fresh; |
| 2513 { MaybeObject* maybe_fresh = | 2654 { MaybeObject* maybe_fresh = |
| 2514 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); | 2655 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); |
| 2515 if (maybe_fresh->ToObject(&fresh)) { | 2656 if (maybe_fresh->ToObject(&fresh)) { |
| 2516 ASSERT(memcmp(Map::cast(fresh)->address(), | 2657 ASSERT(memcmp(Map::cast(fresh)->address(), |
| 2517 Map::cast(result)->address(), | 2658 Map::cast(result)->address(), |
| 2518 Map::kSize) == 0); | 2659 Map::kSize) == 0); |
| 2519 } | 2660 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2535 | 2676 |
| 2536 | 2677 |
| 2537 void NormalizedMapCache::Clear() { | 2678 void NormalizedMapCache::Clear() { |
| 2538 int entries = length(); | 2679 int entries = length(); |
| 2539 for (int i = 0; i != entries; i++) { | 2680 for (int i = 0; i != entries; i++) { |
| 2540 set_undefined(i); | 2681 set_undefined(i); |
| 2541 } | 2682 } |
| 2542 } | 2683 } |
| 2543 | 2684 |
| 2544 | 2685 |
| 2545 int NormalizedMapCache::Hash(Map* fast) { | |
| 2546 // For performance reasons we only hash the 3 most variable fields of a map: | |
| 2547 // constructor, prototype and bit_field2. | |
| 2548 | |
| 2549 // Shift away the tag. | |
| 2550 int hash = (static_cast<uint32_t>( | |
| 2551 reinterpret_cast<uintptr_t>(fast->constructor())) >> 2); | |
| 2552 | |
| 2553 // XOR-ing the prototype and constructor directly yields too many zero bits | |
| 2554 // when the two pointers are close (which is fairly common). | |
| 2555 // To avoid this we shift the prototype 4 bits relatively to the constructor. | |
| 2556 hash ^= (static_cast<uint32_t>( | |
| 2557 reinterpret_cast<uintptr_t>(fast->prototype())) << 2); | |
| 2558 | |
| 2559 return hash ^ (hash >> 16) ^ fast->bit_field2(); | |
| 2560 } | |
| 2561 | |
| 2562 | |
| 2563 bool NormalizedMapCache::CheckHit(Map* slow, | |
| 2564 Map* fast, | |
| 2565 PropertyNormalizationMode mode) { | |
| 2566 #ifdef DEBUG | |
| 2567 slow->SharedMapVerify(); | |
| 2568 #endif | |
| 2569 return | |
| 2570 slow->constructor() == fast->constructor() && | |
| 2571 slow->prototype() == fast->prototype() && | |
| 2572 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? | |
| 2573 0 : | |
| 2574 fast->inobject_properties()) && | |
| 2575 slow->instance_type() == fast->instance_type() && | |
| 2576 slow->bit_field() == fast->bit_field() && | |
| 2577 slow->bit_field2() == fast->bit_field2() && | |
| 2578 (slow->bit_field3() & ~(1<<Map::kIsShared)) == fast->bit_field3(); | |
| 2579 } | |
| 2580 | |
| 2581 | |
| 2582 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) { | 2686 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) { |
| 2583 if (map()->is_shared()) { | 2687 if (map()->is_shared()) { |
| 2584 // Fast case maps are never marked as shared. | 2688 // Fast case maps are never marked as shared. |
| 2585 ASSERT(!HasFastProperties()); | 2689 ASSERT(!HasFastProperties()); |
| 2586 // Replace the map with an identical copy that can be safely modified. | 2690 // Replace the map with an identical copy that can be safely modified. |
| 2587 Object* obj; | 2691 Object* obj; |
| 2588 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, | 2692 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, |
| 2589 UNIQUE_NORMALIZED_MAP); | 2693 UNIQUE_NORMALIZED_MAP); |
| 2590 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 2694 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 2591 } | 2695 } |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2720 MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) { | 2824 MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) { |
| 2721 if (HasFastProperties()) return this; | 2825 if (HasFastProperties()) return this; |
| 2722 ASSERT(!IsGlobalObject()); | 2826 ASSERT(!IsGlobalObject()); |
| 2723 return property_dictionary()-> | 2827 return property_dictionary()-> |
| 2724 TransformPropertiesToFastFor(this, unused_property_fields); | 2828 TransformPropertiesToFastFor(this, unused_property_fields); |
| 2725 } | 2829 } |
| 2726 | 2830 |
| 2727 | 2831 |
| 2728 MaybeObject* JSObject::NormalizeElements() { | 2832 MaybeObject* JSObject::NormalizeElements() { |
| 2729 ASSERT(!HasExternalArrayElements()); | 2833 ASSERT(!HasExternalArrayElements()); |
| 2730 if (HasDictionaryElements()) return this; | |
| 2731 Map* old_map = map(); | |
| 2732 ASSERT(old_map->has_fast_elements()); | |
| 2733 | 2834 |
| 2734 Object* obj; | 2835 // Find the backing store. |
| 2735 { MaybeObject* maybe_obj = old_map->GetSlowElementsMap(); | 2836 FixedArray* array = FixedArray::cast(elements()); |
| 2736 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 2837 Map* old_map = array->map(); |
| 2838 bool is_arguments = |
| 2839 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map()); |
| 2840 if (is_arguments) { |
| 2841 array = FixedArray::cast(array->get(1)); |
| 2737 } | 2842 } |
| 2738 Map* new_map = Map::cast(obj); | 2843 if (array->IsDictionary()) return array; |
| 2739 | 2844 |
| 2740 // Get number of entries. | 2845 ASSERT(HasFastElements() || HasFastArgumentsElements()); |
| 2741 FixedArray* array = FixedArray::cast(elements()); | 2846 // Compute the effective length and allocate a new backing store. |
| 2847 int length = IsJSArray() |
| 2848 ? Smi::cast(JSArray::cast(this)->length())->value() |
| 2849 : array->length(); |
| 2850 NumberDictionary* dictionary = NULL; |
| 2851 { Object* object; |
| 2852 MaybeObject* maybe = NumberDictionary::Allocate(length); |
| 2853 if (!maybe->ToObject(&object)) return maybe; |
| 2854 dictionary = NumberDictionary::cast(object); |
| 2855 } |
| 2742 | 2856 |
| 2743 // Compute the effective length. | 2857 // Copy the elements to the new backing store. |
| 2744 int length = IsJSArray() ? | 2858 bool has_double_elements = old_map->has_fast_double_elements(); |
| 2745 Smi::cast(JSArray::cast(this)->length())->value() : | |
| 2746 array->length(); | |
| 2747 { MaybeObject* maybe_obj = NumberDictionary::Allocate(length); | |
| 2748 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
| 2749 } | |
| 2750 NumberDictionary* dictionary = NumberDictionary::cast(obj); | |
| 2751 // Copy entries. | |
| 2752 for (int i = 0; i < length; i++) { | 2859 for (int i = 0; i < length; i++) { |
| 2753 Object* value = array->get(i); | 2860 Object* value = NULL; |
| 2861 if (has_double_elements) { |
| 2862 FixedDoubleArray* double_array = FixedDoubleArray::cast(array); |
| 2863 if (double_array->is_the_hole(i)) { |
| 2864 value = GetIsolate()->heap()->the_hole_value(); |
| 2865 } else { |
| 2866 // Objects must be allocated in the old object space, since the |
| 2867 // overall number of HeapNumbers needed for the conversion might |
| 2868 // exceed the capacity of new space, and we would fail repeatedly |
| 2869 // trying to convert the FixedDoubleArray. |
| 2870 MaybeObject* maybe_value_object = |
| 2871 GetHeap()->AllocateHeapNumber(double_array->get(i), TENURED); |
| 2872 if (!maybe_value_object->ToObject(&value)) return maybe_value_object; |
| 2873 } |
| 2874 } else { |
| 2875 ASSERT(old_map->has_fast_elements()); |
| 2876 value = array->get(i); |
| 2877 } |
| 2878 PropertyDetails details = PropertyDetails(NONE, NORMAL); |
| 2754 if (!value->IsTheHole()) { | 2879 if (!value->IsTheHole()) { |
| 2755 PropertyDetails details = PropertyDetails(NONE, NORMAL); | |
| 2756 Object* result; | 2880 Object* result; |
| 2757 { MaybeObject* maybe_result = | 2881 MaybeObject* maybe_result = |
| 2758 dictionary->AddNumberEntry(i, array->get(i), details); | 2882 dictionary->AddNumberEntry(i, value, details); |
| 2759 if (!maybe_result->ToObject(&result)) return maybe_result; | 2883 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2760 } | |
| 2761 dictionary = NumberDictionary::cast(result); | 2884 dictionary = NumberDictionary::cast(result); |
| 2762 } | 2885 } |
| 2763 } | 2886 } |
| 2764 // Switch to using the dictionary as the backing storage for | |
| 2765 // elements. Set the new map first to satify the elements type | |
| 2766 // assert in set_elements(). | |
| 2767 set_map(new_map); | |
| 2768 set_elements(dictionary); | |
| 2769 | 2887 |
| 2770 GetIsolate()->counters()->elements_to_dictionary()->Increment(); | 2888 // Switch to using the dictionary as the backing storage for elements. |
| 2889 if (is_arguments) { |
| 2890 FixedArray::cast(elements())->set(1, dictionary); |
| 2891 } else { |
| 2892 // Set the new map first to satify the elements type assert in |
| 2893 // set_elements(). |
| 2894 Object* new_map; |
| 2895 MaybeObject* maybe = map()->GetSlowElementsMap(); |
| 2896 if (!maybe->ToObject(&new_map)) return maybe; |
| 2897 set_map(Map::cast(new_map)); |
| 2898 set_elements(dictionary); |
| 2899 } |
| 2900 |
| 2901 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->Increment
(); |
| 2771 | 2902 |
| 2772 #ifdef DEBUG | 2903 #ifdef DEBUG |
| 2773 if (FLAG_trace_normalization) { | 2904 if (FLAG_trace_normalization) { |
| 2774 PrintF("Object elements have been normalized:\n"); | 2905 PrintF("Object elements have been normalized:\n"); |
| 2775 Print(); | 2906 Print(); |
| 2776 } | 2907 } |
| 2777 #endif | 2908 #endif |
| 2778 | 2909 |
| 2779 return this; | 2910 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
| 2911 return dictionary; |
| 2780 } | 2912 } |
| 2781 | 2913 |
| 2782 | 2914 |
| 2783 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, | 2915 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, |
| 2784 DeleteMode mode) { | 2916 DeleteMode mode) { |
| 2785 // Check local property, ignore interceptor. | 2917 // Check local property, ignore interceptor. |
| 2786 LookupResult result; | 2918 LookupResult result; |
| 2787 LocalLookupRealNamedProperty(name, &result); | 2919 LocalLookupRealNamedProperty(name, &result); |
| 2788 if (!result.IsProperty()) return GetHeap()->true_value(); | 2920 if (!result.IsProperty()) return GetHeap()->true_value(); |
| 2789 | 2921 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2843 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 2975 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
| 2844 if (index < length) { | 2976 if (index < length) { |
| 2845 FixedArray::cast(elements())->set_the_hole(index); | 2977 FixedArray::cast(elements())->set_the_hole(index); |
| 2846 } | 2978 } |
| 2847 break; | 2979 break; |
| 2848 } | 2980 } |
| 2849 case DICTIONARY_ELEMENTS: { | 2981 case DICTIONARY_ELEMENTS: { |
| 2850 NumberDictionary* dictionary = element_dictionary(); | 2982 NumberDictionary* dictionary = element_dictionary(); |
| 2851 int entry = dictionary->FindEntry(index); | 2983 int entry = dictionary->FindEntry(index); |
| 2852 if (entry != NumberDictionary::kNotFound) { | 2984 if (entry != NumberDictionary::kNotFound) { |
| 2853 return dictionary->DeleteProperty(entry, mode); | 2985 Object* deleted = dictionary->DeleteProperty(entry, mode); |
| 2986 if (deleted == GetHeap()->true_value()) { |
| 2987 MaybeObject* maybe_elements = dictionary->Shrink(index); |
| 2988 FixedArray* new_elements = NULL; |
| 2989 if (!maybe_elements->To(&new_elements)) { |
| 2990 return maybe_elements; |
| 2991 } |
| 2992 set_elements(new_elements); |
| 2993 } |
| 2994 return deleted; |
| 2854 } | 2995 } |
| 2855 break; | 2996 break; |
| 2856 } | 2997 } |
| 2857 default: | 2998 default: |
| 2858 UNREACHABLE(); | 2999 UNREACHABLE(); |
| 2859 break; | 3000 break; |
| 2860 } | 3001 } |
| 2861 return GetHeap()->true_value(); | 3002 return GetHeap()->true_value(); |
| 2862 } | 3003 } |
| 2863 | 3004 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2889 ASSERT(result->IsBoolean()); | 3030 ASSERT(result->IsBoolean()); |
| 2890 return *v8::Utils::OpenHandle(*result); | 3031 return *v8::Utils::OpenHandle(*result); |
| 2891 } | 3032 } |
| 2892 MaybeObject* raw_result = | 3033 MaybeObject* raw_result = |
| 2893 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION); | 3034 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION); |
| 2894 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 3035 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
| 2895 return raw_result; | 3036 return raw_result; |
| 2896 } | 3037 } |
| 2897 | 3038 |
| 2898 | 3039 |
| 3040 MaybeObject* JSObject::DeleteFastElement(uint32_t index) { |
| 3041 ASSERT(HasFastElements() || HasFastArgumentsElements()); |
| 3042 Heap* heap = GetHeap(); |
| 3043 FixedArray* backing_store = FixedArray::cast(elements()); |
| 3044 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { |
| 3045 backing_store = FixedArray::cast(backing_store->get(1)); |
| 3046 } else { |
| 3047 Object* writable; |
| 3048 MaybeObject* maybe = EnsureWritableFastElements(); |
| 3049 if (!maybe->ToObject(&writable)) return maybe; |
| 3050 backing_store = FixedArray::cast(writable); |
| 3051 } |
| 3052 uint32_t length = static_cast<uint32_t>( |
| 3053 IsJSArray() |
| 3054 ? Smi::cast(JSArray::cast(this)->length())->value() |
| 3055 : backing_store->length()); |
| 3056 if (index < length) { |
| 3057 backing_store->set_the_hole(index); |
| 3058 // If an old space backing store is larger than a certain size and |
| 3059 // has too few used values, normalize it. |
| 3060 // To avoid doing the check on every delete we require at least |
| 3061 // one adjacent hole to the value being deleted. |
| 3062 Object* hole = heap->the_hole_value(); |
| 3063 const int kMinLengthForSparsenessCheck = 64; |
| 3064 if (backing_store->length() >= kMinLengthForSparsenessCheck && |
| 3065 !heap->InNewSpace(backing_store) && |
| 3066 ((index > 0 && backing_store->get(index - 1) == hole) || |
| 3067 (index + 1 < length && backing_store->get(index + 1) == hole))) { |
| 3068 int num_used = 0; |
| 3069 for (int i = 0; i < backing_store->length(); ++i) { |
| 3070 if (backing_store->get(i) != hole) ++num_used; |
| 3071 // Bail out early if more than 1/4 is used. |
| 3072 if (4 * num_used > backing_store->length()) break; |
| 3073 } |
| 3074 if (4 * num_used <= backing_store->length()) { |
| 3075 MaybeObject* result = NormalizeElements(); |
| 3076 if (result->IsFailure()) return result; |
| 3077 } |
| 3078 } |
| 3079 } |
| 3080 return heap->true_value(); |
| 3081 } |
| 3082 |
| 3083 |
| 3084 MaybeObject* JSObject::DeleteDictionaryElement(uint32_t index, |
| 3085 DeleteMode mode) { |
| 3086 Isolate* isolate = GetIsolate(); |
| 3087 Heap* heap = isolate->heap(); |
| 3088 FixedArray* backing_store = FixedArray::cast(elements()); |
| 3089 bool is_arguments = |
| 3090 (GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS); |
| 3091 if (is_arguments) { |
| 3092 backing_store = FixedArray::cast(backing_store->get(1)); |
| 3093 } |
| 3094 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
| 3095 int entry = dictionary->FindEntry(index); |
| 3096 if (entry != NumberDictionary::kNotFound) { |
| 3097 Object* result = dictionary->DeleteProperty(entry, mode); |
| 3098 if (result == heap->true_value()) { |
| 3099 MaybeObject* maybe_elements = dictionary->Shrink(index); |
| 3100 FixedArray* new_elements = NULL; |
| 3101 if (!maybe_elements->To(&new_elements)) { |
| 3102 return maybe_elements; |
| 3103 } |
| 3104 if (is_arguments) { |
| 3105 FixedArray::cast(elements())->set(1, new_elements); |
| 3106 } else { |
| 3107 set_elements(new_elements); |
| 3108 } |
| 3109 } |
| 3110 if (mode == STRICT_DELETION && result == heap->false_value()) { |
| 3111 // In strict mode, attempting to delete a non-configurable property |
| 3112 // throws an exception. |
| 3113 HandleScope scope(isolate); |
| 3114 Handle<Object> holder(this); |
| 3115 Handle<Object> name = isolate->factory()->NewNumberFromUint(index); |
| 3116 Handle<Object> args[2] = { name, holder }; |
| 3117 Handle<Object> error = |
| 3118 isolate->factory()->NewTypeError("strict_delete_property", |
| 3119 HandleVector(args, 2)); |
| 3120 return isolate->Throw(*error); |
| 3121 } |
| 3122 } |
| 3123 return heap->true_value(); |
| 3124 } |
| 3125 |
| 3126 |
| 2899 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { | 3127 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { |
| 2900 Isolate* isolate = GetIsolate(); | 3128 Isolate* isolate = GetIsolate(); |
| 2901 // Check access rights if needed. | 3129 // Check access rights if needed. |
| 2902 if (IsAccessCheckNeeded() && | 3130 if (IsAccessCheckNeeded() && |
| 2903 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { | 3131 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { |
| 2904 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); | 3132 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); |
| 2905 return isolate->heap()->false_value(); | 3133 return isolate->heap()->false_value(); |
| 2906 } | 3134 } |
| 2907 | 3135 |
| 2908 if (IsJSGlobalProxy()) { | 3136 if (IsJSGlobalProxy()) { |
| 2909 Object* proto = GetPrototype(); | 3137 Object* proto = GetPrototype(); |
| 2910 if (proto->IsNull()) return isolate->heap()->false_value(); | 3138 if (proto->IsNull()) return isolate->heap()->false_value(); |
| 2911 ASSERT(proto->IsJSGlobalObject()); | 3139 ASSERT(proto->IsJSGlobalObject()); |
| 2912 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); | 3140 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); |
| 2913 } | 3141 } |
| 2914 | 3142 |
| 2915 if (HasIndexedInterceptor()) { | 3143 if (HasIndexedInterceptor()) { |
| 2916 // Skip interceptor if forcing deletion. | 3144 // Skip interceptor if forcing deletion. |
| 2917 if (mode == FORCE_DELETION) { | 3145 return (mode == FORCE_DELETION) |
| 2918 return DeleteElementPostInterceptor(index, mode); | 3146 ? DeleteElementPostInterceptor(index, FORCE_DELETION) |
| 2919 } | 3147 : DeleteElementWithInterceptor(index); |
| 2920 return DeleteElementWithInterceptor(index); | |
| 2921 } | 3148 } |
| 2922 | 3149 |
| 2923 switch (GetElementsKind()) { | 3150 switch (GetElementsKind()) { |
| 2924 case FAST_ELEMENTS: { | 3151 case FAST_ELEMENTS: |
| 2925 Object* obj; | 3152 return DeleteFastElement(index); |
| 2926 { MaybeObject* maybe_obj = EnsureWritableFastElements(); | 3153 |
| 2927 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 3154 case DICTIONARY_ELEMENTS: |
| 2928 } | 3155 return DeleteDictionaryElement(index, mode); |
| 2929 uint32_t length = IsJSArray() ? | 3156 |
| 2930 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : | 3157 case FAST_DOUBLE_ELEMENTS: { |
| 2931 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 3158 int length = IsJSArray() |
| 2932 if (index < length) { | 3159 ? Smi::cast(JSArray::cast(this)->length())->value() |
| 2933 FixedArray::cast(elements())->set_the_hole(index); | 3160 : FixedArray::cast(elements())->length(); |
| 3161 if (index < static_cast<uint32_t>(length)) { |
| 3162 FixedDoubleArray::cast(elements())->set_the_hole(index); |
| 2934 } | 3163 } |
| 2935 break; | 3164 break; |
| 2936 } | 3165 } |
| 2937 case EXTERNAL_PIXEL_ELEMENTS: | 3166 case EXTERNAL_PIXEL_ELEMENTS: |
| 2938 case EXTERNAL_BYTE_ELEMENTS: | 3167 case EXTERNAL_BYTE_ELEMENTS: |
| 2939 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 3168 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 2940 case EXTERNAL_SHORT_ELEMENTS: | 3169 case EXTERNAL_SHORT_ELEMENTS: |
| 2941 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3170 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 2942 case EXTERNAL_INT_ELEMENTS: | 3171 case EXTERNAL_INT_ELEMENTS: |
| 2943 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3172 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 2944 case EXTERNAL_FLOAT_ELEMENTS: | 3173 case EXTERNAL_FLOAT_ELEMENTS: |
| 2945 case EXTERNAL_DOUBLE_ELEMENTS: | 3174 case EXTERNAL_DOUBLE_ELEMENTS: |
| 2946 // Pixel and external array elements cannot be deleted. Just | 3175 // Pixel and external array elements cannot be deleted. Just |
| 2947 // silently ignore here. | 3176 // silently ignore here. |
| 2948 break; | 3177 break; |
| 2949 case DICTIONARY_ELEMENTS: { | 3178 |
| 2950 NumberDictionary* dictionary = element_dictionary(); | 3179 case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| 2951 int entry = dictionary->FindEntry(index); | 3180 FixedArray* parameter_map = FixedArray::cast(elements()); |
| 2952 if (entry != NumberDictionary::kNotFound) { | 3181 uint32_t length = parameter_map->length(); |
| 2953 Object* result = dictionary->DeleteProperty(entry, mode); | 3182 Object* probe = |
| 2954 if (mode == STRICT_DELETION && result == | 3183 index < (length - 2) ? parameter_map->get(index + 2) : NULL; |
| 2955 isolate->heap()->false_value()) { | 3184 if (probe != NULL && !probe->IsTheHole()) { |
| 2956 // In strict mode, deleting a non-configurable property throws | 3185 // TODO(kmillikin): We could check if this was the last aliased |
| 2957 // exception. dictionary->DeleteProperty will return false_value() | 3186 // parameter, and revert to normal elements in that case. That |
| 2958 // if a non-configurable property is being deleted. | 3187 // would enable GC of the context. |
| 2959 HandleScope scope; | 3188 parameter_map->set_the_hole(index + 2); |
| 2960 Handle<Object> self(this); | 3189 } else { |
| 2961 Handle<Object> i = isolate->factory()->NewNumberFromUint(index); | 3190 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 2962 Handle<Object> args[2] = { i, self }; | 3191 if (arguments->IsDictionary()) { |
| 2963 return isolate->Throw(*isolate->factory()->NewTypeError( | 3192 return DeleteDictionaryElement(index, mode); |
| 2964 "strict_delete_property", HandleVector(args, 2))); | 3193 } else { |
| 3194 return DeleteFastElement(index); |
| 2965 } | 3195 } |
| 2966 } | 3196 } |
| 2967 break; | 3197 break; |
| 2968 } | 3198 } |
| 2969 default: | |
| 2970 UNREACHABLE(); | |
| 2971 break; | |
| 2972 } | 3199 } |
| 2973 return isolate->heap()->true_value(); | 3200 return isolate->heap()->true_value(); |
| 2974 } | 3201 } |
| 2975 | 3202 |
| 2976 | 3203 |
| 2977 MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { | 3204 MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { |
| 2978 Isolate* isolate = GetIsolate(); | 3205 Isolate* isolate = GetIsolate(); |
| 2979 // ECMA-262, 3rd, 8.6.2.5 | 3206 // ECMA-262, 3rd, 8.6.2.5 |
| 2980 ASSERT(name->IsString()); | 3207 ASSERT(name->IsString()); |
| 2981 | 3208 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3024 { MaybeObject* maybe_obj = | 3251 { MaybeObject* maybe_obj = |
| 3025 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 3252 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 3026 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 3253 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 3027 } | 3254 } |
| 3028 // Make sure the properties are normalized before removing the entry. | 3255 // Make sure the properties are normalized before removing the entry. |
| 3029 return DeleteNormalizedProperty(name, mode); | 3256 return DeleteNormalizedProperty(name, mode); |
| 3030 } | 3257 } |
| 3031 } | 3258 } |
| 3032 | 3259 |
| 3033 | 3260 |
| 3261 bool JSObject::ReferencesObjectFromElements(FixedArray* elements, |
| 3262 ElementsKind kind, |
| 3263 Object* object) { |
| 3264 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS); |
| 3265 if (kind == FAST_ELEMENTS) { |
| 3266 int length = IsJSArray() |
| 3267 ? Smi::cast(JSArray::cast(this)->length())->value() |
| 3268 : elements->length(); |
| 3269 for (int i = 0; i < length; ++i) { |
| 3270 Object* element = elements->get(i); |
| 3271 if (!element->IsTheHole() && element == object) return true; |
| 3272 } |
| 3273 } else { |
| 3274 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object); |
| 3275 if (!key->IsUndefined()) return true; |
| 3276 } |
| 3277 return false; |
| 3278 } |
| 3279 |
| 3280 |
| 3034 // Check whether this object references another object. | 3281 // Check whether this object references another object. |
| 3035 bool JSObject::ReferencesObject(Object* obj) { | 3282 bool JSObject::ReferencesObject(Object* obj) { |
| 3036 Map* map_of_this = map(); | 3283 Map* map_of_this = map(); |
| 3037 Heap* heap = GetHeap(); | 3284 Heap* heap = GetHeap(); |
| 3038 AssertNoAllocation no_alloc; | 3285 AssertNoAllocation no_alloc; |
| 3039 | 3286 |
| 3040 // Is the object the constructor for this object? | 3287 // Is the object the constructor for this object? |
| 3041 if (map_of_this->constructor() == obj) { | 3288 if (map_of_this->constructor() == obj) { |
| 3042 return true; | 3289 return true; |
| 3043 } | 3290 } |
| 3044 | 3291 |
| 3045 // Is the object the prototype for this object? | 3292 // Is the object the prototype for this object? |
| 3046 if (map_of_this->prototype() == obj) { | 3293 if (map_of_this->prototype() == obj) { |
| 3047 return true; | 3294 return true; |
| 3048 } | 3295 } |
| 3049 | 3296 |
| 3050 // Check if the object is among the named properties. | 3297 // Check if the object is among the named properties. |
| 3051 Object* key = SlowReverseLookup(obj); | 3298 Object* key = SlowReverseLookup(obj); |
| 3052 if (!key->IsUndefined()) { | 3299 if (!key->IsUndefined()) { |
| 3053 return true; | 3300 return true; |
| 3054 } | 3301 } |
| 3055 | 3302 |
| 3056 // Check if the object is among the indexed properties. | 3303 // Check if the object is among the indexed properties. |
| 3057 switch (GetElementsKind()) { | 3304 ElementsKind kind = GetElementsKind(); |
| 3305 switch (kind) { |
| 3058 case EXTERNAL_PIXEL_ELEMENTS: | 3306 case EXTERNAL_PIXEL_ELEMENTS: |
| 3059 case EXTERNAL_BYTE_ELEMENTS: | 3307 case EXTERNAL_BYTE_ELEMENTS: |
| 3060 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 3308 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3061 case EXTERNAL_SHORT_ELEMENTS: | 3309 case EXTERNAL_SHORT_ELEMENTS: |
| 3062 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3310 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3063 case EXTERNAL_INT_ELEMENTS: | 3311 case EXTERNAL_INT_ELEMENTS: |
| 3064 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3312 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3065 case EXTERNAL_FLOAT_ELEMENTS: | 3313 case EXTERNAL_FLOAT_ELEMENTS: |
| 3066 case EXTERNAL_DOUBLE_ELEMENTS: | 3314 case EXTERNAL_DOUBLE_ELEMENTS: |
| 3315 case FAST_DOUBLE_ELEMENTS: |
| 3067 // Raw pixels and external arrays do not reference other | 3316 // Raw pixels and external arrays do not reference other |
| 3068 // objects. | 3317 // objects. |
| 3069 break; | 3318 break; |
| 3070 case FAST_ELEMENTS: { | 3319 case FAST_ELEMENTS: |
| 3071 int length = IsJSArray() ? | 3320 case DICTIONARY_ELEMENTS: { |
| 3072 Smi::cast(JSArray::cast(this)->length())->value() : | 3321 FixedArray* elements = FixedArray::cast(this->elements()); |
| 3073 FixedArray::cast(elements())->length(); | 3322 if (ReferencesObjectFromElements(elements, kind, obj)) return true; |
| 3074 for (int i = 0; i < length; i++) { | |
| 3075 Object* element = FixedArray::cast(elements())->get(i); | |
| 3076 if (!element->IsTheHole() && element == obj) { | |
| 3077 return true; | |
| 3078 } | |
| 3079 } | |
| 3080 break; | 3323 break; |
| 3081 } | 3324 } |
| 3082 case DICTIONARY_ELEMENTS: { | 3325 case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| 3083 key = element_dictionary()->SlowReverseLookup(obj); | 3326 FixedArray* parameter_map = FixedArray::cast(elements()); |
| 3084 if (!key->IsUndefined()) { | 3327 // Check the mapped parameters. |
| 3085 return true; | 3328 int length = parameter_map->length(); |
| 3329 for (int i = 2; i < length; ++i) { |
| 3330 Object* value = parameter_map->get(i); |
| 3331 if (!value->IsTheHole() && value == obj) return true; |
| 3086 } | 3332 } |
| 3333 // Check the arguments. |
| 3334 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 3335 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS; |
| 3336 if (ReferencesObjectFromElements(arguments, kind, obj)) return true; |
| 3087 break; | 3337 break; |
| 3088 } | 3338 } |
| 3089 default: | |
| 3090 UNREACHABLE(); | |
| 3091 break; | |
| 3092 } | 3339 } |
| 3093 | 3340 |
| 3094 // For functions check the context. | 3341 // For functions check the context. |
| 3095 if (IsJSFunction()) { | 3342 if (IsJSFunction()) { |
| 3096 // Get the constructor function for arguments array. | 3343 // Get the constructor function for arguments array. |
| 3097 JSObject* arguments_boilerplate = | 3344 JSObject* arguments_boilerplate = |
| 3098 heap->isolate()->context()->global_context()-> | 3345 heap->isolate()->context()->global_context()-> |
| 3099 arguments_boilerplate(); | 3346 arguments_boilerplate(); |
| 3100 JSFunction* arguments_function = | 3347 JSFunction* arguments_function = |
| 3101 JSFunction::cast(arguments_boilerplate->map()->constructor()); | 3348 JSFunction::cast(arguments_boilerplate->map()->constructor()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3116 if (ctxobj->map()->constructor() == arguments_function) { | 3363 if (ctxobj->map()->constructor() == arguments_function) { |
| 3117 if (ctxobj->ReferencesObject(obj)) { | 3364 if (ctxobj->ReferencesObject(obj)) { |
| 3118 return true; | 3365 return true; |
| 3119 } | 3366 } |
| 3120 } else if (ctxobj == obj) { | 3367 } else if (ctxobj == obj) { |
| 3121 return true; | 3368 return true; |
| 3122 } | 3369 } |
| 3123 } | 3370 } |
| 3124 } | 3371 } |
| 3125 | 3372 |
| 3126 // Check the context extension if any. | 3373 // Check the context extension (if any) if it can have references. |
| 3127 if (context->has_extension()) { | 3374 if (context->has_extension() && !context->IsCatchContext()) { |
| 3128 return context->extension()->ReferencesObject(obj); | 3375 return JSObject::cast(context->extension())->ReferencesObject(obj); |
| 3129 } | 3376 } |
| 3130 } | 3377 } |
| 3131 | 3378 |
| 3132 // No references to object. | 3379 // No references to object. |
| 3133 return false; | 3380 return false; |
| 3134 } | 3381 } |
| 3135 | 3382 |
| 3136 | 3383 |
| 3137 MaybeObject* JSObject::PreventExtensions() { | 3384 MaybeObject* JSObject::PreventExtensions() { |
| 3138 Isolate* isolate = GetIsolate(); | 3385 Isolate* isolate = GetIsolate(); |
| 3139 if (IsAccessCheckNeeded() && | 3386 if (IsAccessCheckNeeded() && |
| 3140 !isolate->MayNamedAccess(this, | 3387 !isolate->MayNamedAccess(this, |
| 3141 isolate->heap()->undefined_value(), | 3388 isolate->heap()->undefined_value(), |
| 3142 v8::ACCESS_KEYS)) { | 3389 v8::ACCESS_KEYS)) { |
| 3143 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS); | 3390 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS); |
| 3144 return isolate->heap()->false_value(); | 3391 return isolate->heap()->false_value(); |
| 3145 } | 3392 } |
| 3146 | 3393 |
| 3147 if (IsJSGlobalProxy()) { | 3394 if (IsJSGlobalProxy()) { |
| 3148 Object* proto = GetPrototype(); | 3395 Object* proto = GetPrototype(); |
| 3149 if (proto->IsNull()) return this; | 3396 if (proto->IsNull()) return this; |
| 3150 ASSERT(proto->IsJSGlobalObject()); | 3397 ASSERT(proto->IsJSGlobalObject()); |
| 3151 return JSObject::cast(proto)->PreventExtensions(); | 3398 return JSObject::cast(proto)->PreventExtensions(); |
| 3152 } | 3399 } |
| 3153 | 3400 |
| 3154 // If there are fast elements we normalize. | 3401 // If there are fast elements we normalize. |
| 3155 if (HasFastElements()) { | 3402 NumberDictionary* dictionary = NULL; |
| 3156 Object* ok; | 3403 { MaybeObject* maybe = NormalizeElements(); |
| 3157 { MaybeObject* maybe_ok = NormalizeElements(); | 3404 if (!maybe->To<NumberDictionary>(&dictionary)) return maybe; |
| 3158 if (!maybe_ok->ToObject(&ok)) return maybe_ok; | |
| 3159 } | |
| 3160 } | 3405 } |
| 3406 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
| 3161 // Make sure that we never go back to fast case. | 3407 // Make sure that we never go back to fast case. |
| 3162 element_dictionary()->set_requires_slow_elements(); | 3408 dictionary->set_requires_slow_elements(); |
| 3163 | 3409 |
| 3164 // Do a map transition, other objects with this map may still | 3410 // Do a map transition, other objects with this map may still |
| 3165 // be extensible. | 3411 // be extensible. |
| 3166 Object* new_map; | 3412 Map* new_map; |
| 3167 { MaybeObject* maybe_new_map = map()->CopyDropTransitions(); | 3413 { MaybeObject* maybe = map()->CopyDropTransitions(); |
| 3168 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 3414 if (!maybe->To<Map>(&new_map)) return maybe; |
| 3169 } | 3415 } |
| 3170 Map::cast(new_map)->set_is_extensible(false); | 3416 new_map->set_is_extensible(false); |
| 3171 set_map(Map::cast(new_map)); | 3417 set_map(new_map); |
| 3172 ASSERT(!map()->is_extensible()); | 3418 ASSERT(!map()->is_extensible()); |
| 3173 return new_map; | 3419 return new_map; |
| 3174 } | 3420 } |
| 3175 | 3421 |
| 3176 | 3422 |
| 3177 // Tests for the fast common case for property enumeration: | 3423 // Tests for the fast common case for property enumeration: |
| 3178 // - This object and all prototypes has an enum cache (which means that it has | 3424 // - This object and all prototypes has an enum cache (which means that it has |
| 3179 // no interceptors and needs no access checks). | 3425 // no interceptors and needs no access checks). |
| 3180 // - This object has no elements. | 3426 // - This object has no elements. |
| 3181 // - No prototype has enumerable properties/elements. | 3427 // - No prototype has enumerable properties/elements. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3238 DescriptorArray* descs = instance_descriptors(); | 3484 DescriptorArray* descs = instance_descriptors(); |
| 3239 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 3485 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 3240 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) { | 3486 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) { |
| 3241 return descs->GetCallbacks(i); | 3487 return descs->GetCallbacks(i); |
| 3242 } | 3488 } |
| 3243 } | 3489 } |
| 3244 return NULL; | 3490 return NULL; |
| 3245 } | 3491 } |
| 3246 | 3492 |
| 3247 | 3493 |
| 3494 void JSReceiver::LocalLookup(String* name, LookupResult* result) { |
| 3495 if (IsJSProxy()) { |
| 3496 result->HandlerResult(); |
| 3497 } else { |
| 3498 JSObject::cast(this)->LocalLookup(name, result); |
| 3499 } |
| 3500 } |
| 3501 |
| 3502 |
| 3248 void JSObject::LocalLookup(String* name, LookupResult* result) { | 3503 void JSObject::LocalLookup(String* name, LookupResult* result) { |
| 3249 ASSERT(name->IsString()); | 3504 ASSERT(name->IsString()); |
| 3250 | 3505 |
| 3251 Heap* heap = GetHeap(); | 3506 Heap* heap = GetHeap(); |
| 3252 | 3507 |
| 3253 if (IsJSGlobalProxy()) { | 3508 if (IsJSGlobalProxy()) { |
| 3254 Object* proto = GetPrototype(); | 3509 Object* proto = GetPrototype(); |
| 3255 if (proto->IsNull()) return result->NotFound(); | 3510 if (proto->IsNull()) return result->NotFound(); |
| 3256 ASSERT(proto->IsJSGlobalObject()); | 3511 ASSERT(proto->IsJSGlobalObject()); |
| 3257 return JSObject::cast(proto)->LocalLookup(name, result); | 3512 return JSObject::cast(proto)->LocalLookup(name, result); |
| 3258 } | 3513 } |
| 3259 | 3514 |
| 3260 // Do not use inline caching if the object is a non-global object | 3515 // Do not use inline caching if the object is a non-global object |
| 3261 // that requires access checks. | 3516 // that requires access checks. |
| 3262 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) { | 3517 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) { |
| 3263 result->DisallowCaching(); | 3518 result->DisallowCaching(); |
| 3264 } | 3519 } |
| 3265 | 3520 |
| 3266 // Check __proto__ before interceptor. | 3521 // Check __proto__ before interceptor. |
| 3267 if (name->Equals(heap->Proto_symbol()) && | 3522 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) { |
| 3268 !IsJSContextExtensionObject()) { | |
| 3269 result->ConstantResult(this); | 3523 result->ConstantResult(this); |
| 3270 return; | 3524 return; |
| 3271 } | 3525 } |
| 3272 | 3526 |
| 3273 // Check for lookup interceptor except when bootstrapping. | 3527 // Check for lookup interceptor except when bootstrapping. |
| 3274 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) { | 3528 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) { |
| 3275 result->InterceptorResult(this); | 3529 result->InterceptorResult(this); |
| 3276 return; | 3530 return; |
| 3277 } | 3531 } |
| 3278 | 3532 |
| 3279 LocalLookupRealNamedProperty(name, result); | 3533 LocalLookupRealNamedProperty(name, result); |
| 3280 } | 3534 } |
| 3281 | 3535 |
| 3282 | 3536 |
| 3283 void JSObject::Lookup(String* name, LookupResult* result) { | 3537 void JSReceiver::Lookup(String* name, LookupResult* result) { |
| 3284 // Ecma-262 3rd 8.6.2.4 | 3538 // Ecma-262 3rd 8.6.2.4 |
| 3285 Heap* heap = GetHeap(); | 3539 Heap* heap = GetHeap(); |
| 3286 for (Object* current = this; | 3540 for (Object* current = this; |
| 3287 current != heap->null_value(); | 3541 current != heap->null_value(); |
| 3288 current = JSObject::cast(current)->GetPrototype()) { | 3542 current = JSObject::cast(current)->GetPrototype()) { |
| 3289 JSObject::cast(current)->LocalLookup(name, result); | 3543 JSObject::cast(current)->LocalLookup(name, result); |
| 3290 if (result->IsProperty()) return; | 3544 if (result->IsProperty()) return; |
| 3291 } | 3545 } |
| 3292 result->NotFound(); | 3546 result->NotFound(); |
| 3293 } | 3547 } |
| 3294 | 3548 |
| 3295 | 3549 |
| 3296 // Search object and it's prototype chain for callback properties. | 3550 // Search object and it's prototype chain for callback properties. |
| 3297 void JSObject::LookupCallback(String* name, LookupResult* result) { | 3551 void JSObject::LookupCallback(String* name, LookupResult* result) { |
| 3298 Heap* heap = GetHeap(); | 3552 Heap* heap = GetHeap(); |
| 3299 for (Object* current = this; | 3553 for (Object* current = this; |
| 3300 current != heap->null_value(); | 3554 current != heap->null_value(); |
| 3301 current = JSObject::cast(current)->GetPrototype()) { | 3555 current = JSObject::cast(current)->GetPrototype()) { |
| 3302 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); | 3556 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); |
| 3303 if (result->IsProperty() && result->type() == CALLBACKS) return; | 3557 if (result->IsProperty() && result->type() == CALLBACKS) return; |
| 3304 } | 3558 } |
| 3305 result->NotFound(); | 3559 result->NotFound(); |
| 3306 } | 3560 } |
| 3307 | 3561 |
| 3308 | 3562 |
| 3563 // Search for a getter or setter in an elements dictionary. Returns either |
| 3564 // undefined if the element is read-only, or the getter/setter pair (fixed |
| 3565 // array) if there is an existing one, or the hole value if the element does |
| 3566 // not exist or is a normal non-getter/setter data element. |
| 3567 static Object* FindGetterSetterInDictionary(NumberDictionary* dictionary, |
| 3568 uint32_t index, |
| 3569 Heap* heap) { |
| 3570 int entry = dictionary->FindEntry(index); |
| 3571 if (entry != NumberDictionary::kNotFound) { |
| 3572 Object* result = dictionary->ValueAt(entry); |
| 3573 PropertyDetails details = dictionary->DetailsAt(entry); |
| 3574 if (details.IsReadOnly()) return heap->undefined_value(); |
| 3575 if (details.type() == CALLBACKS && result->IsFixedArray()) return result; |
| 3576 } |
| 3577 return heap->the_hole_value(); |
| 3578 } |
| 3579 |
| 3580 |
| 3309 MaybeObject* JSObject::DefineGetterSetter(String* name, | 3581 MaybeObject* JSObject::DefineGetterSetter(String* name, |
| 3310 PropertyAttributes attributes) { | 3582 PropertyAttributes attributes) { |
| 3311 Heap* heap = GetHeap(); | 3583 Heap* heap = GetHeap(); |
| 3312 // Make sure that the top context does not change when doing callbacks or | 3584 // Make sure that the top context does not change when doing callbacks or |
| 3313 // interceptor calls. | 3585 // interceptor calls. |
| 3314 AssertNoContextChange ncc; | 3586 AssertNoContextChange ncc; |
| 3315 | 3587 |
| 3316 // Try to flatten before operating on the string. | 3588 // Try to flatten before operating on the string. |
| 3317 name->TryFlatten(); | 3589 name->TryFlatten(); |
| 3318 | 3590 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3329 break; | 3601 break; |
| 3330 case EXTERNAL_PIXEL_ELEMENTS: | 3602 case EXTERNAL_PIXEL_ELEMENTS: |
| 3331 case EXTERNAL_BYTE_ELEMENTS: | 3603 case EXTERNAL_BYTE_ELEMENTS: |
| 3332 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 3604 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3333 case EXTERNAL_SHORT_ELEMENTS: | 3605 case EXTERNAL_SHORT_ELEMENTS: |
| 3334 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3606 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3335 case EXTERNAL_INT_ELEMENTS: | 3607 case EXTERNAL_INT_ELEMENTS: |
| 3336 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3608 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3337 case EXTERNAL_FLOAT_ELEMENTS: | 3609 case EXTERNAL_FLOAT_ELEMENTS: |
| 3338 case EXTERNAL_DOUBLE_ELEMENTS: | 3610 case EXTERNAL_DOUBLE_ELEMENTS: |
| 3611 case FAST_DOUBLE_ELEMENTS: |
| 3339 // Ignore getters and setters on pixel and external array | 3612 // Ignore getters and setters on pixel and external array |
| 3340 // elements. | 3613 // elements. |
| 3341 return heap->undefined_value(); | 3614 return heap->undefined_value(); |
| 3342 case DICTIONARY_ELEMENTS: { | 3615 case DICTIONARY_ELEMENTS: { |
| 3343 // Lookup the index. | 3616 Object* probe = |
| 3344 NumberDictionary* dictionary = element_dictionary(); | 3617 FindGetterSetterInDictionary(element_dictionary(), index, heap); |
| 3345 int entry = dictionary->FindEntry(index); | 3618 if (!probe->IsTheHole()) return probe; |
| 3346 if (entry != NumberDictionary::kNotFound) { | 3619 // Otherwise allow to override it. |
| 3347 Object* result = dictionary->ValueAt(entry); | 3620 break; |
| 3348 PropertyDetails details = dictionary->DetailsAt(entry); | 3621 } |
| 3349 if (details.IsReadOnly()) return heap->undefined_value(); | 3622 case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| 3350 if (details.type() == CALLBACKS) { | 3623 // Ascertain whether we have read-only properties or an existing |
| 3351 if (result->IsFixedArray()) { | 3624 // getter/setter pair in an arguments elements dictionary backing |
| 3352 return result; | 3625 // store. |
| 3353 } | 3626 FixedArray* parameter_map = FixedArray::cast(elements()); |
| 3354 // Otherwise allow to override it. | 3627 uint32_t length = parameter_map->length(); |
| 3628 Object* probe = |
| 3629 index < (length - 2) ? parameter_map->get(index + 2) : NULL; |
| 3630 if (probe == NULL || probe->IsTheHole()) { |
| 3631 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 3632 if (arguments->IsDictionary()) { |
| 3633 NumberDictionary* dictionary = NumberDictionary::cast(arguments); |
| 3634 probe = FindGetterSetterInDictionary(dictionary, index, heap); |
| 3635 if (!probe->IsTheHole()) return probe; |
| 3355 } | 3636 } |
| 3356 } | 3637 } |
| 3357 break; | 3638 break; |
| 3358 } | 3639 } |
| 3359 default: | |
| 3360 UNREACHABLE(); | |
| 3361 break; | |
| 3362 } | 3640 } |
| 3363 } else { | 3641 } else { |
| 3364 // Lookup the name. | 3642 // Lookup the name. |
| 3365 LookupResult result; | 3643 LookupResult result; |
| 3366 LocalLookup(name, &result); | 3644 LocalLookup(name, &result); |
| 3367 if (result.IsProperty()) { | 3645 if (result.IsProperty()) { |
| 3368 if (result.IsReadOnly()) return heap->undefined_value(); | 3646 if (result.IsReadOnly()) return heap->undefined_value(); |
| 3369 if (result.type() == CALLBACKS) { | 3647 if (result.type() == CALLBACKS) { |
| 3370 Object* obj = result.GetCallbackObject(); | 3648 Object* obj = result.GetCallbackObject(); |
| 3371 // Need to preserve old getters/setters. | 3649 // Need to preserve old getters/setters. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3414 return true; | 3692 return true; |
| 3415 } | 3693 } |
| 3416 | 3694 |
| 3417 | 3695 |
| 3418 MaybeObject* JSObject::SetElementCallback(uint32_t index, | 3696 MaybeObject* JSObject::SetElementCallback(uint32_t index, |
| 3419 Object* structure, | 3697 Object* structure, |
| 3420 PropertyAttributes attributes) { | 3698 PropertyAttributes attributes) { |
| 3421 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); | 3699 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); |
| 3422 | 3700 |
| 3423 // Normalize elements to make this operation simple. | 3701 // Normalize elements to make this operation simple. |
| 3424 Object* ok; | 3702 NumberDictionary* dictionary = NULL; |
| 3425 { MaybeObject* maybe_ok = NormalizeElements(); | 3703 { Object* result; |
| 3426 if (!maybe_ok->ToObject(&ok)) return maybe_ok; | 3704 MaybeObject* maybe = NormalizeElements(); |
| 3705 if (!maybe->ToObject(&result)) return maybe; |
| 3706 dictionary = NumberDictionary::cast(result); |
| 3707 } |
| 3708 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
| 3709 |
| 3710 // Update the dictionary with the new CALLBACKS property. |
| 3711 { Object* result; |
| 3712 MaybeObject* maybe = dictionary->Set(index, structure, details); |
| 3713 if (!maybe->ToObject(&result)) return maybe; |
| 3714 dictionary = NumberDictionary::cast(result); |
| 3427 } | 3715 } |
| 3428 | 3716 |
| 3429 // Update the dictionary with the new CALLBACKS property. | 3717 dictionary->set_requires_slow_elements(); |
| 3430 Object* dict; | 3718 // Update the dictionary backing store on the object. |
| 3431 { MaybeObject* maybe_dict = | 3719 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) { |
| 3432 element_dictionary()->Set(index, structure, details); | 3720 // Also delete any parameter alias. |
| 3433 if (!maybe_dict->ToObject(&dict)) return maybe_dict; | 3721 // |
| 3722 // TODO(kmillikin): when deleting the last parameter alias we could |
| 3723 // switch to a direct backing store without the parameter map. This |
| 3724 // would allow GC of the context. |
| 3725 FixedArray* parameter_map = FixedArray::cast(elements()); |
| 3726 uint32_t length = parameter_map->length(); |
| 3727 if (index < length - 2) { |
| 3728 parameter_map->set(index + 2, GetHeap()->the_hole_value()); |
| 3729 } |
| 3730 parameter_map->set(1, dictionary); |
| 3731 } else { |
| 3732 set_elements(dictionary); |
| 3434 } | 3733 } |
| 3435 | 3734 |
| 3436 NumberDictionary* elements = NumberDictionary::cast(dict); | |
| 3437 elements->set_requires_slow_elements(); | |
| 3438 // Set the potential new dictionary on the object. | |
| 3439 set_elements(elements); | |
| 3440 | |
| 3441 return structure; | 3735 return structure; |
| 3442 } | 3736 } |
| 3443 | 3737 |
| 3444 | 3738 |
| 3445 MaybeObject* JSObject::SetPropertyCallback(String* name, | 3739 MaybeObject* JSObject::SetPropertyCallback(String* name, |
| 3446 Object* structure, | 3740 Object* structure, |
| 3447 PropertyAttributes attributes) { | 3741 PropertyAttributes attributes) { |
| 3448 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); | 3742 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); |
| 3449 | 3743 |
| 3450 bool convert_back_to_fast = HasFastProperties() && | 3744 bool convert_back_to_fast = HasFastProperties() && |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3556 break; | 3850 break; |
| 3557 case EXTERNAL_PIXEL_ELEMENTS: | 3851 case EXTERNAL_PIXEL_ELEMENTS: |
| 3558 case EXTERNAL_BYTE_ELEMENTS: | 3852 case EXTERNAL_BYTE_ELEMENTS: |
| 3559 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 3853 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3560 case EXTERNAL_SHORT_ELEMENTS: | 3854 case EXTERNAL_SHORT_ELEMENTS: |
| 3561 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3855 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3562 case EXTERNAL_INT_ELEMENTS: | 3856 case EXTERNAL_INT_ELEMENTS: |
| 3563 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3857 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3564 case EXTERNAL_FLOAT_ELEMENTS: | 3858 case EXTERNAL_FLOAT_ELEMENTS: |
| 3565 case EXTERNAL_DOUBLE_ELEMENTS: | 3859 case EXTERNAL_DOUBLE_ELEMENTS: |
| 3860 case FAST_DOUBLE_ELEMENTS: |
| 3566 // Ignore getters and setters on pixel and external array | 3861 // Ignore getters and setters on pixel and external array |
| 3567 // elements. | 3862 // elements. |
| 3568 return isolate->heap()->undefined_value(); | 3863 return isolate->heap()->undefined_value(); |
| 3569 case DICTIONARY_ELEMENTS: | 3864 case DICTIONARY_ELEMENTS: |
| 3570 break; | 3865 break; |
| 3571 default: | 3866 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 3572 UNREACHABLE(); | 3867 UNIMPLEMENTED(); |
| 3573 break; | 3868 break; |
| 3574 } | 3869 } |
| 3575 | 3870 |
| 3576 Object* ok; | 3871 Object* ok; |
| 3577 { MaybeObject* maybe_ok = | 3872 { MaybeObject* maybe_ok = |
| 3578 SetElementCallback(index, info, info->property_attributes()); | 3873 SetElementCallback(index, info, info->property_attributes()); |
| 3579 if (!maybe_ok->ToObject(&ok)) return maybe_ok; | 3874 if (!maybe_ok->ToObject(&ok)) return maybe_ok; |
| 3580 } | 3875 } |
| 3581 } else { | 3876 } else { |
| 3582 // Lookup the name. | 3877 // Lookup the name. |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3806 | 4101 |
| 3807 void Map::RemoveFromCodeCache(String* name, Code* code, int index) { | 4102 void Map::RemoveFromCodeCache(String* name, Code* code, int index) { |
| 3808 // No GC is supposed to happen between a call to IndexInCodeCache and | 4103 // No GC is supposed to happen between a call to IndexInCodeCache and |
| 3809 // RemoveFromCodeCache so the code cache must be there. | 4104 // RemoveFromCodeCache so the code cache must be there. |
| 3810 ASSERT(!code_cache()->IsFixedArray()); | 4105 ASSERT(!code_cache()->IsFixedArray()); |
| 3811 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); | 4106 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); |
| 3812 } | 4107 } |
| 3813 | 4108 |
| 3814 | 4109 |
| 3815 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { | 4110 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { |
| 4111 // Traverse the transition tree without using a stack. We do this by |
| 4112 // reversing the pointers in the maps and descriptor arrays. |
| 3816 Map* current = this; | 4113 Map* current = this; |
| 3817 Map* meta_map = GetHeap()->meta_map(); | 4114 Map* meta_map = GetHeap()->meta_map(); |
| 4115 Object** map_or_index_field = NULL; |
| 3818 while (current != meta_map) { | 4116 while (current != meta_map) { |
| 3819 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( | 4117 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( |
| 3820 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); | 4118 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); |
| 3821 if (d->IsEmpty()) { | 4119 if (!d->IsEmpty()) { |
| 3822 Map* prev = current->map(); | 4120 FixedArray* contents = reinterpret_cast<FixedArray*>( |
| 3823 current->set_map(meta_map); | 4121 d->get(DescriptorArray::kContentArrayIndex)); |
| 3824 callback(current, data); | 4122 map_or_index_field = RawField(contents, HeapObject::kMapOffset); |
| 3825 current = prev; | 4123 Object* map_or_index = *map_or_index_field; |
| 3826 continue; | 4124 bool map_done = true; // Controls a nested continue statement. |
| 4125 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0; |
| 4126 i < contents->length(); |
| 4127 i += 2) { |
| 4128 PropertyDetails details(Smi::cast(contents->get(i + 1))); |
| 4129 if (details.IsTransition()) { |
| 4130 // Found a map in the transition array. We record our progress in |
| 4131 // the transition array by recording the current map in the map field |
| 4132 // of the next map and recording the index in the transition array in |
| 4133 // the map field of the array. |
| 4134 Map* next = Map::cast(contents->get(i)); |
| 4135 next->set_map(current); |
| 4136 *map_or_index_field = Smi::FromInt(i + 2); |
| 4137 current = next; |
| 4138 map_done = false; |
| 4139 break; |
| 4140 } |
| 4141 } |
| 4142 if (!map_done) continue; |
| 4143 } else { |
| 4144 map_or_index_field = NULL; |
| 4145 } |
| 4146 // That was the regular transitions, now for the prototype transitions. |
| 4147 FixedArray* prototype_transitions = |
| 4148 current->unchecked_prototype_transitions(); |
| 4149 Object** proto_map_or_index_field = |
| 4150 RawField(prototype_transitions, HeapObject::kMapOffset); |
| 4151 Object* map_or_index = *proto_map_or_index_field; |
| 4152 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; |
| 4153 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start; |
| 4154 if (i < prototype_transitions->length()) { |
| 4155 // Found a map in the prototype transition array. Record progress in |
| 4156 // an analogous way to the regular transitions array above. |
| 4157 Object* perhaps_map = prototype_transitions->get(i); |
| 4158 if (perhaps_map->IsMap()) { |
| 4159 Map* next = Map::cast(perhaps_map); |
| 4160 next->set_map(current); |
| 4161 *proto_map_or_index_field = |
| 4162 Smi::FromInt(i + kProtoTransitionElementsPerEntry); |
| 4163 current = next; |
| 4164 continue; |
| 4165 } |
| 4166 } |
| 4167 *proto_map_or_index_field = GetHeap()->fixed_array_map(); |
| 4168 if (map_or_index_field != NULL) { |
| 4169 *map_or_index_field = GetHeap()->fixed_array_map(); |
| 3827 } | 4170 } |
| 3828 | 4171 |
| 3829 FixedArray* contents = reinterpret_cast<FixedArray*>( | 4172 // The callback expects a map to have a real map as its map, so we save |
| 3830 d->get(DescriptorArray::kContentArrayIndex)); | 4173 // the map field, which is being used to track the traversal and put the |
| 3831 Object** map_or_index_field = RawField(contents, HeapObject::kMapOffset); | 4174 // correct map (the meta_map) in place while we do the callback. |
| 3832 Object* map_or_index = *map_or_index_field; | |
| 3833 bool map_done = true; | |
| 3834 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0; | |
| 3835 i < contents->length(); | |
| 3836 i += 2) { | |
| 3837 PropertyDetails details(Smi::cast(contents->get(i + 1))); | |
| 3838 if (details.IsTransition()) { | |
| 3839 Map* next = reinterpret_cast<Map*>(contents->get(i)); | |
| 3840 next->set_map(current); | |
| 3841 *map_or_index_field = Smi::FromInt(i + 2); | |
| 3842 current = next; | |
| 3843 map_done = false; | |
| 3844 break; | |
| 3845 } | |
| 3846 } | |
| 3847 if (!map_done) continue; | |
| 3848 *map_or_index_field = GetHeap()->fixed_array_map(); | |
| 3849 Map* prev = current->map(); | 4175 Map* prev = current->map(); |
| 3850 current->set_map(meta_map); | 4176 current->set_map(meta_map); |
| 3851 callback(current, data); | 4177 callback(current, data); |
| 3852 current = prev; | 4178 current = prev; |
| 3853 } | 4179 } |
| 3854 } | 4180 } |
| 3855 | 4181 |
| 3856 | 4182 |
| 3857 MaybeObject* CodeCache::Update(String* name, Code* code) { | 4183 MaybeObject* CodeCache::Update(String* name, Code* code) { |
| 3858 // The number of monomorphic stubs for normal load/store/call IC's can grow to | 4184 // The number of monomorphic stubs for normal load/store/call IC's can grow to |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4068 } | 4394 } |
| 4069 FixedArray* pair = FixedArray::cast(obj); | 4395 FixedArray* pair = FixedArray::cast(obj); |
| 4070 pair->set(0, name_); | 4396 pair->set(0, name_); |
| 4071 pair->set(1, code_); | 4397 pair->set(1, code_); |
| 4072 return pair; | 4398 return pair; |
| 4073 } | 4399 } |
| 4074 | 4400 |
| 4075 private: | 4401 private: |
| 4076 String* name_; | 4402 String* name_; |
| 4077 Code::Flags flags_; | 4403 Code::Flags flags_; |
| 4404 // TODO(jkummerow): We should be able to get by without this. |
| 4078 Code* code_; | 4405 Code* code_; |
| 4079 }; | 4406 }; |
| 4080 | 4407 |
| 4081 | 4408 |
| 4082 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { | 4409 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { |
| 4083 CodeCacheHashTableKey key(name, flags); | 4410 CodeCacheHashTableKey key(name, flags); |
| 4084 int entry = FindEntry(&key); | 4411 int entry = FindEntry(&key); |
| 4085 if (entry == kNotFound) return GetHeap()->undefined_value(); | 4412 if (entry == kNotFound) return GetHeap()->undefined_value(); |
| 4086 return get(EntryToIndex(entry) + 1); | 4413 return get(EntryToIndex(entry) + 1); |
| 4087 } | 4414 } |
| 4088 | 4415 |
| 4089 | 4416 |
| 4090 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) { | 4417 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) { |
| 4091 CodeCacheHashTableKey key(name, code); | 4418 CodeCacheHashTableKey key(name, code); |
| 4092 Object* obj; | 4419 Object* obj; |
| 4093 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); | 4420 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); |
| 4094 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 4421 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 4095 } | 4422 } |
| 4096 | 4423 |
| 4097 // Don't use this, as the table might have grown. | 4424 // Don't use |this|, as the table might have grown. |
| 4098 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); | 4425 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); |
| 4099 | 4426 |
| 4100 int entry = cache->FindInsertionEntry(key.Hash()); | 4427 int entry = cache->FindInsertionEntry(key.Hash()); |
| 4101 Object* k; | 4428 Object* k; |
| 4102 { MaybeObject* maybe_k = key.AsObject(); | 4429 { MaybeObject* maybe_k = key.AsObject(); |
| 4103 if (!maybe_k->ToObject(&k)) return maybe_k; | 4430 if (!maybe_k->ToObject(&k)) return maybe_k; |
| 4104 } | 4431 } |
| 4105 | 4432 |
| 4106 cache->set(EntryToIndex(entry), k); | 4433 cache->set(EntryToIndex(entry), k); |
| 4107 cache->set(EntryToIndex(entry) + 1, code); | 4434 cache->set(EntryToIndex(entry) + 1, code); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 4133 if (element->IsSmi() && key->IsSmi() && (element == key)) return true; | 4460 if (element->IsSmi() && key->IsSmi() && (element == key)) return true; |
| 4134 if (element->IsString() && | 4461 if (element->IsString() && |
| 4135 key->IsString() && String::cast(element)->Equals(String::cast(key))) { | 4462 key->IsString() && String::cast(element)->Equals(String::cast(key))) { |
| 4136 return true; | 4463 return true; |
| 4137 } | 4464 } |
| 4138 } | 4465 } |
| 4139 return false; | 4466 return false; |
| 4140 } | 4467 } |
| 4141 | 4468 |
| 4142 | 4469 |
| 4470 MaybeObject* PolymorphicCodeCache::Update(MapList* maps, |
| 4471 Code::Flags flags, |
| 4472 Code* code) { |
| 4473 // Initialize cache if necessary. |
| 4474 if (cache()->IsUndefined()) { |
| 4475 Object* result; |
| 4476 { MaybeObject* maybe_result = |
| 4477 PolymorphicCodeCacheHashTable::Allocate( |
| 4478 PolymorphicCodeCacheHashTable::kInitialSize); |
| 4479 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 4480 } |
| 4481 set_cache(result); |
| 4482 } else { |
| 4483 // This entry shouldn't be contained in the cache yet. |
| 4484 ASSERT(PolymorphicCodeCacheHashTable::cast(cache()) |
| 4485 ->Lookup(maps, flags)->IsUndefined()); |
| 4486 } |
| 4487 PolymorphicCodeCacheHashTable* hash_table = |
| 4488 PolymorphicCodeCacheHashTable::cast(cache()); |
| 4489 Object* new_cache; |
| 4490 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code); |
| 4491 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache; |
| 4492 } |
| 4493 set_cache(new_cache); |
| 4494 return this; |
| 4495 } |
| 4496 |
| 4497 |
| 4498 Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) { |
| 4499 if (!cache()->IsUndefined()) { |
| 4500 PolymorphicCodeCacheHashTable* hash_table = |
| 4501 PolymorphicCodeCacheHashTable::cast(cache()); |
| 4502 return hash_table->Lookup(maps, flags); |
| 4503 } else { |
| 4504 return GetHeap()->undefined_value(); |
| 4505 } |
| 4506 } |
| 4507 |
| 4508 |
| 4509 // Despite their name, object of this class are not stored in the actual |
| 4510 // hash table; instead they're temporarily used for lookups. It is therefore |
| 4511 // safe to have a weak (non-owning) pointer to a MapList as a member field. |
| 4512 class PolymorphicCodeCacheHashTableKey : public HashTableKey { |
| 4513 public: |
| 4514 // Callers must ensure that |maps| outlives the newly constructed object. |
| 4515 PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags) |
| 4516 : maps_(maps), |
| 4517 code_flags_(code_flags) {} |
| 4518 |
| 4519 bool IsMatch(Object* other) { |
| 4520 MapList other_maps(kDefaultListAllocationSize); |
| 4521 int other_flags; |
| 4522 FromObject(other, &other_flags, &other_maps); |
| 4523 if (code_flags_ != other_flags) return false; |
| 4524 if (maps_->length() != other_maps.length()) return false; |
| 4525 // Compare just the hashes first because it's faster. |
| 4526 int this_hash = MapsHashHelper(maps_, code_flags_); |
| 4527 int other_hash = MapsHashHelper(&other_maps, other_flags); |
| 4528 if (this_hash != other_hash) return false; |
| 4529 |
| 4530 // Full comparison: for each map in maps_, look for an equivalent map in |
| 4531 // other_maps. This implementation is slow, but probably good enough for |
| 4532 // now because the lists are short (<= 4 elements currently). |
| 4533 for (int i = 0; i < maps_->length(); ++i) { |
| 4534 bool match_found = false; |
| 4535 for (int j = 0; j < other_maps.length(); ++j) { |
| 4536 if (maps_->at(i)->EquivalentTo(other_maps.at(j))) { |
| 4537 match_found = true; |
| 4538 break; |
| 4539 } |
| 4540 } |
| 4541 if (!match_found) return false; |
| 4542 } |
| 4543 return true; |
| 4544 } |
| 4545 |
| 4546 static uint32_t MapsHashHelper(MapList* maps, int code_flags) { |
| 4547 uint32_t hash = code_flags; |
| 4548 for (int i = 0; i < maps->length(); ++i) { |
| 4549 hash ^= maps->at(i)->Hash(); |
| 4550 } |
| 4551 return hash; |
| 4552 } |
| 4553 |
| 4554 uint32_t Hash() { |
| 4555 return MapsHashHelper(maps_, code_flags_); |
| 4556 } |
| 4557 |
| 4558 uint32_t HashForObject(Object* obj) { |
| 4559 MapList other_maps(kDefaultListAllocationSize); |
| 4560 int other_flags; |
| 4561 FromObject(obj, &other_flags, &other_maps); |
| 4562 return MapsHashHelper(&other_maps, other_flags); |
| 4563 } |
| 4564 |
| 4565 MUST_USE_RESULT MaybeObject* AsObject() { |
| 4566 Object* obj; |
| 4567 // The maps in |maps_| must be copied to a newly allocated FixedArray, |
| 4568 // both because the referenced MapList is short-lived, and because C++ |
| 4569 // objects can't be stored in the heap anyway. |
| 4570 { MaybeObject* maybe_obj = |
| 4571 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1); |
| 4572 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 4573 } |
| 4574 FixedArray* list = FixedArray::cast(obj); |
| 4575 list->set(0, Smi::FromInt(code_flags_)); |
| 4576 for (int i = 0; i < maps_->length(); ++i) { |
| 4577 list->set(i + 1, maps_->at(i)); |
| 4578 } |
| 4579 return list; |
| 4580 } |
| 4581 |
| 4582 private: |
| 4583 static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) { |
| 4584 FixedArray* list = FixedArray::cast(obj); |
| 4585 maps->Rewind(0); |
| 4586 *code_flags = Smi::cast(list->get(0))->value(); |
| 4587 for (int i = 1; i < list->length(); ++i) { |
| 4588 maps->Add(Map::cast(list->get(i))); |
| 4589 } |
| 4590 return maps; |
| 4591 } |
| 4592 |
| 4593 MapList* maps_; // weak. |
| 4594 int code_flags_; |
| 4595 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1; |
| 4596 }; |
| 4597 |
| 4598 |
| 4599 Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) { |
| 4600 PolymorphicCodeCacheHashTableKey key(maps, code_flags); |
| 4601 int entry = FindEntry(&key); |
| 4602 if (entry == kNotFound) return GetHeap()->undefined_value(); |
| 4603 return get(EntryToIndex(entry) + 1); |
| 4604 } |
| 4605 |
| 4606 |
| 4607 MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps, |
| 4608 int code_flags, |
| 4609 Code* code) { |
| 4610 PolymorphicCodeCacheHashTableKey key(maps, code_flags); |
| 4611 Object* obj; |
| 4612 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); |
| 4613 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 4614 } |
| 4615 PolymorphicCodeCacheHashTable* cache = |
| 4616 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj); |
| 4617 int entry = cache->FindInsertionEntry(key.Hash()); |
| 4618 { MaybeObject* maybe_obj = key.AsObject(); |
| 4619 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 4620 } |
| 4621 cache->set(EntryToIndex(entry), obj); |
| 4622 cache->set(EntryToIndex(entry) + 1, code); |
| 4623 cache->ElementAdded(); |
| 4624 return cache; |
| 4625 } |
| 4626 |
| 4627 |
| 4143 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { | 4628 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { |
| 4144 ASSERT(!array->HasExternalArrayElements()); | 4629 ASSERT(!array->HasExternalArrayElements()); |
| 4145 switch (array->GetElementsKind()) { | 4630 switch (array->GetElementsKind()) { |
| 4146 case JSObject::FAST_ELEMENTS: | 4631 case JSObject::FAST_ELEMENTS: |
| 4147 return UnionOfKeys(FixedArray::cast(array->elements())); | 4632 return UnionOfKeys(FixedArray::cast(array->elements())); |
| 4148 case JSObject::DICTIONARY_ELEMENTS: { | 4633 case JSObject::DICTIONARY_ELEMENTS: { |
| 4149 NumberDictionary* dict = array->element_dictionary(); | 4634 NumberDictionary* dict = array->element_dictionary(); |
| 4150 int size = dict->NumberOfElements(); | 4635 int size = dict->NumberOfElements(); |
| 4151 | 4636 |
| 4152 // Allocate a temporary fixed array. | 4637 // Allocate a temporary fixed array. |
| 4153 Object* object; | 4638 Object* object; |
| 4154 { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size); | 4639 { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size); |
| 4155 if (!maybe_object->ToObject(&object)) return maybe_object; | 4640 if (!maybe_object->ToObject(&object)) return maybe_object; |
| 4156 } | 4641 } |
| 4157 FixedArray* key_array = FixedArray::cast(object); | 4642 FixedArray* key_array = FixedArray::cast(object); |
| 4158 | 4643 |
| 4159 int capacity = dict->Capacity(); | 4644 int capacity = dict->Capacity(); |
| 4160 int pos = 0; | 4645 int pos = 0; |
| 4161 // Copy the elements from the JSArray to the temporary fixed array. | 4646 // Copy the elements from the JSArray to the temporary fixed array. |
| 4162 for (int i = 0; i < capacity; i++) { | 4647 for (int i = 0; i < capacity; i++) { |
| 4163 if (dict->IsKey(dict->KeyAt(i))) { | 4648 if (dict->IsKey(dict->KeyAt(i))) { |
| 4164 key_array->set(pos++, dict->ValueAt(i)); | 4649 key_array->set(pos++, dict->ValueAt(i)); |
| 4165 } | 4650 } |
| 4166 } | 4651 } |
| 4167 // Compute the union of this and the temporary fixed array. | 4652 // Compute the union of this and the temporary fixed array. |
| 4168 return UnionOfKeys(key_array); | 4653 return UnionOfKeys(key_array); |
| 4169 } | 4654 } |
| 4170 default: | 4655 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS: |
| 4171 UNREACHABLE(); | 4656 UNIMPLEMENTED(); |
| 4657 break; |
| 4658 case JSObject::EXTERNAL_BYTE_ELEMENTS: |
| 4659 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 4660 case JSObject::EXTERNAL_SHORT_ELEMENTS: |
| 4661 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 4662 case JSObject::EXTERNAL_INT_ELEMENTS: |
| 4663 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 4664 case JSObject::EXTERNAL_FLOAT_ELEMENTS: |
| 4665 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: |
| 4666 case JSObject::EXTERNAL_PIXEL_ELEMENTS: |
| 4667 case JSObject::FAST_DOUBLE_ELEMENTS: |
| 4668 break; |
| 4172 } | 4669 } |
| 4173 UNREACHABLE(); | 4670 UNREACHABLE(); |
| 4174 return GetHeap()->null_value(); // Failure case needs to "return" a value. | 4671 return GetHeap()->null_value(); // Failure case needs to "return" a value. |
| 4175 } | 4672 } |
| 4176 | 4673 |
| 4177 | 4674 |
| 4178 MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) { | 4675 MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) { |
| 4179 int len0 = length(); | 4676 int len0 = length(); |
| 4180 #ifdef DEBUG | 4677 #ifdef DEBUG |
| 4181 if (FLAG_enable_slow_asserts) { | 4678 if (FLAG_enable_slow_asserts) { |
| (...skipping 1362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5544 uc32 r = decoder->GetNext(); | 6041 uc32 r = decoder->GetNext(); |
| 5545 if (Get(i) != r) return false; | 6042 if (Get(i) != r) return false; |
| 5546 } | 6043 } |
| 5547 return i == slen && !decoder->has_more(); | 6044 return i == slen && !decoder->has_more(); |
| 5548 } | 6045 } |
| 5549 | 6046 |
| 5550 | 6047 |
| 5551 bool String::IsAsciiEqualTo(Vector<const char> str) { | 6048 bool String::IsAsciiEqualTo(Vector<const char> str) { |
| 5552 int slen = length(); | 6049 int slen = length(); |
| 5553 if (str.length() != slen) return false; | 6050 if (str.length() != slen) return false; |
| 5554 if (this->IsSeqAsciiString()) { | 6051 if (IsFlat() && IsAsciiRepresentation()) { |
| 5555 SeqAsciiString* seq = SeqAsciiString::cast(this); | 6052 return CompareChars(ToAsciiVector().start(), str.start(), slen) == 0; |
| 5556 char* ch = seq->GetChars(); | 6053 } |
| 5557 for (int i = 0; i < slen; i++, ch++) { | 6054 for (int i = 0; i < slen; i++) { |
| 5558 if (*ch != str[i]) return false; | 6055 if (Get(i) != static_cast<uint16_t>(str[i])) return false; |
| 5559 } | |
| 5560 } else { | |
| 5561 for (int i = 0; i < slen; i++) { | |
| 5562 if (Get(i) != static_cast<uint16_t>(str[i])) return false; | |
| 5563 } | |
| 5564 } | 6056 } |
| 5565 return true; | 6057 return true; |
| 5566 } | 6058 } |
| 5567 | 6059 |
| 5568 | 6060 |
| 5569 bool String::IsTwoByteEqualTo(Vector<const uc16> str) { | 6061 bool String::IsTwoByteEqualTo(Vector<const uc16> str) { |
| 5570 int slen = length(); | 6062 int slen = length(); |
| 5571 if (str.length() != slen) return false; | 6063 if (str.length() != slen) return false; |
| 6064 if (IsFlat() && IsTwoByteRepresentation()) { |
| 6065 return CompareChars(ToUC16Vector().start(), str.start(), slen) == 0; |
| 6066 } |
| 5572 for (int i = 0; i < slen; i++) { | 6067 for (int i = 0; i < slen; i++) { |
| 5573 if (Get(i) != str[i]) return false; | 6068 if (Get(i) != str[i]) return false; |
| 5574 } | 6069 } |
| 5575 return true; | 6070 return true; |
| 5576 } | 6071 } |
| 5577 | 6072 |
| 5578 | 6073 |
| 5579 uint32_t String::ComputeAndSetHash() { | 6074 uint32_t String::ComputeAndSetHash() { |
| 5580 // Should only be called if hash code has not yet been computed. | 6075 // Should only be called if hash code has not yet been computed. |
| 5581 ASSERT(!HasHashCode()); | 6076 ASSERT(!HasHashCode()); |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5781 ASSERT(target->prototype() == this || | 6276 ASSERT(target->prototype() == this || |
| 5782 target->prototype() == real_prototype); | 6277 target->prototype() == real_prototype); |
| 5783 // Getter prototype() is read-only, set_prototype() has side effects. | 6278 // Getter prototype() is read-only, set_prototype() has side effects. |
| 5784 *RawField(target, Map::kPrototypeOffset) = real_prototype; | 6279 *RawField(target, Map::kPrototypeOffset) = real_prototype; |
| 5785 } | 6280 } |
| 5786 } | 6281 } |
| 5787 } | 6282 } |
| 5788 } | 6283 } |
| 5789 | 6284 |
| 5790 | 6285 |
| 6286 int Map::Hash() { |
| 6287 // For performance reasons we only hash the 3 most variable fields of a map: |
| 6288 // constructor, prototype and bit_field2. |
| 6289 |
| 6290 // Shift away the tag. |
| 6291 int hash = (static_cast<uint32_t>( |
| 6292 reinterpret_cast<uintptr_t>(constructor())) >> 2); |
| 6293 |
| 6294 // XOR-ing the prototype and constructor directly yields too many zero bits |
| 6295 // when the two pointers are close (which is fairly common). |
| 6296 // To avoid this we shift the prototype 4 bits relatively to the constructor. |
| 6297 hash ^= (static_cast<uint32_t>( |
| 6298 reinterpret_cast<uintptr_t>(prototype())) << 2); |
| 6299 |
| 6300 return hash ^ (hash >> 16) ^ bit_field2(); |
| 6301 } |
| 6302 |
| 6303 |
| 6304 bool Map::EquivalentToForNormalization(Map* other, |
| 6305 PropertyNormalizationMode mode) { |
| 6306 return |
| 6307 constructor() == other->constructor() && |
| 6308 prototype() == other->prototype() && |
| 6309 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? |
| 6310 0 : |
| 6311 other->inobject_properties()) && |
| 6312 instance_type() == other->instance_type() && |
| 6313 bit_field() == other->bit_field() && |
| 6314 bit_field2() == other->bit_field2() && |
| 6315 (bit_field3() & ~(1<<Map::kIsShared)) == |
| 6316 (other->bit_field3() & ~(1<<Map::kIsShared)); |
| 6317 } |
| 6318 |
| 6319 |
| 5791 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { | 6320 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { |
| 5792 // Iterate over all fields in the body but take care in dealing with | 6321 // Iterate over all fields in the body but take care in dealing with |
| 5793 // the code entry. | 6322 // the code entry. |
| 5794 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); | 6323 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); |
| 5795 v->VisitCodeEntry(this->address() + kCodeEntryOffset); | 6324 v->VisitCodeEntry(this->address() + kCodeEntryOffset); |
| 5796 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); | 6325 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); |
| 5797 } | 6326 } |
| 5798 | 6327 |
| 5799 | 6328 |
| 5800 void JSFunction::MarkForLazyRecompilation() { | 6329 void JSFunction::MarkForLazyRecompilation() { |
| 5801 ASSERT(is_compiled() && !IsOptimized()); | 6330 ASSERT(is_compiled() && !IsOptimized()); |
| 5802 ASSERT(shared()->allows_lazy_compilation() || | 6331 ASSERT(shared()->allows_lazy_compilation() || |
| 5803 code()->optimizable()); | 6332 code()->optimizable()); |
| 5804 Builtins* builtins = GetIsolate()->builtins(); | 6333 Builtins* builtins = GetIsolate()->builtins(); |
| 5805 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile)); | 6334 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile)); |
| 5806 } | 6335 } |
| 5807 | 6336 |
| 5808 | 6337 |
| 5809 uint32_t JSFunction::SourceHash() { | |
| 5810 uint32_t hash = 0; | |
| 5811 Object* script = shared()->script(); | |
| 5812 if (!script->IsUndefined()) { | |
| 5813 Object* source = Script::cast(script)->source(); | |
| 5814 if (source->IsUndefined()) hash = String::cast(source)->Hash(); | |
| 5815 } | |
| 5816 hash ^= ComputeIntegerHash(shared()->start_position_and_type()); | |
| 5817 hash += ComputeIntegerHash(shared()->end_position()); | |
| 5818 return hash; | |
| 5819 } | |
| 5820 | |
| 5821 | |
| 5822 bool JSFunction::IsInlineable() { | 6338 bool JSFunction::IsInlineable() { |
| 5823 if (IsBuiltin()) return false; | 6339 if (IsBuiltin()) return false; |
| 5824 SharedFunctionInfo* shared_info = shared(); | 6340 SharedFunctionInfo* shared_info = shared(); |
| 5825 // Check that the function has a script associated with it. | 6341 // Check that the function has a script associated with it. |
| 5826 if (!shared_info->script()->IsScript()) return false; | 6342 if (!shared_info->script()->IsScript()) return false; |
| 5827 if (shared_info->optimization_disabled()) return false; | 6343 if (shared_info->optimization_disabled()) return false; |
| 5828 Code* code = shared_info->code(); | 6344 Code* code = shared_info->code(); |
| 5829 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true; | 6345 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true; |
| 5830 // If we never ran this (unlikely) then lets try to optimize it. | 6346 // If we never ran this (unlikely) then lets try to optimize it. |
| 5831 if (code->kind() != Code::FUNCTION) return true; | 6347 if (code->kind() != Code::FUNCTION) return true; |
| (...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6280 Builtins* builtins = heap->isolate()->builtins(); | 6796 Builtins* builtins = heap->isolate()->builtins(); |
| 6281 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), | 6797 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), |
| 6282 construct_stub()); | 6798 construct_stub()); |
| 6283 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); | 6799 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); |
| 6284 | 6800 |
| 6285 int slack = map->unused_property_fields(); | 6801 int slack = map->unused_property_fields(); |
| 6286 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack); | 6802 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack); |
| 6287 if (slack != 0) { | 6803 if (slack != 0) { |
| 6288 // Resize the initial map and all maps in its transition tree. | 6804 // Resize the initial map and all maps in its transition tree. |
| 6289 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack); | 6805 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack); |
| 6806 |
| 6290 // Give the correct expected_nof_properties to initial maps created later. | 6807 // Give the correct expected_nof_properties to initial maps created later. |
| 6291 ASSERT(expected_nof_properties() >= slack); | 6808 ASSERT(expected_nof_properties() >= slack); |
| 6292 set_expected_nof_properties(expected_nof_properties() - slack); | 6809 set_expected_nof_properties(expected_nof_properties() - slack); |
| 6293 } | 6810 } |
| 6294 } | 6811 } |
| 6295 | 6812 |
| 6296 | 6813 |
| 6297 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { | 6814 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { |
| 6298 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); | 6815 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); |
| 6299 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); | 6816 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6464 RelocInfo* info = it.rinfo(); | 6981 RelocInfo* info = it.rinfo(); |
| 6465 Object* object = info->target_object(); | 6982 Object* object = info->target_object(); |
| 6466 if (object->IsMap()) return Map::cast(object); | 6983 if (object->IsMap()) return Map::cast(object); |
| 6467 } | 6984 } |
| 6468 return NULL; | 6985 return NULL; |
| 6469 } | 6986 } |
| 6470 | 6987 |
| 6471 | 6988 |
| 6472 #ifdef ENABLE_DISASSEMBLER | 6989 #ifdef ENABLE_DISASSEMBLER |
| 6473 | 6990 |
| 6474 #ifdef OBJECT_PRINT | |
| 6475 | |
| 6476 void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { | 6991 void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) { |
| 6477 disasm::NameConverter converter; | 6992 disasm::NameConverter converter; |
| 6478 int deopt_count = DeoptCount(); | 6993 int deopt_count = DeoptCount(); |
| 6479 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count); | 6994 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count); |
| 6480 if (0 == deopt_count) return; | 6995 if (0 == deopt_count) return; |
| 6481 | 6996 |
| 6482 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands"); | 6997 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands"); |
| 6483 for (int i = 0; i < deopt_count; i++) { | 6998 for (int i = 0; i < deopt_count; i++) { |
| 6484 int command_count = 0; | 6999 int command_count = 0; |
| 6485 PrintF(out, "%6d %6d %6d", | 7000 PrintF(out, "%6d %6d %6d", |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6612 for (int i = 0; i < this->DeoptPoints(); i++) { | 7127 for (int i = 0; i < this->DeoptPoints(); i++) { |
| 6613 int pc_and_state = this->PcAndState(i)->value(); | 7128 int pc_and_state = this->PcAndState(i)->value(); |
| 6614 PrintF("%6d %8d %s\n", | 7129 PrintF("%6d %8d %s\n", |
| 6615 this->AstId(i)->value(), | 7130 this->AstId(i)->value(), |
| 6616 FullCodeGenerator::PcField::decode(pc_and_state), | 7131 FullCodeGenerator::PcField::decode(pc_and_state), |
| 6617 FullCodeGenerator::State2String( | 7132 FullCodeGenerator::State2String( |
| 6618 FullCodeGenerator::StateField::decode(pc_and_state))); | 7133 FullCodeGenerator::StateField::decode(pc_and_state))); |
| 6619 } | 7134 } |
| 6620 } | 7135 } |
| 6621 | 7136 |
| 6622 #endif | |
| 6623 | |
| 6624 | 7137 |
| 6625 // Identify kind of code. | 7138 // Identify kind of code. |
| 6626 const char* Code::Kind2String(Kind kind) { | 7139 const char* Code::Kind2String(Kind kind) { |
| 6627 switch (kind) { | 7140 switch (kind) { |
| 6628 case FUNCTION: return "FUNCTION"; | 7141 case FUNCTION: return "FUNCTION"; |
| 6629 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION"; | 7142 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION"; |
| 6630 case STUB: return "STUB"; | 7143 case STUB: return "STUB"; |
| 6631 case BUILTIN: return "BUILTIN"; | 7144 case BUILTIN: return "BUILTIN"; |
| 6632 case LOAD_IC: return "LOAD_IC"; | 7145 case LOAD_IC: return "LOAD_IC"; |
| 6633 case KEYED_LOAD_IC: return "KEYED_LOAD_IC"; | 7146 case KEYED_LOAD_IC: return "KEYED_LOAD_IC"; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6690 if (extra == kStrictMode) { | 7203 if (extra == kStrictMode) { |
| 6691 name = "STRICT"; | 7204 name = "STRICT"; |
| 6692 } | 7205 } |
| 6693 break; | 7206 break; |
| 6694 default: | 7207 default: |
| 6695 break; | 7208 break; |
| 6696 } | 7209 } |
| 6697 if (name != NULL) { | 7210 if (name != NULL) { |
| 6698 PrintF(out, "extra_ic_state = %s\n", name); | 7211 PrintF(out, "extra_ic_state = %s\n", name); |
| 6699 } else { | 7212 } else { |
| 6700 PrintF(out, "etra_ic_state = %d\n", extra); | 7213 PrintF(out, "extra_ic_state = %d\n", extra); |
| 6701 } | 7214 } |
| 6702 } | 7215 } |
| 6703 | 7216 |
| 6704 | 7217 |
| 6705 void Code::Disassemble(const char* name, FILE* out) { | 7218 void Code::Disassemble(const char* name, FILE* out) { |
| 6706 PrintF(out, "kind = %s\n", Kind2String(kind())); | 7219 PrintF(out, "kind = %s\n", Kind2String(kind())); |
| 6707 if (is_inline_cache_stub()) { | 7220 if (is_inline_cache_stub()) { |
| 6708 PrintF(out, "ic_state = %s\n", ICState2String(ic_state())); | 7221 PrintF(out, "ic_state = %s\n", ICState2String(ic_state())); |
| 6709 PrintExtraICState(out, kind(), extra_ic_state()); | 7222 PrintExtraICState(out, kind(), extra_ic_state()); |
| 6710 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP); | 7223 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP); |
| 6711 if (ic_state() == MONOMORPHIC) { | 7224 if (ic_state() == MONOMORPHIC) { |
| 6712 PrintF(out, "type = %s\n", PropertyType2String(type())); | 7225 PrintF(out, "type = %s\n", PropertyType2String(type())); |
| 6713 } | 7226 } |
| 7227 if (is_call_stub() || is_keyed_call_stub()) { |
| 7228 PrintF(out, "argc = %d\n", arguments_count()); |
| 7229 } |
| 6714 } | 7230 } |
| 6715 if ((name != NULL) && (name[0] != '\0')) { | 7231 if ((name != NULL) && (name[0] != '\0')) { |
| 6716 PrintF(out, "name = %s\n", name); | 7232 PrintF(out, "name = %s\n", name); |
| 6717 } | 7233 } |
| 6718 if (kind() == OPTIMIZED_FUNCTION) { | 7234 if (kind() == OPTIMIZED_FUNCTION) { |
| 6719 PrintF(out, "stack_slots = %d\n", stack_slots()); | 7235 PrintF(out, "stack_slots = %d\n", stack_slots()); |
| 6720 } | 7236 } |
| 6721 | 7237 |
| 6722 PrintF(out, "Instructions (size = %d)\n", instruction_size()); | 7238 PrintF(out, "Instructions (size = %d)\n", instruction_size()); |
| 6723 Disassembler::Decode(out, this); | 7239 Disassembler::Decode(out, this); |
| 6724 PrintF(out, "\n"); | 7240 PrintF(out, "\n"); |
| 6725 | 7241 |
| 6726 #ifdef DEBUG | |
| 6727 if (kind() == FUNCTION) { | 7242 if (kind() == FUNCTION) { |
| 6728 DeoptimizationOutputData* data = | 7243 DeoptimizationOutputData* data = |
| 6729 DeoptimizationOutputData::cast(this->deoptimization_data()); | 7244 DeoptimizationOutputData::cast(this->deoptimization_data()); |
| 6730 data->DeoptimizationOutputDataPrint(out); | 7245 data->DeoptimizationOutputDataPrint(out); |
| 6731 } else if (kind() == OPTIMIZED_FUNCTION) { | 7246 } else if (kind() == OPTIMIZED_FUNCTION) { |
| 6732 DeoptimizationInputData* data = | 7247 DeoptimizationInputData* data = |
| 6733 DeoptimizationInputData::cast(this->deoptimization_data()); | 7248 DeoptimizationInputData::cast(this->deoptimization_data()); |
| 6734 data->DeoptimizationInputDataPrint(out); | 7249 data->DeoptimizationInputDataPrint(out); |
| 6735 } | 7250 } |
| 6736 PrintF("\n"); | 7251 PrintF("\n"); |
| 6737 #endif | |
| 6738 | 7252 |
| 6739 if (kind() == OPTIMIZED_FUNCTION) { | 7253 if (kind() == OPTIMIZED_FUNCTION) { |
| 6740 SafepointTable table(this); | 7254 SafepointTable table(this); |
| 6741 PrintF(out, "Safepoints (size = %u)\n", table.size()); | 7255 PrintF(out, "Safepoints (size = %u)\n", table.size()); |
| 6742 for (unsigned i = 0; i < table.length(); i++) { | 7256 for (unsigned i = 0; i < table.length(); i++) { |
| 6743 unsigned pc_offset = table.GetPcOffset(i); | 7257 unsigned pc_offset = table.GetPcOffset(i); |
| 6744 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset); | 7258 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset); |
| 6745 table.PrintEntry(i); | 7259 table.PrintEntry(i); |
| 6746 PrintF(out, " (sp -> fp)"); | 7260 PrintF(out, " (sp -> fp)"); |
| 6747 SafepointEntry entry = table.GetEntry(i); | 7261 SafepointEntry entry = table.GetEntry(i); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 6774 } | 7288 } |
| 6775 } | 7289 } |
| 6776 | 7290 |
| 6777 PrintF("RelocInfo (size = %d)\n", relocation_size()); | 7291 PrintF("RelocInfo (size = %d)\n", relocation_size()); |
| 6778 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out); | 7292 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out); |
| 6779 PrintF(out, "\n"); | 7293 PrintF(out, "\n"); |
| 6780 } | 7294 } |
| 6781 #endif // ENABLE_DISASSEMBLER | 7295 #endif // ENABLE_DISASSEMBLER |
| 6782 | 7296 |
| 6783 | 7297 |
| 7298 static void CopyFastElementsToFast(FixedArray* source, |
| 7299 FixedArray* destination, |
| 7300 WriteBarrierMode mode) { |
| 7301 uint32_t count = static_cast<uint32_t>(source->length()); |
| 7302 for (uint32_t i = 0; i < count; ++i) { |
| 7303 destination->set(i, source->get(i), mode); |
| 7304 } |
| 7305 } |
| 7306 |
| 7307 |
| 7308 static void CopySlowElementsToFast(NumberDictionary* source, |
| 7309 FixedArray* destination, |
| 7310 WriteBarrierMode mode) { |
| 7311 for (int i = 0; i < source->Capacity(); ++i) { |
| 7312 Object* key = source->KeyAt(i); |
| 7313 if (key->IsNumber()) { |
| 7314 uint32_t entry = static_cast<uint32_t>(key->Number()); |
| 7315 destination->set(entry, source->ValueAt(i), mode); |
| 7316 } |
| 7317 } |
| 7318 } |
| 7319 |
| 7320 |
| 6784 MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, | 7321 MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, |
| 6785 int length) { | 7322 int length) { |
| 6786 Heap* heap = GetHeap(); | 7323 Heap* heap = GetHeap(); |
| 6787 // We should never end in here with a pixel or external array. | 7324 // We should never end in here with a pixel or external array. |
| 6788 ASSERT(!HasExternalArrayElements()); | 7325 ASSERT(!HasExternalArrayElements()); |
| 6789 | 7326 |
| 7327 // Allocate a new fast elements backing store. |
| 7328 FixedArray* new_elements = NULL; |
| 7329 { Object* object; |
| 7330 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity); |
| 7331 if (!maybe->ToObject(&object)) return maybe; |
| 7332 new_elements = FixedArray::cast(object); |
| 7333 } |
| 7334 |
| 7335 // Find the new map to use for this object if there is a map change. |
| 7336 Map* new_map = NULL; |
| 7337 if (elements()->map() != heap->non_strict_arguments_elements_map()) { |
| 7338 Object* object; |
| 7339 MaybeObject* maybe = map()->GetFastElementsMap(); |
| 7340 if (!maybe->ToObject(&object)) return maybe; |
| 7341 new_map = Map::cast(object); |
| 7342 } |
| 7343 |
| 7344 AssertNoAllocation no_gc; |
| 7345 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc); |
| 7346 switch (GetElementsKind()) { |
| 7347 case FAST_ELEMENTS: |
| 7348 CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode); |
| 7349 set_map(new_map); |
| 7350 set_elements(new_elements); |
| 7351 break; |
| 7352 case DICTIONARY_ELEMENTS: |
| 7353 CopySlowElementsToFast(NumberDictionary::cast(elements()), |
| 7354 new_elements, |
| 7355 mode); |
| 7356 set_map(new_map); |
| 7357 set_elements(new_elements); |
| 7358 break; |
| 7359 case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| 7360 // The object's map and the parameter map are unchanged, the unaliased |
| 7361 // arguments are copied to the new backing store. |
| 7362 FixedArray* parameter_map = FixedArray::cast(elements()); |
| 7363 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 7364 if (arguments->IsDictionary()) { |
| 7365 CopySlowElementsToFast(NumberDictionary::cast(arguments), |
| 7366 new_elements, |
| 7367 mode); |
| 7368 } else { |
| 7369 CopyFastElementsToFast(arguments, new_elements, mode); |
| 7370 } |
| 7371 parameter_map->set(1, new_elements); |
| 7372 break; |
| 7373 } |
| 7374 case FAST_DOUBLE_ELEMENTS: { |
| 7375 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements()); |
| 7376 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); |
| 7377 // Fill out the new array with this content and array holes. |
| 7378 for (uint32_t i = 0; i < old_length; i++) { |
| 7379 if (!old_elements->is_the_hole(i)) { |
| 7380 Object* obj; |
| 7381 // Objects must be allocated in the old object space, since the |
| 7382 // overall number of HeapNumbers needed for the conversion might |
| 7383 // exceed the capacity of new space, and we would fail repeatedly |
| 7384 // trying to convert the FixedDoubleArray. |
| 7385 MaybeObject* maybe_value_object = |
| 7386 GetHeap()->AllocateHeapNumber(old_elements->get(i), TENURED); |
| 7387 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object; |
| 7388 // Force write barrier. It's not worth trying to exploit |
| 7389 // elems->GetWriteBarrierMode(), since it requires an |
| 7390 // AssertNoAllocation stack object that would have to be positioned |
| 7391 // after the HeapNumber allocation anyway. |
| 7392 new_elements->set(i, obj, UPDATE_WRITE_BARRIER); |
| 7393 } |
| 7394 } |
| 7395 break; |
| 7396 } |
| 7397 case EXTERNAL_BYTE_ELEMENTS: |
| 7398 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 7399 case EXTERNAL_SHORT_ELEMENTS: |
| 7400 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 7401 case EXTERNAL_INT_ELEMENTS: |
| 7402 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7403 case EXTERNAL_FLOAT_ELEMENTS: |
| 7404 case EXTERNAL_DOUBLE_ELEMENTS: |
| 7405 case EXTERNAL_PIXEL_ELEMENTS: |
| 7406 UNREACHABLE(); |
| 7407 break; |
| 7408 } |
| 7409 |
| 7410 // Update the length if necessary. |
| 7411 if (IsJSArray()) { |
| 7412 JSArray::cast(this)->set_length(Smi::FromInt(length)); |
| 7413 } |
| 7414 |
| 7415 return new_elements; |
| 7416 } |
| 7417 |
| 7418 |
| 7419 MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( |
| 7420 int capacity, |
| 7421 int length) { |
| 7422 Heap* heap = GetHeap(); |
| 7423 // We should never end in here with a pixel or external array. |
| 7424 ASSERT(!HasExternalArrayElements()); |
| 7425 |
| 6790 Object* obj; | 7426 Object* obj; |
| 6791 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity); | 7427 { MaybeObject* maybe_obj = |
| 7428 heap->AllocateUninitializedFixedDoubleArray(capacity); |
| 6792 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7429 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 6793 } | 7430 } |
| 6794 FixedArray* elems = FixedArray::cast(obj); | 7431 FixedDoubleArray* elems = FixedDoubleArray::cast(obj); |
| 6795 | 7432 |
| 6796 { MaybeObject* maybe_obj = map()->GetFastElementsMap(); | 7433 { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap(); |
| 6797 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7434 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 6798 } | 7435 } |
| 6799 Map* new_map = Map::cast(obj); | 7436 Map* new_map = Map::cast(obj); |
| 6800 | 7437 |
| 6801 AssertNoAllocation no_gc; | 7438 AssertNoAllocation no_gc; |
| 6802 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); | |
| 6803 switch (GetElementsKind()) { | 7439 switch (GetElementsKind()) { |
| 6804 case FAST_ELEMENTS: { | 7440 case FAST_ELEMENTS: { |
| 6805 FixedArray* old_elements = FixedArray::cast(elements()); | 7441 elems->Initialize(FixedArray::cast(elements())); |
| 6806 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); | 7442 break; |
| 6807 // Fill out the new array with this content and array holes. | 7443 } |
| 6808 for (uint32_t i = 0; i < old_length; i++) { | 7444 case FAST_DOUBLE_ELEMENTS: { |
| 6809 elems->set(i, old_elements->get(i), mode); | 7445 elems->Initialize(FixedDoubleArray::cast(elements())); |
| 6810 } | |
| 6811 break; | 7446 break; |
| 6812 } | 7447 } |
| 6813 case DICTIONARY_ELEMENTS: { | 7448 case DICTIONARY_ELEMENTS: { |
| 6814 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | 7449 elems->Initialize(NumberDictionary::cast(elements())); |
| 6815 for (int i = 0; i < dictionary->Capacity(); i++) { | |
| 6816 Object* key = dictionary->KeyAt(i); | |
| 6817 if (key->IsNumber()) { | |
| 6818 uint32_t entry = static_cast<uint32_t>(key->Number()); | |
| 6819 elems->set(entry, dictionary->ValueAt(i), mode); | |
| 6820 } | |
| 6821 } | |
| 6822 break; | 7450 break; |
| 6823 } | 7451 } |
| 6824 default: | 7452 default: |
| 6825 UNREACHABLE(); | 7453 UNREACHABLE(); |
| 6826 break; | 7454 break; |
| 6827 } | 7455 } |
| 6828 | 7456 |
| 6829 set_map(new_map); | 7457 set_map(new_map); |
| 6830 set_elements(elems); | 7458 set_elements(elems); |
| 6831 | 7459 |
| 6832 if (IsJSArray()) { | 7460 if (IsJSArray()) { |
| 6833 JSArray::cast(this)->set_length(Smi::FromInt(length)); | 7461 JSArray::cast(this)->set_length(Smi::FromInt(length)); |
| 6834 } | 7462 } |
| 6835 | 7463 |
| 6836 return this; | 7464 return this; |
| 6837 } | 7465 } |
| 6838 | 7466 |
| 6839 | 7467 |
| 6840 MaybeObject* JSObject::SetSlowElements(Object* len) { | 7468 MaybeObject* JSObject::SetSlowElements(Object* len) { |
| 6841 // We should never end in here with a pixel or external array. | 7469 // We should never end in here with a pixel or external array. |
| 6842 ASSERT(!HasExternalArrayElements()); | 7470 ASSERT(!HasExternalArrayElements()); |
| 6843 | 7471 |
| 6844 uint32_t new_length = static_cast<uint32_t>(len->Number()); | 7472 uint32_t new_length = static_cast<uint32_t>(len->Number()); |
| 6845 | 7473 |
| 6846 switch (GetElementsKind()) { | 7474 switch (GetElementsKind()) { |
| 6847 case FAST_ELEMENTS: { | 7475 case FAST_ELEMENTS: { |
| 6848 // Make sure we never try to shrink dense arrays into sparse arrays. | 7476 // Make sure we never try to shrink dense arrays into sparse arrays. |
| 6849 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= | 7477 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= |
| 6850 new_length); | 7478 new_length); |
| 6851 Object* obj; | 7479 MaybeObject* result = NormalizeElements(); |
| 6852 { MaybeObject* maybe_obj = NormalizeElements(); | 7480 if (result->IsFailure()) return result; |
| 6853 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
| 6854 } | |
| 6855 | 7481 |
| 6856 // Update length for JSArrays. | 7482 // Update length for JSArrays. |
| 6857 if (IsJSArray()) JSArray::cast(this)->set_length(len); | 7483 if (IsJSArray()) JSArray::cast(this)->set_length(len); |
| 6858 break; | 7484 break; |
| 6859 } | 7485 } |
| 6860 case DICTIONARY_ELEMENTS: { | 7486 case DICTIONARY_ELEMENTS: { |
| 6861 if (IsJSArray()) { | 7487 if (IsJSArray()) { |
| 6862 uint32_t old_length = | 7488 uint32_t old_length = |
| 6863 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); | 7489 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); |
| 6864 element_dictionary()->RemoveNumberEntries(new_length, old_length), | 7490 element_dictionary()->RemoveNumberEntries(new_length, old_length), |
| 6865 JSArray::cast(this)->set_length(len); | 7491 JSArray::cast(this)->set_length(len); |
| 6866 } | 7492 } |
| 6867 break; | 7493 break; |
| 6868 } | 7494 } |
| 6869 default: | 7495 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 7496 UNIMPLEMENTED(); |
| 7497 break; |
| 7498 case EXTERNAL_BYTE_ELEMENTS: |
| 7499 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 7500 case EXTERNAL_SHORT_ELEMENTS: |
| 7501 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 7502 case EXTERNAL_INT_ELEMENTS: |
| 7503 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7504 case EXTERNAL_FLOAT_ELEMENTS: |
| 7505 case EXTERNAL_DOUBLE_ELEMENTS: |
| 7506 case EXTERNAL_PIXEL_ELEMENTS: |
| 7507 case FAST_DOUBLE_ELEMENTS: |
| 6870 UNREACHABLE(); | 7508 UNREACHABLE(); |
| 6871 break; | 7509 break; |
| 6872 } | 7510 } |
| 6873 return this; | 7511 return this; |
| 6874 } | 7512 } |
| 6875 | 7513 |
| 6876 | 7514 |
| 6877 MaybeObject* JSArray::Initialize(int capacity) { | 7515 MaybeObject* JSArray::Initialize(int capacity) { |
| 6878 Heap* heap = GetHeap(); | 7516 Heap* heap = GetHeap(); |
| 6879 ASSERT(capacity >= 0); | 7517 ASSERT(capacity >= 0); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6924 if (value < 0) return ArrayLengthRangeError(GetHeap()); | 7562 if (value < 0) return ArrayLengthRangeError(GetHeap()); |
| 6925 switch (GetElementsKind()) { | 7563 switch (GetElementsKind()) { |
| 6926 case FAST_ELEMENTS: { | 7564 case FAST_ELEMENTS: { |
| 6927 int old_capacity = FixedArray::cast(elements())->length(); | 7565 int old_capacity = FixedArray::cast(elements())->length(); |
| 6928 if (value <= old_capacity) { | 7566 if (value <= old_capacity) { |
| 6929 if (IsJSArray()) { | 7567 if (IsJSArray()) { |
| 6930 Object* obj; | 7568 Object* obj; |
| 6931 { MaybeObject* maybe_obj = EnsureWritableFastElements(); | 7569 { MaybeObject* maybe_obj = EnsureWritableFastElements(); |
| 6932 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7570 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 6933 } | 7571 } |
| 6934 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); | 7572 FixedArray* fast_elements = FixedArray::cast(elements()); |
| 6935 // NOTE: We may be able to optimize this by removing the | 7573 if (2 * value <= old_capacity) { |
| 6936 // last part of the elements backing storage array and | 7574 // If more than half the elements won't be used, trim the array. |
| 6937 // setting the capacity to the new size. | 7575 if (value == 0) { |
| 6938 for (int i = value; i < old_length; i++) { | 7576 initialize_elements(); |
| 6939 FixedArray::cast(elements())->set_the_hole(i); | 7577 } else { |
| 7578 fast_elements->set_length(value); |
| 7579 Address filler_start = fast_elements->address() + |
| 7580 FixedArray::OffsetOfElementAt(value); |
| 7581 int filler_size = (old_capacity - value) * kPointerSize; |
| 7582 GetHeap()->CreateFillerObjectAt(filler_start, filler_size); |
| 7583 } |
| 7584 } else { |
| 7585 // Otherwise, fill the unused tail with holes. |
| 7586 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); |
| 7587 for (int i = value; i < old_length; i++) { |
| 7588 fast_elements->set_the_hole(i); |
| 7589 } |
| 6940 } | 7590 } |
| 6941 JSArray::cast(this)->set_length(Smi::cast(smi_length)); | 7591 JSArray::cast(this)->set_length(Smi::cast(smi_length)); |
| 6942 } | 7592 } |
| 6943 return this; | 7593 return this; |
| 6944 } | 7594 } |
| 6945 int min = NewElementsCapacity(old_capacity); | 7595 int min = NewElementsCapacity(old_capacity); |
| 6946 int new_capacity = value > min ? value : min; | 7596 int new_capacity = value > min ? value : min; |
| 6947 if (new_capacity <= kMaxFastElementsLength || | 7597 if (new_capacity <= kMaxFastElementsLength || |
| 6948 !ShouldConvertToSlowElements(new_capacity)) { | 7598 !ShouldConvertToSlowElements(new_capacity)) { |
| 6949 Object* obj; | 7599 MaybeObject* result = |
| 6950 { MaybeObject* maybe_obj = | 7600 SetFastElementsCapacityAndLength(new_capacity, value); |
| 6951 SetFastElementsCapacityAndLength(new_capacity, value); | 7601 if (result->IsFailure()) return result; |
| 6952 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
| 6953 } | |
| 6954 return this; | 7602 return this; |
| 6955 } | 7603 } |
| 6956 break; | 7604 break; |
| 6957 } | 7605 } |
| 6958 case DICTIONARY_ELEMENTS: { | 7606 case DICTIONARY_ELEMENTS: { |
| 6959 if (IsJSArray()) { | 7607 if (IsJSArray()) { |
| 6960 if (value == 0) { | 7608 if (value == 0) { |
| 6961 // If the length of a slow array is reset to zero, we clear | 7609 // If the length of a slow array is reset to zero, we clear |
| 6962 // the array and flush backing storage. This has the added | 7610 // the array and flush backing storage. This has the added |
| 6963 // benefit that the array returns to fast mode. | 7611 // benefit that the array returns to fast mode. |
| 6964 Object* obj; | 7612 Object* obj; |
| 6965 { MaybeObject* maybe_obj = ResetElements(); | 7613 { MaybeObject* maybe_obj = ResetElements(); |
| 6966 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7614 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 6967 } | 7615 } |
| 6968 } else { | 7616 } else { |
| 6969 // Remove deleted elements. | 7617 // Remove deleted elements. |
| 6970 uint32_t old_length = | 7618 uint32_t old_length = |
| 6971 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); | 7619 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); |
| 6972 element_dictionary()->RemoveNumberEntries(value, old_length); | 7620 element_dictionary()->RemoveNumberEntries(value, old_length); |
| 6973 } | 7621 } |
| 6974 JSArray::cast(this)->set_length(Smi::cast(smi_length)); | 7622 JSArray::cast(this)->set_length(Smi::cast(smi_length)); |
| 6975 } | 7623 } |
| 6976 return this; | 7624 return this; |
| 6977 } | 7625 } |
| 6978 default: | 7626 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 7627 case EXTERNAL_BYTE_ELEMENTS: |
| 7628 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 7629 case EXTERNAL_SHORT_ELEMENTS: |
| 7630 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 7631 case EXTERNAL_INT_ELEMENTS: |
| 7632 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7633 case EXTERNAL_FLOAT_ELEMENTS: |
| 7634 case EXTERNAL_DOUBLE_ELEMENTS: |
| 7635 case EXTERNAL_PIXEL_ELEMENTS: |
| 7636 case FAST_DOUBLE_ELEMENTS: |
| 6979 UNREACHABLE(); | 7637 UNREACHABLE(); |
| 6980 break; | 7638 break; |
| 6981 } | 7639 } |
| 6982 } | 7640 } |
| 6983 | 7641 |
| 6984 // General slow case. | 7642 // General slow case. |
| 6985 if (len->IsNumber()) { | 7643 if (len->IsNumber()) { |
| 6986 uint32_t length; | 7644 uint32_t length; |
| 6987 if (len->ToArrayIndex(&length)) { | 7645 if (len->ToArrayIndex(&length)) { |
| 6988 return SetSlowElements(len); | 7646 return SetSlowElements(len); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 6999 } | 7657 } |
| 7000 FixedArray::cast(obj)->set(0, len); | 7658 FixedArray::cast(obj)->set(0, len); |
| 7001 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); | 7659 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); |
| 7002 set_elements(FixedArray::cast(obj)); | 7660 set_elements(FixedArray::cast(obj)); |
| 7003 return this; | 7661 return this; |
| 7004 } | 7662 } |
| 7005 | 7663 |
| 7006 | 7664 |
| 7007 Object* Map::GetPrototypeTransition(Object* prototype) { | 7665 Object* Map::GetPrototypeTransition(Object* prototype) { |
| 7008 FixedArray* cache = prototype_transitions(); | 7666 FixedArray* cache = prototype_transitions(); |
| 7009 int capacity = cache->length(); | 7667 int number_of_transitions = NumberOfProtoTransitions(); |
| 7010 if (capacity == 0) return NULL; | 7668 const int proto_offset = |
| 7011 int finger = Smi::cast(cache->get(0))->value(); | 7669 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset; |
| 7012 for (int i = 1; i < finger; i += 2) { | 7670 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; |
| 7013 if (cache->get(i) == prototype) return cache->get(i + 1); | 7671 const int step = kProtoTransitionElementsPerEntry; |
| 7672 for (int i = 0; i < number_of_transitions; i++) { |
| 7673 if (cache->get(proto_offset + i * step) == prototype) { |
| 7674 Object* map = cache->get(map_offset + i * step); |
| 7675 ASSERT(map->IsMap()); |
| 7676 return map; |
| 7677 } |
| 7014 } | 7678 } |
| 7015 return NULL; | 7679 return NULL; |
| 7016 } | 7680 } |
| 7017 | 7681 |
| 7018 | 7682 |
| 7019 MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { | 7683 MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { |
| 7684 ASSERT(map->IsMap()); |
| 7685 ASSERT(HeapObject::cast(prototype)->map()->IsMap()); |
| 7020 // Don't cache prototype transition if this map is shared. | 7686 // Don't cache prototype transition if this map is shared. |
| 7021 if (is_shared() || !FLAG_cache_prototype_transitions) return this; | 7687 if (is_shared() || !FLAG_cache_prototype_transitions) return this; |
| 7022 | 7688 |
| 7023 FixedArray* cache = prototype_transitions(); | 7689 FixedArray* cache = prototype_transitions(); |
| 7024 | 7690 |
| 7025 int capacity = cache->length(); | 7691 const int step = kProtoTransitionElementsPerEntry; |
| 7692 const int header = kProtoTransitionHeaderSize; |
| 7026 | 7693 |
| 7027 int finger = (capacity == 0) ? 1 : Smi::cast(cache->get(0))->value(); | 7694 int capacity = (cache->length() - header) / step; |
| 7028 | 7695 |
| 7029 if (finger >= capacity) { | 7696 int transitions = NumberOfProtoTransitions() + 1; |
| 7697 |
| 7698 if (transitions > capacity) { |
| 7030 if (capacity > kMaxCachedPrototypeTransitions) return this; | 7699 if (capacity > kMaxCachedPrototypeTransitions) return this; |
| 7031 | 7700 |
| 7032 FixedArray* new_cache; | 7701 FixedArray* new_cache; |
| 7033 { MaybeObject* maybe_cache = GetHeap()->AllocateFixedArray(finger * 2 + 1); | 7702 // Grow array by factor 2 over and above what we need. |
| 7703 { MaybeObject* maybe_cache = |
| 7704 GetHeap()->AllocateFixedArray(transitions * 2 * step + header); |
| 7034 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache; | 7705 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache; |
| 7035 } | 7706 } |
| 7036 | 7707 |
| 7037 for (int i = 1; i < capacity; i++) new_cache->set(i, cache->get(i)); | 7708 for (int i = 0; i < capacity * step; i++) { |
| 7709 new_cache->set(i + header, cache->get(i + header)); |
| 7710 } |
| 7038 cache = new_cache; | 7711 cache = new_cache; |
| 7039 set_prototype_transitions(cache); | 7712 set_prototype_transitions(cache); |
| 7040 } | 7713 } |
| 7041 | 7714 |
| 7042 cache->set(finger, prototype); | 7715 int last = transitions - 1; |
| 7043 cache->set(finger + 1, map); | 7716 |
| 7044 cache->set(0, Smi::FromInt(finger + 2)); | 7717 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype); |
| 7718 cache->set(header + last * step + kProtoTransitionMapOffset, map); |
| 7719 SetNumberOfProtoTransitions(transitions); |
| 7045 | 7720 |
| 7046 return cache; | 7721 return cache; |
| 7047 } | 7722 } |
| 7048 | 7723 |
| 7049 | 7724 |
| 7050 MaybeObject* JSObject::SetPrototype(Object* value, | 7725 MaybeObject* JSReceiver::SetPrototype(Object* value, |
| 7051 bool skip_hidden_prototypes) { | 7726 bool skip_hidden_prototypes) { |
| 7727 #ifdef DEBUG |
| 7728 int size = Size(); |
| 7729 #endif |
| 7730 |
| 7052 Heap* heap = GetHeap(); | 7731 Heap* heap = GetHeap(); |
| 7053 // Silently ignore the change if value is not a JSObject or null. | 7732 // Silently ignore the change if value is not a JSObject or null. |
| 7054 // SpiderMonkey behaves this way. | 7733 // SpiderMonkey behaves this way. |
| 7055 if (!value->IsJSObject() && !value->IsNull()) return value; | 7734 if (!value->IsJSReceiver() && !value->IsNull()) return value; |
| 7056 | 7735 |
| 7057 // From 8.6.2 Object Internal Methods | 7736 // From 8.6.2 Object Internal Methods |
| 7058 // ... | 7737 // ... |
| 7059 // In addition, if [[Extensible]] is false the value of the [[Class]] and | 7738 // In addition, if [[Extensible]] is false the value of the [[Class]] and |
| 7060 // [[Prototype]] internal properties of the object may not be modified. | 7739 // [[Prototype]] internal properties of the object may not be modified. |
| 7061 // ... | 7740 // ... |
| 7062 // Implementation specific extensions that modify [[Class]], [[Prototype]] | 7741 // Implementation specific extensions that modify [[Class]], [[Prototype]] |
| 7063 // or [[Extensible]] must not violate the invariants defined in the preceding | 7742 // or [[Extensible]] must not violate the invariants defined in the preceding |
| 7064 // paragraph. | 7743 // paragraph. |
| 7065 if (!this->map()->is_extensible()) { | 7744 if (!this->map()->is_extensible()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 7076 // chain. | 7755 // chain. |
| 7077 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) { | 7756 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) { |
| 7078 if (JSObject::cast(pt) == this) { | 7757 if (JSObject::cast(pt) == this) { |
| 7079 // Cycle detected. | 7758 // Cycle detected. |
| 7080 HandleScope scope; | 7759 HandleScope scope; |
| 7081 return heap->isolate()->Throw( | 7760 return heap->isolate()->Throw( |
| 7082 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0))); | 7761 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0))); |
| 7083 } | 7762 } |
| 7084 } | 7763 } |
| 7085 | 7764 |
| 7086 JSObject* real_receiver = this; | 7765 JSReceiver* real_receiver = this; |
| 7087 | 7766 |
| 7088 if (skip_hidden_prototypes) { | 7767 if (skip_hidden_prototypes) { |
| 7089 // Find the first object in the chain whose prototype object is not | 7768 // Find the first object in the chain whose prototype object is not |
| 7090 // hidden and set the new prototype on that object. | 7769 // hidden and set the new prototype on that object. |
| 7091 Object* current_proto = real_receiver->GetPrototype(); | 7770 Object* current_proto = real_receiver->GetPrototype(); |
| 7092 while (current_proto->IsJSObject() && | 7771 while (current_proto->IsJSObject() && |
| 7093 JSObject::cast(current_proto)->map()->is_hidden_prototype()) { | 7772 JSObject::cast(current_proto)->map()->is_hidden_prototype()) { |
| 7094 real_receiver = JSObject::cast(current_proto); | 7773 real_receiver = JSObject::cast(current_proto); |
| 7095 current_proto = current_proto->GetPrototype(); | 7774 current_proto = current_proto->GetPrototype(); |
| 7096 } | 7775 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 7112 map->PutPrototypeTransition(value, Map::cast(new_map)); | 7791 map->PutPrototypeTransition(value, Map::cast(new_map)); |
| 7113 if (maybe_new_cache->IsFailure()) return maybe_new_cache; | 7792 if (maybe_new_cache->IsFailure()) return maybe_new_cache; |
| 7114 } | 7793 } |
| 7115 | 7794 |
| 7116 Map::cast(new_map)->set_prototype(value); | 7795 Map::cast(new_map)->set_prototype(value); |
| 7117 } | 7796 } |
| 7118 ASSERT(Map::cast(new_map)->prototype() == value); | 7797 ASSERT(Map::cast(new_map)->prototype() == value); |
| 7119 real_receiver->set_map(Map::cast(new_map)); | 7798 real_receiver->set_map(Map::cast(new_map)); |
| 7120 | 7799 |
| 7121 heap->ClearInstanceofCache(); | 7800 heap->ClearInstanceofCache(); |
| 7122 | 7801 ASSERT(size == Size()); |
| 7123 return value; | 7802 return value; |
| 7124 } | 7803 } |
| 7125 | 7804 |
| 7126 | 7805 |
| 7127 bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) { | 7806 bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) { |
| 7128 switch (GetElementsKind()) { | 7807 switch (GetElementsKind()) { |
| 7129 case FAST_ELEMENTS: { | 7808 case FAST_ELEMENTS: { |
| 7130 uint32_t length = IsJSArray() ? | 7809 uint32_t length = IsJSArray() ? |
| 7131 static_cast<uint32_t> | 7810 static_cast<uint32_t> |
| 7132 (Smi::cast(JSArray::cast(this)->length())->value()) : | 7811 (Smi::cast(JSArray::cast(this)->length())->value()) : |
| 7133 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 7812 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
| 7134 if ((index < length) && | 7813 if ((index < length) && |
| 7135 !FixedArray::cast(elements())->get(index)->IsTheHole()) { | 7814 !FixedArray::cast(elements())->get(index)->IsTheHole()) { |
| 7136 return true; | 7815 return true; |
| 7137 } | 7816 } |
| 7138 break; | 7817 break; |
| 7139 } | 7818 } |
| 7140 case EXTERNAL_PIXEL_ELEMENTS: { | 7819 case EXTERNAL_PIXEL_ELEMENTS: { |
| 7141 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); | 7820 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); |
| 7142 if (index < static_cast<uint32_t>(pixels->length())) { | 7821 if (index < static_cast<uint32_t>(pixels->length())) { |
| 7143 return true; | 7822 return true; |
| 7144 } | 7823 } |
| 7145 break; | 7824 break; |
| 7146 } | 7825 } |
| 7147 case EXTERNAL_BYTE_ELEMENTS: | 7826 case EXTERNAL_BYTE_ELEMENTS: |
| 7148 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 7827 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 7149 case EXTERNAL_SHORT_ELEMENTS: | 7828 case EXTERNAL_SHORT_ELEMENTS: |
| 7150 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 7829 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 7151 case EXTERNAL_INT_ELEMENTS: | 7830 case EXTERNAL_INT_ELEMENTS: |
| 7152 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 7831 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7153 case EXTERNAL_FLOAT_ELEMENTS: | 7832 case EXTERNAL_FLOAT_ELEMENTS: |
| 7154 case EXTERNAL_DOUBLE_ELEMENTS: { | 7833 case EXTERNAL_DOUBLE_ELEMENTS: |
| 7834 case FAST_DOUBLE_ELEMENTS: { |
| 7155 ExternalArray* array = ExternalArray::cast(elements()); | 7835 ExternalArray* array = ExternalArray::cast(elements()); |
| 7156 if (index < static_cast<uint32_t>(array->length())) { | 7836 if (index < static_cast<uint32_t>(array->length())) { |
| 7157 return true; | 7837 return true; |
| 7158 } | 7838 } |
| 7159 break; | 7839 break; |
| 7160 } | 7840 } |
| 7161 case DICTIONARY_ELEMENTS: { | 7841 case DICTIONARY_ELEMENTS: { |
| 7162 if (element_dictionary()->FindEntry(index) | 7842 if (element_dictionary()->FindEntry(index) |
| 7163 != NumberDictionary::kNotFound) { | 7843 != NumberDictionary::kNotFound) { |
| 7164 return true; | 7844 return true; |
| 7165 } | 7845 } |
| 7166 break; | 7846 break; |
| 7167 } | 7847 } |
| 7168 default: | 7848 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 7169 UNREACHABLE(); | 7849 UNREACHABLE(); |
| 7170 break; | 7850 break; |
| 7171 } | 7851 } |
| 7172 | 7852 |
| 7173 // Handle [] on String objects. | 7853 // Handle [] on String objects. |
| 7174 if (this->IsStringObjectWithCharacterAt(index)) return true; | 7854 if (this->IsStringObjectWithCharacterAt(index)) return true; |
| 7175 | 7855 |
| 7176 Object* pt = GetPrototype(); | 7856 Object* pt = GetPrototype(); |
| 7177 if (pt->IsNull()) return false; | 7857 if (pt->IsNull()) return false; |
| 7178 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); | 7858 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); |
| 7179 } | 7859 } |
| 7180 | 7860 |
| 7181 | 7861 |
| 7182 bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) { | 7862 bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) { |
| 7183 Isolate* isolate = GetIsolate(); | 7863 Isolate* isolate = GetIsolate(); |
| 7184 // Make sure that the top context does not change when doing | 7864 // Make sure that the top context does not change when doing |
| 7185 // callbacks or interceptor calls. | 7865 // callbacks or interceptor calls. |
| 7186 AssertNoContextChange ncc; | 7866 AssertNoContextChange ncc; |
| 7187 HandleScope scope(isolate); | 7867 HandleScope scope(isolate); |
| 7188 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); | 7868 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); |
| 7189 Handle<JSObject> receiver_handle(receiver); | 7869 Handle<JSReceiver> receiver_handle(receiver); |
| 7190 Handle<JSObject> holder_handle(this); | 7870 Handle<JSObject> holder_handle(this); |
| 7191 CustomArguments args(isolate, interceptor->data(), receiver, this); | 7871 CustomArguments args(isolate, interceptor->data(), receiver, this); |
| 7192 v8::AccessorInfo info(args.end()); | 7872 v8::AccessorInfo info(args.end()); |
| 7193 if (!interceptor->query()->IsUndefined()) { | 7873 if (!interceptor->query()->IsUndefined()) { |
| 7194 v8::IndexedPropertyQuery query = | 7874 v8::IndexedPropertyQuery query = |
| 7195 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query()); | 7875 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query()); |
| 7196 LOG(isolate, | 7876 LOG(isolate, |
| 7197 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index)); | 7877 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index)); |
| 7198 v8::Handle<v8::Integer> result; | 7878 v8::Handle<v8::Integer> result; |
| 7199 { | 7879 { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7272 case EXTERNAL_SHORT_ELEMENTS: | 7952 case EXTERNAL_SHORT_ELEMENTS: |
| 7273 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 7953 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 7274 case EXTERNAL_INT_ELEMENTS: | 7954 case EXTERNAL_INT_ELEMENTS: |
| 7275 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 7955 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7276 case EXTERNAL_FLOAT_ELEMENTS: | 7956 case EXTERNAL_FLOAT_ELEMENTS: |
| 7277 case EXTERNAL_DOUBLE_ELEMENTS: { | 7957 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 7278 ExternalArray* array = ExternalArray::cast(elements()); | 7958 ExternalArray* array = ExternalArray::cast(elements()); |
| 7279 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT; | 7959 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT; |
| 7280 break; | 7960 break; |
| 7281 } | 7961 } |
| 7962 case FAST_DOUBLE_ELEMENTS: |
| 7963 UNREACHABLE(); |
| 7964 break; |
| 7282 case DICTIONARY_ELEMENTS: { | 7965 case DICTIONARY_ELEMENTS: { |
| 7283 if (element_dictionary()->FindEntry(index) != | 7966 if (element_dictionary()->FindEntry(index) != |
| 7284 NumberDictionary::kNotFound) { | 7967 NumberDictionary::kNotFound) { |
| 7285 return DICTIONARY_ELEMENT; | 7968 return DICTIONARY_ELEMENT; |
| 7286 } | 7969 } |
| 7287 break; | 7970 break; |
| 7288 } | 7971 } |
| 7289 default: | 7972 case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| 7290 UNREACHABLE(); | 7973 // Aliased parameters and non-aliased elements in a fast backing store |
| 7974 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary |
| 7975 // backing store behave as DICTIONARY_ELEMENT. |
| 7976 FixedArray* parameter_map = FixedArray::cast(elements()); |
| 7977 uint32_t length = parameter_map->length(); |
| 7978 Object* probe = |
| 7979 index < (length - 2) ? parameter_map->get(index + 2) : NULL; |
| 7980 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT; |
| 7981 // If not aliased, check the arguments. |
| 7982 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 7983 if (arguments->IsDictionary()) { |
| 7984 NumberDictionary* dictionary = NumberDictionary::cast(arguments); |
| 7985 if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) { |
| 7986 return DICTIONARY_ELEMENT; |
| 7987 } |
| 7988 } else { |
| 7989 length = arguments->length(); |
| 7990 probe = (index < length) ? arguments->get(index) : NULL; |
| 7991 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT; |
| 7992 } |
| 7291 break; | 7993 break; |
| 7994 } |
| 7292 } | 7995 } |
| 7293 | 7996 |
| 7294 return UNDEFINED_ELEMENT; | 7997 return UNDEFINED_ELEMENT; |
| 7295 } | 7998 } |
| 7296 | 7999 |
| 7297 | 8000 |
| 7298 bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) { | 8001 bool JSObject::HasElementInElements(FixedArray* elements, |
| 8002 ElementsKind kind, |
| 8003 uint32_t index) { |
| 8004 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS); |
| 8005 if (kind == FAST_ELEMENTS) { |
| 8006 int length = IsJSArray() |
| 8007 ? Smi::cast(JSArray::cast(this)->length())->value() |
| 8008 : elements->length(); |
| 8009 if (index < static_cast<uint32_t>(length) && |
| 8010 !elements->get(index)->IsTheHole()) { |
| 8011 return true; |
| 8012 } |
| 8013 } else { |
| 8014 if (NumberDictionary::cast(elements)->FindEntry(index) != |
| 8015 NumberDictionary::kNotFound) { |
| 8016 return true; |
| 8017 } |
| 8018 } |
| 8019 return false; |
| 8020 } |
| 8021 |
| 8022 |
| 8023 bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) { |
| 7299 // Check access rights if needed. | 8024 // Check access rights if needed. |
| 7300 if (IsAccessCheckNeeded()) { | 8025 if (IsAccessCheckNeeded()) { |
| 7301 Heap* heap = GetHeap(); | 8026 Heap* heap = GetHeap(); |
| 7302 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { | 8027 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { |
| 7303 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); | 8028 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
| 7304 return false; | 8029 return false; |
| 7305 } | 8030 } |
| 7306 } | 8031 } |
| 7307 | 8032 |
| 7308 // Check for lookup interceptor | 8033 // Check for lookup interceptor |
| 7309 if (HasIndexedInterceptor()) { | 8034 if (HasIndexedInterceptor()) { |
| 7310 return HasElementWithInterceptor(receiver, index); | 8035 return HasElementWithInterceptor(receiver, index); |
| 7311 } | 8036 } |
| 7312 | 8037 |
| 7313 switch (GetElementsKind()) { | 8038 ElementsKind kind = GetElementsKind(); |
| 8039 switch (kind) { |
| 7314 case FAST_ELEMENTS: { | 8040 case FAST_ELEMENTS: { |
| 7315 uint32_t length = IsJSArray() ? | 8041 uint32_t length = IsJSArray() ? |
| 7316 static_cast<uint32_t> | 8042 static_cast<uint32_t> |
| 7317 (Smi::cast(JSArray::cast(this)->length())->value()) : | 8043 (Smi::cast(JSArray::cast(this)->length())->value()) : |
| 7318 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 8044 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
| 7319 if ((index < length) && | 8045 if ((index < length) && |
| 7320 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; | 8046 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; |
| 7321 break; | 8047 break; |
| 7322 } | 8048 } |
| 7323 case EXTERNAL_PIXEL_ELEMENTS: { | 8049 case EXTERNAL_PIXEL_ELEMENTS: { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 7334 case EXTERNAL_INT_ELEMENTS: | 8060 case EXTERNAL_INT_ELEMENTS: |
| 7335 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 8061 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7336 case EXTERNAL_FLOAT_ELEMENTS: | 8062 case EXTERNAL_FLOAT_ELEMENTS: |
| 7337 case EXTERNAL_DOUBLE_ELEMENTS: { | 8063 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 7338 ExternalArray* array = ExternalArray::cast(elements()); | 8064 ExternalArray* array = ExternalArray::cast(elements()); |
| 7339 if (index < static_cast<uint32_t>(array->length())) { | 8065 if (index < static_cast<uint32_t>(array->length())) { |
| 7340 return true; | 8066 return true; |
| 7341 } | 8067 } |
| 7342 break; | 8068 break; |
| 7343 } | 8069 } |
| 8070 case FAST_DOUBLE_ELEMENTS: |
| 8071 UNREACHABLE(); |
| 8072 break; |
| 7344 case DICTIONARY_ELEMENTS: { | 8073 case DICTIONARY_ELEMENTS: { |
| 7345 if (element_dictionary()->FindEntry(index) | 8074 if (element_dictionary()->FindEntry(index) |
| 7346 != NumberDictionary::kNotFound) { | 8075 != NumberDictionary::kNotFound) { |
| 7347 return true; | 8076 return true; |
| 7348 } | 8077 } |
| 7349 break; | 8078 break; |
| 7350 } | 8079 } |
| 7351 default: | 8080 case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| 7352 UNREACHABLE(); | 8081 FixedArray* parameter_map = FixedArray::cast(elements()); |
| 8082 uint32_t length = parameter_map->length(); |
| 8083 Object* probe = |
| 8084 (index < length - 2) ? parameter_map->get(index + 2) : NULL; |
| 8085 if (probe != NULL && !probe->IsTheHole()) return true; |
| 8086 |
| 8087 // Not a mapped parameter, check the arguments. |
| 8088 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 8089 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS; |
| 8090 if (HasElementInElements(arguments, kind, index)) return true; |
| 7353 break; | 8091 break; |
| 8092 } |
| 7354 } | 8093 } |
| 7355 | 8094 |
| 7356 // Handle [] on String objects. | 8095 // Handle [] on String objects. |
| 7357 if (this->IsStringObjectWithCharacterAt(index)) return true; | 8096 if (this->IsStringObjectWithCharacterAt(index)) return true; |
| 7358 | 8097 |
| 7359 Object* pt = GetPrototype(); | 8098 Object* pt = GetPrototype(); |
| 7360 if (pt->IsNull()) return false; | 8099 if (pt->IsNull()) return false; |
| 7361 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); | 8100 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); |
| 7362 } | 8101 } |
| 7363 | 8102 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7409 | 8148 |
| 7410 // api style callbacks. | 8149 // api style callbacks. |
| 7411 if (structure->IsAccessorInfo()) { | 8150 if (structure->IsAccessorInfo()) { |
| 7412 Handle<AccessorInfo> data(AccessorInfo::cast(structure)); | 8151 Handle<AccessorInfo> data(AccessorInfo::cast(structure)); |
| 7413 Object* fun_obj = data->getter(); | 8152 Object* fun_obj = data->getter(); |
| 7414 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); | 8153 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); |
| 7415 HandleScope scope(isolate); | 8154 HandleScope scope(isolate); |
| 7416 Handle<JSObject> self(JSObject::cast(receiver)); | 8155 Handle<JSObject> self(JSObject::cast(receiver)); |
| 7417 Handle<JSObject> holder_handle(JSObject::cast(holder)); | 8156 Handle<JSObject> holder_handle(JSObject::cast(holder)); |
| 7418 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); | 8157 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); |
| 7419 Handle<String> key(isolate->factory()->NumberToString(number)); | 8158 Handle<String> key = isolate->factory()->NumberToString(number); |
| 7420 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key)); | 8159 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key)); |
| 7421 CustomArguments args(isolate, data->data(), *self, *holder_handle); | 8160 CustomArguments args(isolate, data->data(), *self, *holder_handle); |
| 7422 v8::AccessorInfo info(args.end()); | 8161 v8::AccessorInfo info(args.end()); |
| 7423 v8::Handle<v8::Value> result; | 8162 v8::Handle<v8::Value> result; |
| 7424 { | 8163 { |
| 7425 // Leaving JavaScript. | 8164 // Leaving JavaScript. |
| 7426 VMState state(isolate, EXTERNAL); | 8165 VMState state(isolate, EXTERNAL); |
| 7427 result = call_fun(v8::Utils::ToLocal(key), info); | 8166 result = call_fun(v8::Utils::ToLocal(key), info); |
| 7428 } | 8167 } |
| 7429 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 8168 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7504 *isolate->factory()->NewTypeError("no_setter_in_callback", | 8243 *isolate->factory()->NewTypeError("no_setter_in_callback", |
| 7505 HandleVector(args, 2))); | 8244 HandleVector(args, 2))); |
| 7506 } | 8245 } |
| 7507 } | 8246 } |
| 7508 | 8247 |
| 7509 UNREACHABLE(); | 8248 UNREACHABLE(); |
| 7510 return NULL; | 8249 return NULL; |
| 7511 } | 8250 } |
| 7512 | 8251 |
| 7513 | 8252 |
| 8253 bool JSObject::HasFastArgumentsElements() { |
| 8254 Heap* heap = GetHeap(); |
| 8255 if (!elements()->IsFixedArray()) return false; |
| 8256 FixedArray* elements = FixedArray::cast(this->elements()); |
| 8257 if (elements->map() != heap->non_strict_arguments_elements_map()) { |
| 8258 return false; |
| 8259 } |
| 8260 FixedArray* arguments = FixedArray::cast(elements->get(1)); |
| 8261 return !arguments->IsDictionary(); |
| 8262 } |
| 8263 |
| 8264 |
| 8265 bool JSObject::HasDictionaryArgumentsElements() { |
| 8266 Heap* heap = GetHeap(); |
| 8267 if (!elements()->IsFixedArray()) return false; |
| 8268 FixedArray* elements = FixedArray::cast(this->elements()); |
| 8269 if (elements->map() != heap->non_strict_arguments_elements_map()) { |
| 8270 return false; |
| 8271 } |
| 8272 FixedArray* arguments = FixedArray::cast(elements->get(1)); |
| 8273 return arguments->IsDictionary(); |
| 8274 } |
| 8275 |
| 8276 |
| 7514 // Adding n elements in fast case is O(n*n). | 8277 // Adding n elements in fast case is O(n*n). |
| 7515 // Note: revisit design to have dual undefined values to capture absent | 8278 // Note: revisit design to have dual undefined values to capture absent |
| 7516 // elements. | 8279 // elements. |
| 7517 MaybeObject* JSObject::SetFastElement(uint32_t index, | 8280 MaybeObject* JSObject::SetFastElement(uint32_t index, |
| 7518 Object* value, | 8281 Object* value, |
| 7519 StrictModeFlag strict_mode, | 8282 StrictModeFlag strict_mode, |
| 7520 bool check_prototype) { | 8283 bool check_prototype) { |
| 7521 ASSERT(HasFastElements()); | 8284 ASSERT(HasFastElements() || HasFastArgumentsElements()); |
| 7522 | 8285 |
| 7523 Object* elms_obj; | 8286 FixedArray* backing_store = FixedArray::cast(elements()); |
| 7524 { MaybeObject* maybe_elms_obj = EnsureWritableFastElements(); | 8287 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) { |
| 7525 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; | 8288 backing_store = FixedArray::cast(backing_store->get(1)); |
| 8289 } else { |
| 8290 Object* writable; |
| 8291 MaybeObject* maybe = EnsureWritableFastElements(); |
| 8292 if (!maybe->ToObject(&writable)) return maybe; |
| 8293 backing_store = FixedArray::cast(writable); |
| 7526 } | 8294 } |
| 7527 FixedArray* elms = FixedArray::cast(elms_obj); | 8295 uint32_t length = static_cast<uint32_t>(backing_store->length()); |
| 7528 uint32_t elms_length = static_cast<uint32_t>(elms->length()); | |
| 7529 | 8296 |
| 7530 if (check_prototype && | 8297 if (check_prototype && |
| 7531 (index >= elms_length || elms->get(index)->IsTheHole())) { | 8298 (index >= length || backing_store->get(index)->IsTheHole())) { |
| 7532 bool found; | 8299 bool found; |
| 7533 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, | 8300 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, |
| 7534 value, | 8301 value, |
| 8302 &found, |
| 8303 strict_mode); |
| 8304 if (found) return result; |
| 8305 } |
| 8306 |
| 8307 // Check whether there is extra space in fixed array. |
| 8308 if (index < length) { |
| 8309 backing_store->set(index, value); |
| 8310 if (IsJSArray()) { |
| 8311 // Update the length of the array if needed. |
| 8312 uint32_t array_length = 0; |
| 8313 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); |
| 8314 if (index >= array_length) { |
| 8315 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); |
| 8316 } |
| 8317 } |
| 8318 return value; |
| 8319 } |
| 8320 |
| 8321 // Allow gap in fast case. |
| 8322 if ((index - length) < kMaxGap) { |
| 8323 // Try allocating extra space. |
| 8324 int new_capacity = NewElementsCapacity(index + 1); |
| 8325 if (new_capacity <= kMaxFastElementsLength || |
| 8326 !ShouldConvertToSlowElements(new_capacity)) { |
| 8327 ASSERT(static_cast<uint32_t>(new_capacity) > index); |
| 8328 Object* new_elements; |
| 8329 MaybeObject* maybe = |
| 8330 SetFastElementsCapacityAndLength(new_capacity, index + 1); |
| 8331 if (!maybe->ToObject(&new_elements)) return maybe; |
| 8332 FixedArray::cast(new_elements)->set(index, value); |
| 8333 return value; |
| 8334 } |
| 8335 } |
| 8336 |
| 8337 // Otherwise default to slow case. |
| 8338 MaybeObject* result = NormalizeElements(); |
| 8339 if (result->IsFailure()) return result; |
| 8340 return SetDictionaryElement(index, value, strict_mode, check_prototype); |
| 8341 } |
| 8342 |
| 8343 |
| 8344 MaybeObject* JSObject::SetDictionaryElement(uint32_t index, |
| 8345 Object* value, |
| 8346 StrictModeFlag strict_mode, |
| 8347 bool check_prototype) { |
| 8348 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
| 8349 Isolate* isolate = GetIsolate(); |
| 8350 Heap* heap = isolate->heap(); |
| 8351 |
| 8352 // Insert element in the dictionary. |
| 8353 FixedArray* elements = FixedArray::cast(this->elements()); |
| 8354 bool is_arguments = |
| 8355 (elements->map() == heap->non_strict_arguments_elements_map()); |
| 8356 NumberDictionary* dictionary = NULL; |
| 8357 if (is_arguments) { |
| 8358 dictionary = NumberDictionary::cast(elements->get(1)); |
| 8359 } else { |
| 8360 dictionary = NumberDictionary::cast(elements); |
| 8361 } |
| 8362 |
| 8363 int entry = dictionary->FindEntry(index); |
| 8364 if (entry != NumberDictionary::kNotFound) { |
| 8365 Object* element = dictionary->ValueAt(entry); |
| 8366 PropertyDetails details = dictionary->DetailsAt(entry); |
| 8367 if (details.type() == CALLBACKS) { |
| 8368 return SetElementWithCallback(element, index, value, this, strict_mode); |
| 8369 } else { |
| 8370 dictionary->UpdateMaxNumberKey(index); |
| 8371 // If put fails in strict mode, throw an exception. |
| 8372 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) { |
| 8373 Handle<Object> holder(this); |
| 8374 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); |
| 8375 Handle<Object> args[2] = { number, holder }; |
| 8376 Handle<Object> error = |
| 8377 isolate->factory()->NewTypeError("strict_read_only_property", |
| 8378 HandleVector(args, 2)); |
| 8379 return isolate->Throw(*error); |
| 8380 } |
| 8381 } |
| 8382 } else { |
| 8383 // Index not already used. Look for an accessor in the prototype chain. |
| 8384 if (check_prototype) { |
| 8385 bool found; |
| 8386 MaybeObject* result = |
| 8387 SetElementWithCallbackSetterInPrototypes( |
| 8388 index, value, &found, strict_mode); |
| 8389 if (found) return result; |
| 8390 } |
| 8391 // When we set the is_extensible flag to false we always force the |
| 8392 // element into dictionary mode (and force them to stay there). |
| 8393 if (!map()->is_extensible()) { |
| 8394 if (strict_mode == kNonStrictMode) { |
| 8395 return isolate->heap()->undefined_value(); |
| 8396 } else { |
| 8397 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); |
| 8398 Handle<String> name = isolate->factory()->NumberToString(number); |
| 8399 Handle<Object> args[1] = { name }; |
| 8400 Handle<Object> error = |
| 8401 isolate->factory()->NewTypeError("object_not_extensible", |
| 8402 HandleVector(args, 1)); |
| 8403 return isolate->Throw(*error); |
| 8404 } |
| 8405 } |
| 8406 Object* new_dictionary; |
| 8407 MaybeObject* maybe = dictionary->AtNumberPut(index, value); |
| 8408 if (!maybe->ToObject(&new_dictionary)) return maybe; |
| 8409 if (dictionary != NumberDictionary::cast(new_dictionary)) { |
| 8410 if (is_arguments) { |
| 8411 elements->set(1, new_dictionary); |
| 8412 } else { |
| 8413 set_elements(HeapObject::cast(new_dictionary)); |
| 8414 } |
| 8415 dictionary = NumberDictionary::cast(new_dictionary); |
| 8416 } |
| 8417 } |
| 8418 |
| 8419 // Update the array length if this JSObject is an array. |
| 8420 if (IsJSArray()) { |
| 8421 MaybeObject* result = |
| 8422 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value); |
| 8423 if (result->IsFailure()) return result; |
| 8424 } |
| 8425 |
| 8426 // Attempt to put this object back in fast case. |
| 8427 if (ShouldConvertToFastElements()) { |
| 8428 uint32_t new_length = 0; |
| 8429 if (IsJSArray()) { |
| 8430 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); |
| 8431 } else { |
| 8432 new_length = dictionary->max_number_key() + 1; |
| 8433 } |
| 8434 MaybeObject* result = |
| 8435 SetFastElementsCapacityAndLength(new_length, new_length); |
| 8436 if (result->IsFailure()) return result; |
| 8437 #ifdef DEBUG |
| 8438 if (FLAG_trace_normalization) { |
| 8439 PrintF("Object elements are fast case again:\n"); |
| 8440 Print(); |
| 8441 } |
| 8442 #endif |
| 8443 } |
| 8444 return value; |
| 8445 } |
| 8446 |
| 8447 |
| 8448 MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement( |
| 8449 uint32_t index, |
| 8450 Object* value, |
| 8451 StrictModeFlag strict_mode, |
| 8452 bool check_prototype) { |
| 8453 ASSERT(HasFastDoubleElements()); |
| 8454 |
| 8455 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
| 8456 uint32_t elms_length = static_cast<uint32_t>(elms->length()); |
| 8457 |
| 8458 // If storing to an element that isn't in the array, pass the store request |
| 8459 // up the prototype chain before storing in the receiver's elements. |
| 8460 if (check_prototype && |
| 8461 (index >= elms_length || elms->is_the_hole(index))) { |
| 8462 bool found; |
| 8463 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, |
| 8464 value, |
| 7535 &found, | 8465 &found, |
| 7536 strict_mode); | 8466 strict_mode); |
| 7537 if (found) return result; | 8467 if (found) return result; |
| 7538 } | 8468 } |
| 7539 | 8469 |
| 8470 // If the value object is not a heap number, switch to fast elements and try |
| 8471 // again. |
| 8472 bool value_is_smi = value->IsSmi(); |
| 8473 if (!value->IsNumber()) { |
| 8474 Object* obj; |
| 8475 uint32_t length = elms_length; |
| 8476 if (IsJSArray()) { |
| 8477 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); |
| 8478 } |
| 8479 MaybeObject* maybe_obj = |
| 8480 SetFastElementsCapacityAndLength(elms_length, length); |
| 8481 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 8482 return SetFastElement(index, value, strict_mode, check_prototype); |
| 8483 } |
| 7540 | 8484 |
| 7541 // Check whether there is extra space in fixed array.. | 8485 double double_value = value_is_smi |
| 8486 ? static_cast<double>(Smi::cast(value)->value()) |
| 8487 : HeapNumber::cast(value)->value(); |
| 8488 |
| 8489 // Check whether there is extra space in the fixed array. |
| 7542 if (index < elms_length) { | 8490 if (index < elms_length) { |
| 7543 elms->set(index, value); | 8491 elms->set(index, double_value); |
| 7544 if (IsJSArray()) { | 8492 if (IsJSArray()) { |
| 7545 // Update the length of the array if needed. | 8493 // Update the length of the array if needed. |
| 7546 uint32_t array_length = 0; | 8494 uint32_t array_length = 0; |
| 7547 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); | 8495 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); |
| 7548 if (index >= array_length) { | 8496 if (index >= array_length) { |
| 7549 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); | 8497 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); |
| 7550 } | 8498 } |
| 7551 } | 8499 } |
| 7552 return value; | 8500 return value; |
| 7553 } | 8501 } |
| 7554 | 8502 |
| 7555 // Allow gap in fast case. | 8503 // Allow gap in fast case. |
| 7556 if ((index - elms_length) < kMaxGap) { | 8504 if ((index - elms_length) < kMaxGap) { |
| 7557 // Try allocating extra space. | 8505 // Try allocating extra space. |
| 7558 int new_capacity = NewElementsCapacity(index+1); | 8506 int new_capacity = NewElementsCapacity(index+1); |
| 7559 if (new_capacity <= kMaxFastElementsLength || | 8507 if (new_capacity <= kMaxFastElementsLength || |
| 7560 !ShouldConvertToSlowElements(new_capacity)) { | 8508 !ShouldConvertToSlowElements(new_capacity)) { |
| 7561 ASSERT(static_cast<uint32_t>(new_capacity) > index); | 8509 ASSERT(static_cast<uint32_t>(new_capacity) > index); |
| 7562 Object* obj; | 8510 Object* obj; |
| 7563 { MaybeObject* maybe_obj = | 8511 { MaybeObject* maybe_obj = |
| 7564 SetFastElementsCapacityAndLength(new_capacity, index + 1); | 8512 SetFastDoubleElementsCapacityAndLength(new_capacity, |
| 8513 index + 1); |
| 7565 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 8514 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 7566 } | 8515 } |
| 7567 FixedArray::cast(elements())->set(index, value); | 8516 FixedDoubleArray::cast(elements())->set(index, double_value); |
| 7568 return value; | 8517 return value; |
| 7569 } | 8518 } |
| 7570 } | 8519 } |
| 7571 | 8520 |
| 7572 // Otherwise default to slow case. | 8521 // Otherwise default to slow case. |
| 7573 Object* obj; | 8522 Object* obj; |
| 7574 { MaybeObject* maybe_obj = NormalizeElements(); | 8523 { MaybeObject* maybe_obj = NormalizeElements(); |
| 7575 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 8524 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 7576 } | 8525 } |
| 7577 ASSERT(HasDictionaryElements()); | 8526 ASSERT(HasDictionaryElements()); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7619 } | 8568 } |
| 7620 | 8569 |
| 7621 | 8570 |
| 7622 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, | 8571 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, |
| 7623 Object* value, | 8572 Object* value, |
| 7624 StrictModeFlag strict_mode, | 8573 StrictModeFlag strict_mode, |
| 7625 bool check_prototype) { | 8574 bool check_prototype) { |
| 7626 Isolate* isolate = GetIsolate(); | 8575 Isolate* isolate = GetIsolate(); |
| 7627 switch (GetElementsKind()) { | 8576 switch (GetElementsKind()) { |
| 7628 case FAST_ELEMENTS: | 8577 case FAST_ELEMENTS: |
| 7629 // Fast case. | |
| 7630 return SetFastElement(index, value, strict_mode, check_prototype); | 8578 return SetFastElement(index, value, strict_mode, check_prototype); |
| 8579 case FAST_DOUBLE_ELEMENTS: |
| 8580 return SetFastDoubleElement(index, value, strict_mode, check_prototype); |
| 7631 case EXTERNAL_PIXEL_ELEMENTS: { | 8581 case EXTERNAL_PIXEL_ELEMENTS: { |
| 7632 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); | 8582 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); |
| 7633 return pixels->SetValue(index, value); | 8583 return pixels->SetValue(index, value); |
| 7634 } | 8584 } |
| 7635 case EXTERNAL_BYTE_ELEMENTS: { | 8585 case EXTERNAL_BYTE_ELEMENTS: { |
| 7636 ExternalByteArray* array = ExternalByteArray::cast(elements()); | 8586 ExternalByteArray* array = ExternalByteArray::cast(elements()); |
| 7637 return array->SetValue(index, value); | 8587 return array->SetValue(index, value); |
| 7638 } | 8588 } |
| 7639 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { | 8589 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { |
| 7640 ExternalUnsignedByteArray* array = | 8590 ExternalUnsignedByteArray* array = |
| (...skipping 19 matching lines...) Expand all Loading... |
| 7660 return array->SetValue(index, value); | 8610 return array->SetValue(index, value); |
| 7661 } | 8611 } |
| 7662 case EXTERNAL_FLOAT_ELEMENTS: { | 8612 case EXTERNAL_FLOAT_ELEMENTS: { |
| 7663 ExternalFloatArray* array = ExternalFloatArray::cast(elements()); | 8613 ExternalFloatArray* array = ExternalFloatArray::cast(elements()); |
| 7664 return array->SetValue(index, value); | 8614 return array->SetValue(index, value); |
| 7665 } | 8615 } |
| 7666 case EXTERNAL_DOUBLE_ELEMENTS: { | 8616 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 7667 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements()); | 8617 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements()); |
| 7668 return array->SetValue(index, value); | 8618 return array->SetValue(index, value); |
| 7669 } | 8619 } |
| 7670 case DICTIONARY_ELEMENTS: { | 8620 case DICTIONARY_ELEMENTS: |
| 7671 // Insert element in the dictionary. | 8621 return SetDictionaryElement(index, value, strict_mode, check_prototype); |
| 7672 FixedArray* elms = FixedArray::cast(elements()); | 8622 case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| 7673 NumberDictionary* dictionary = NumberDictionary::cast(elms); | 8623 FixedArray* parameter_map = FixedArray::cast(elements()); |
| 7674 | 8624 uint32_t length = parameter_map->length(); |
| 7675 int entry = dictionary->FindEntry(index); | 8625 Object* probe = |
| 7676 if (entry != NumberDictionary::kNotFound) { | 8626 (index < length - 2) ? parameter_map->get(index + 2) : NULL; |
| 7677 Object* element = dictionary->ValueAt(entry); | 8627 if (probe != NULL && !probe->IsTheHole()) { |
| 7678 PropertyDetails details = dictionary->DetailsAt(entry); | 8628 Context* context = Context::cast(parameter_map->get(0)); |
| 7679 if (details.type() == CALLBACKS) { | 8629 int context_index = Smi::cast(probe)->value(); |
| 7680 return SetElementWithCallback(element, | 8630 ASSERT(!context->get(context_index)->IsTheHole()); |
| 7681 index, | 8631 context->set(context_index, value); |
| 7682 value, | 8632 return value; |
| 7683 this, | 8633 } else { |
| 7684 strict_mode); | 8634 // Object is not mapped, defer to the arguments. |
| 8635 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 8636 if (arguments->IsDictionary()) { |
| 8637 return SetDictionaryElement(index, value, strict_mode, |
| 8638 check_prototype); |
| 7685 } else { | 8639 } else { |
| 7686 dictionary->UpdateMaxNumberKey(index); | 8640 return SetFastElement(index, value, strict_mode, check_prototype); |
| 7687 // If put fails instrict mode, throw exception. | |
| 7688 if (!dictionary->ValueAtPut(entry, value) && | |
| 7689 strict_mode == kStrictMode) { | |
| 7690 Handle<Object> holder(this); | |
| 7691 Handle<Object> number(isolate->factory()->NewNumberFromUint(index)); | |
| 7692 Handle<Object> args[2] = { number, holder }; | |
| 7693 return isolate->Throw( | |
| 7694 *isolate->factory()->NewTypeError("strict_read_only_property", | |
| 7695 HandleVector(args, 2))); | |
| 7696 } | |
| 7697 } | |
| 7698 } else { | |
| 7699 // Index not already used. Look for an accessor in the prototype chain. | |
| 7700 if (check_prototype) { | |
| 7701 bool found; | |
| 7702 MaybeObject* result = | |
| 7703 // Strict mode not needed. No-setter case already handled. | |
| 7704 SetElementWithCallbackSetterInPrototypes(index, | |
| 7705 value, | |
| 7706 &found, | |
| 7707 strict_mode); | |
| 7708 if (found) return result; | |
| 7709 } | |
| 7710 // When we set the is_extensible flag to false we always force | |
| 7711 // the element into dictionary mode (and force them to stay there). | |
| 7712 if (!map()->is_extensible()) { | |
| 7713 if (strict_mode == kNonStrictMode) { | |
| 7714 return isolate->heap()->undefined_value(); | |
| 7715 } else { | |
| 7716 Handle<Object> number(isolate->factory()->NewNumberFromUint(index)); | |
| 7717 Handle<String> index_string( | |
| 7718 isolate->factory()->NumberToString(number)); | |
| 7719 Handle<Object> args[1] = { index_string }; | |
| 7720 return isolate->Throw( | |
| 7721 *isolate->factory()->NewTypeError("object_not_extensible", | |
| 7722 HandleVector(args, 1))); | |
| 7723 } | |
| 7724 } | |
| 7725 Object* result; | |
| 7726 { MaybeObject* maybe_result = dictionary->AtNumberPut(index, value); | |
| 7727 if (!maybe_result->ToObject(&result)) return maybe_result; | |
| 7728 } | |
| 7729 if (elms != FixedArray::cast(result)) { | |
| 7730 set_elements(FixedArray::cast(result)); | |
| 7731 } | 8641 } |
| 7732 } | 8642 } |
| 7733 | |
| 7734 // Update the array length if this JSObject is an array. | |
| 7735 if (IsJSArray()) { | |
| 7736 JSArray* array = JSArray::cast(this); | |
| 7737 Object* return_value; | |
| 7738 { MaybeObject* maybe_return_value = | |
| 7739 array->JSArrayUpdateLengthFromIndex(index, value); | |
| 7740 if (!maybe_return_value->ToObject(&return_value)) { | |
| 7741 return maybe_return_value; | |
| 7742 } | |
| 7743 } | |
| 7744 } | |
| 7745 | |
| 7746 // Attempt to put this object back in fast case. | |
| 7747 if (ShouldConvertToFastElements()) { | |
| 7748 uint32_t new_length = 0; | |
| 7749 if (IsJSArray()) { | |
| 7750 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); | |
| 7751 } else { | |
| 7752 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; | |
| 7753 } | |
| 7754 Object* obj; | |
| 7755 { MaybeObject* maybe_obj = | |
| 7756 SetFastElementsCapacityAndLength(new_length, new_length); | |
| 7757 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
| 7758 } | |
| 7759 #ifdef DEBUG | |
| 7760 if (FLAG_trace_normalization) { | |
| 7761 PrintF("Object elements are fast case again:\n"); | |
| 7762 Print(); | |
| 7763 } | |
| 7764 #endif | |
| 7765 } | |
| 7766 | |
| 7767 return value; | |
| 7768 } | 8643 } |
| 7769 default: | |
| 7770 UNREACHABLE(); | |
| 7771 break; | |
| 7772 } | 8644 } |
| 7773 // All possible cases have been handled above. Add a return to avoid the | 8645 // All possible cases have been handled above. Add a return to avoid the |
| 7774 // complaints from the compiler. | 8646 // complaints from the compiler. |
| 7775 UNREACHABLE(); | 8647 UNREACHABLE(); |
| 7776 return isolate->heap()->null_value(); | 8648 return isolate->heap()->null_value(); |
| 7777 } | 8649 } |
| 7778 | 8650 |
| 7779 | 8651 |
| 7780 MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, | 8652 MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, |
| 7781 Object* value) { | 8653 Object* value) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 7801 // JSArray::length cannot change. | 8673 // JSArray::length cannot change. |
| 7802 switch (GetElementsKind()) { | 8674 switch (GetElementsKind()) { |
| 7803 case FAST_ELEMENTS: { | 8675 case FAST_ELEMENTS: { |
| 7804 FixedArray* elms = FixedArray::cast(elements()); | 8676 FixedArray* elms = FixedArray::cast(elements()); |
| 7805 if (index < static_cast<uint32_t>(elms->length())) { | 8677 if (index < static_cast<uint32_t>(elms->length())) { |
| 7806 Object* value = elms->get(index); | 8678 Object* value = elms->get(index); |
| 7807 if (!value->IsTheHole()) return value; | 8679 if (!value->IsTheHole()) return value; |
| 7808 } | 8680 } |
| 7809 break; | 8681 break; |
| 7810 } | 8682 } |
| 8683 case FAST_DOUBLE_ELEMENTS: { |
| 8684 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
| 8685 if (index < static_cast<uint32_t>(elms->length())) { |
| 8686 if (!elms->is_the_hole(index)) { |
| 8687 return GetHeap()->NumberFromDouble(elms->get(index)); |
| 8688 } |
| 8689 } |
| 8690 break; |
| 8691 } |
| 7811 case EXTERNAL_PIXEL_ELEMENTS: | 8692 case EXTERNAL_PIXEL_ELEMENTS: |
| 7812 case EXTERNAL_BYTE_ELEMENTS: | 8693 case EXTERNAL_BYTE_ELEMENTS: |
| 7813 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 8694 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 7814 case EXTERNAL_SHORT_ELEMENTS: | 8695 case EXTERNAL_SHORT_ELEMENTS: |
| 7815 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 8696 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 7816 case EXTERNAL_INT_ELEMENTS: | 8697 case EXTERNAL_INT_ELEMENTS: |
| 7817 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 8698 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7818 case EXTERNAL_FLOAT_ELEMENTS: | 8699 case EXTERNAL_FLOAT_ELEMENTS: |
| 7819 case EXTERNAL_DOUBLE_ELEMENTS: { | 8700 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 7820 MaybeObject* maybe_value = GetExternalElement(index); | 8701 MaybeObject* maybe_value = GetExternalElement(index); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 7832 if (details.type() == CALLBACKS) { | 8713 if (details.type() == CALLBACKS) { |
| 7833 return GetElementWithCallback(receiver, | 8714 return GetElementWithCallback(receiver, |
| 7834 element, | 8715 element, |
| 7835 index, | 8716 index, |
| 7836 this); | 8717 this); |
| 7837 } | 8718 } |
| 7838 return element; | 8719 return element; |
| 7839 } | 8720 } |
| 7840 break; | 8721 break; |
| 7841 } | 8722 } |
| 7842 default: | 8723 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 7843 UNREACHABLE(); | 8724 UNIMPLEMENTED(); |
| 7844 break; | 8725 break; |
| 7845 } | 8726 } |
| 7846 | 8727 |
| 7847 // Continue searching via the prototype chain. | 8728 // Continue searching via the prototype chain. |
| 7848 Object* pt = GetPrototype(); | 8729 Object* pt = GetPrototype(); |
| 7849 if (pt->IsNull()) return GetHeap()->undefined_value(); | 8730 if (pt->IsNull()) return GetHeap()->undefined_value(); |
| 7850 return pt->GetElementWithReceiver(receiver, index); | 8731 return pt->GetElementWithReceiver(receiver, index); |
| 7851 } | 8732 } |
| 7852 | 8733 |
| 7853 | 8734 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7904 // JSArray::length cannot change. | 8785 // JSArray::length cannot change. |
| 7905 switch (GetElementsKind()) { | 8786 switch (GetElementsKind()) { |
| 7906 case FAST_ELEMENTS: { | 8787 case FAST_ELEMENTS: { |
| 7907 FixedArray* elms = FixedArray::cast(elements()); | 8788 FixedArray* elms = FixedArray::cast(elements()); |
| 7908 if (index < static_cast<uint32_t>(elms->length())) { | 8789 if (index < static_cast<uint32_t>(elms->length())) { |
| 7909 Object* value = elms->get(index); | 8790 Object* value = elms->get(index); |
| 7910 if (!value->IsTheHole()) return value; | 8791 if (!value->IsTheHole()) return value; |
| 7911 } | 8792 } |
| 7912 break; | 8793 break; |
| 7913 } | 8794 } |
| 8795 case FAST_DOUBLE_ELEMENTS: { |
| 8796 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
| 8797 if (index < static_cast<uint32_t>(elms->length())) { |
| 8798 if (!elms->is_the_hole(index)) { |
| 8799 double double_value = elms->get(index); |
| 8800 return GetHeap()->NumberFromDouble(double_value); |
| 8801 } |
| 8802 } |
| 8803 break; |
| 8804 } |
| 7914 case EXTERNAL_PIXEL_ELEMENTS: | 8805 case EXTERNAL_PIXEL_ELEMENTS: |
| 7915 case EXTERNAL_BYTE_ELEMENTS: | 8806 case EXTERNAL_BYTE_ELEMENTS: |
| 7916 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 8807 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 7917 case EXTERNAL_SHORT_ELEMENTS: | 8808 case EXTERNAL_SHORT_ELEMENTS: |
| 7918 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 8809 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 7919 case EXTERNAL_INT_ELEMENTS: | 8810 case EXTERNAL_INT_ELEMENTS: |
| 7920 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 8811 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7921 case EXTERNAL_FLOAT_ELEMENTS: | 8812 case EXTERNAL_FLOAT_ELEMENTS: |
| 7922 case EXTERNAL_DOUBLE_ELEMENTS: { | 8813 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 7923 MaybeObject* maybe_value = GetExternalElement(index); | 8814 MaybeObject* maybe_value = GetExternalElement(index); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 7935 if (details.type() == CALLBACKS) { | 8826 if (details.type() == CALLBACKS) { |
| 7936 return GetElementWithCallback(receiver, | 8827 return GetElementWithCallback(receiver, |
| 7937 element, | 8828 element, |
| 7938 index, | 8829 index, |
| 7939 this); | 8830 this); |
| 7940 } | 8831 } |
| 7941 return element; | 8832 return element; |
| 7942 } | 8833 } |
| 7943 break; | 8834 break; |
| 7944 } | 8835 } |
| 8836 case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| 8837 FixedArray* parameter_map = FixedArray::cast(elements()); |
| 8838 uint32_t length = parameter_map->length(); |
| 8839 Object* probe = |
| 8840 (index < length - 2) ? parameter_map->get(index + 2) : NULL; |
| 8841 if (probe != NULL && !probe->IsTheHole()) { |
| 8842 Context* context = Context::cast(parameter_map->get(0)); |
| 8843 int context_index = Smi::cast(probe)->value(); |
| 8844 ASSERT(!context->get(context_index)->IsTheHole()); |
| 8845 return context->get(context_index); |
| 8846 } else { |
| 8847 // Object is not mapped, defer to the arguments. |
| 8848 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 8849 if (arguments->IsDictionary()) { |
| 8850 NumberDictionary* dictionary = NumberDictionary::cast(arguments); |
| 8851 int entry = dictionary->FindEntry(index); |
| 8852 if (entry != NumberDictionary::kNotFound) { |
| 8853 Object* element = dictionary->ValueAt(entry); |
| 8854 PropertyDetails details = dictionary->DetailsAt(entry); |
| 8855 if (details.type() == CALLBACKS) { |
| 8856 return GetElementWithCallback(receiver, |
| 8857 element, |
| 8858 index, |
| 8859 this); |
| 8860 } |
| 8861 return element; |
| 8862 } |
| 8863 } else if (index < static_cast<uint32_t>(arguments->length())) { |
| 8864 Object* value = arguments->get(index); |
| 8865 if (!value->IsTheHole()) return value; |
| 8866 } |
| 8867 } |
| 8868 break; |
| 8869 } |
| 7945 } | 8870 } |
| 7946 | 8871 |
| 7947 Object* pt = GetPrototype(); | 8872 Object* pt = GetPrototype(); |
| 7948 Heap* heap = GetHeap(); | 8873 Heap* heap = GetHeap(); |
| 7949 if (pt == heap->null_value()) return heap->undefined_value(); | 8874 if (pt == heap->null_value()) return heap->undefined_value(); |
| 7950 return pt->GetElementWithReceiver(receiver, index); | 8875 return pt->GetElementWithReceiver(receiver, index); |
| 7951 } | 8876 } |
| 7952 | 8877 |
| 7953 | 8878 |
| 7954 MaybeObject* JSObject::GetExternalElement(uint32_t index) { | 8879 MaybeObject* JSObject::GetExternalElement(uint32_t index) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8023 break; | 8948 break; |
| 8024 } | 8949 } |
| 8025 case EXTERNAL_DOUBLE_ELEMENTS: { | 8950 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 8026 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements()); | 8951 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements()); |
| 8027 if (index < static_cast<uint32_t>(array->length())) { | 8952 if (index < static_cast<uint32_t>(array->length())) { |
| 8028 double value = array->get(index); | 8953 double value = array->get(index); |
| 8029 return GetHeap()->AllocateHeapNumber(value); | 8954 return GetHeap()->AllocateHeapNumber(value); |
| 8030 } | 8955 } |
| 8031 break; | 8956 break; |
| 8032 } | 8957 } |
| 8958 case FAST_DOUBLE_ELEMENTS: |
| 8033 case FAST_ELEMENTS: | 8959 case FAST_ELEMENTS: |
| 8034 case DICTIONARY_ELEMENTS: | 8960 case DICTIONARY_ELEMENTS: |
| 8035 UNREACHABLE(); | 8961 UNREACHABLE(); |
| 8036 break; | 8962 break; |
| 8963 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 8964 UNIMPLEMENTED(); |
| 8965 break; |
| 8037 } | 8966 } |
| 8038 return GetHeap()->undefined_value(); | 8967 return GetHeap()->undefined_value(); |
| 8039 } | 8968 } |
| 8040 | 8969 |
| 8041 | 8970 |
| 8042 bool JSObject::HasDenseElements() { | 8971 bool JSObject::HasDenseElements() { |
| 8043 int capacity = 0; | 8972 int capacity = 0; |
| 8044 int number_of_elements = 0; | 8973 int number_of_elements = 0; |
| 8045 | 8974 |
| 8975 FixedArray* backing_store = FixedArray::cast(elements()); |
| 8046 switch (GetElementsKind()) { | 8976 switch (GetElementsKind()) { |
| 8047 case FAST_ELEMENTS: { | 8977 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 8048 FixedArray* elms = FixedArray::cast(elements()); | 8978 backing_store = FixedArray::cast(backing_store->get(1)); |
| 8979 if (backing_store->IsDictionary()) { |
| 8980 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
| 8981 capacity = dictionary->Capacity(); |
| 8982 number_of_elements = dictionary->NumberOfElements(); |
| 8983 break; |
| 8984 } |
| 8985 // Fall through. |
| 8986 case FAST_ELEMENTS: |
| 8987 capacity = backing_store->length(); |
| 8988 for (int i = 0; i < capacity; ++i) { |
| 8989 if (!backing_store->get(i)->IsTheHole()) ++number_of_elements; |
| 8990 } |
| 8991 break; |
| 8992 case DICTIONARY_ELEMENTS: { |
| 8993 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
| 8994 capacity = dictionary->Capacity(); |
| 8995 number_of_elements = dictionary->NumberOfElements(); |
| 8996 break; |
| 8997 } |
| 8998 case FAST_DOUBLE_ELEMENTS: { |
| 8999 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
| 8049 capacity = elms->length(); | 9000 capacity = elms->length(); |
| 8050 for (int i = 0; i < capacity; i++) { | 9001 for (int i = 0; i < capacity; i++) { |
| 8051 if (!elms->get(i)->IsTheHole()) number_of_elements++; | 9002 if (!elms->is_the_hole(i)) number_of_elements++; |
| 8052 } | 9003 } |
| 8053 break; | 9004 break; |
| 8054 } | 9005 } |
| 8055 case EXTERNAL_PIXEL_ELEMENTS: | 9006 case EXTERNAL_PIXEL_ELEMENTS: |
| 8056 case EXTERNAL_BYTE_ELEMENTS: | 9007 case EXTERNAL_BYTE_ELEMENTS: |
| 8057 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 9008 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 8058 case EXTERNAL_SHORT_ELEMENTS: | 9009 case EXTERNAL_SHORT_ELEMENTS: |
| 8059 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 9010 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 8060 case EXTERNAL_INT_ELEMENTS: | 9011 case EXTERNAL_INT_ELEMENTS: |
| 8061 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 9012 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 8062 case EXTERNAL_FLOAT_ELEMENTS: | 9013 case EXTERNAL_FLOAT_ELEMENTS: |
| 8063 case EXTERNAL_DOUBLE_ELEMENTS: { | 9014 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 8064 return true; | 9015 return true; |
| 8065 } | 9016 } |
| 8066 case DICTIONARY_ELEMENTS: { | |
| 8067 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | |
| 8068 capacity = dictionary->Capacity(); | |
| 8069 number_of_elements = dictionary->NumberOfElements(); | |
| 8070 break; | |
| 8071 } | |
| 8072 default: | |
| 8073 UNREACHABLE(); | |
| 8074 break; | |
| 8075 } | 9017 } |
| 8076 | 9018 return (capacity == 0) || (number_of_elements > (capacity / 2)); |
| 8077 if (capacity == 0) return true; | |
| 8078 return (number_of_elements > (capacity / 2)); | |
| 8079 } | 9019 } |
| 8080 | 9020 |
| 8081 | 9021 |
| 8082 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { | 9022 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { |
| 8083 ASSERT(HasFastElements()); | |
| 8084 // Keep the array in fast case if the current backing storage is | 9023 // Keep the array in fast case if the current backing storage is |
| 8085 // almost filled and if the new capacity is no more than twice the | 9024 // almost filled and if the new capacity is no more than twice the |
| 8086 // old capacity. | 9025 // old capacity. |
| 8087 int elements_length = FixedArray::cast(elements())->length(); | 9026 int elements_length = 0; |
| 9027 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) { |
| 9028 FixedArray* backing_store = FixedArray::cast(elements()); |
| 9029 elements_length = FixedArray::cast(backing_store->get(1))->length(); |
| 9030 } else if (HasFastElements()) { |
| 9031 elements_length = FixedArray::cast(elements())->length(); |
| 9032 } else if (HasFastDoubleElements()) { |
| 9033 elements_length = FixedDoubleArray::cast(elements())->length(); |
| 9034 } else { |
| 9035 UNREACHABLE(); |
| 9036 } |
| 8088 return !HasDenseElements() || ((new_capacity / 2) > elements_length); | 9037 return !HasDenseElements() || ((new_capacity / 2) > elements_length); |
| 8089 } | 9038 } |
| 8090 | 9039 |
| 8091 | 9040 |
| 8092 bool JSObject::ShouldConvertToFastElements() { | 9041 bool JSObject::ShouldConvertToFastElements() { |
| 8093 ASSERT(HasDictionaryElements()); | 9042 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
| 8094 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | |
| 8095 // If the elements are sparse, we should not go back to fast case. | 9043 // If the elements are sparse, we should not go back to fast case. |
| 8096 if (!HasDenseElements()) return false; | 9044 if (!HasDenseElements()) return false; |
| 9045 // An object requiring access checks is never allowed to have fast |
| 9046 // elements. If it had fast elements we would skip security checks. |
| 9047 if (IsAccessCheckNeeded()) return false; |
| 9048 |
| 9049 FixedArray* elements = FixedArray::cast(this->elements()); |
| 9050 NumberDictionary* dictionary = NULL; |
| 9051 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) { |
| 9052 dictionary = NumberDictionary::cast(elements->get(1)); |
| 9053 } else { |
| 9054 dictionary = NumberDictionary::cast(elements); |
| 9055 } |
| 8097 // If an element has been added at a very high index in the elements | 9056 // If an element has been added at a very high index in the elements |
| 8098 // dictionary, we cannot go back to fast case. | 9057 // dictionary, we cannot go back to fast case. |
| 8099 if (dictionary->requires_slow_elements()) return false; | 9058 if (dictionary->requires_slow_elements()) return false; |
| 8100 // An object requiring access checks is never allowed to have fast | |
| 8101 // elements. If it had fast elements we would skip security checks. | |
| 8102 if (IsAccessCheckNeeded()) return false; | |
| 8103 // If the dictionary backing storage takes up roughly half as much | 9059 // If the dictionary backing storage takes up roughly half as much |
| 8104 // space as a fast-case backing storage would the array should have | 9060 // space as a fast-case backing storage would the array should have |
| 8105 // fast elements. | 9061 // fast elements. |
| 8106 uint32_t length = 0; | 9062 uint32_t length = 0; |
| 8107 if (IsJSArray()) { | 9063 if (IsJSArray()) { |
| 8108 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); | 9064 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); |
| 8109 } else { | 9065 } else { |
| 8110 length = dictionary->max_number_key(); | 9066 length = dictionary->max_number_key(); |
| 8111 } | 9067 } |
| 8112 return static_cast<uint32_t>(dictionary->Capacity()) >= | 9068 return static_cast<uint32_t>(dictionary->Capacity()) >= |
| 8113 (length / (2 * NumberDictionary::kEntrySize)); | 9069 (length / (2 * NumberDictionary::kEntrySize)); |
| 8114 } | 9070 } |
| 8115 | 9071 |
| 8116 | 9072 |
| 9073 bool JSObject::ShouldConvertToFastDoubleElements() { |
| 9074 if (FLAG_unbox_double_arrays) { |
| 9075 ASSERT(HasDictionaryElements()); |
| 9076 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
| 9077 for (int i = 0; i < dictionary->Capacity(); i++) { |
| 9078 Object* key = dictionary->KeyAt(i); |
| 9079 if (key->IsNumber()) { |
| 9080 if (!dictionary->ValueAt(i)->IsNumber()) return false; |
| 9081 } |
| 9082 } |
| 9083 return true; |
| 9084 } else { |
| 9085 return false; |
| 9086 } |
| 9087 } |
| 9088 |
| 9089 |
| 8117 // Certain compilers request function template instantiation when they | 9090 // Certain compilers request function template instantiation when they |
| 8118 // see the definition of the other template functions in the | 9091 // see the definition of the other template functions in the |
| 8119 // class. This requires us to have the template functions put | 9092 // class. This requires us to have the template functions put |
| 8120 // together, so even though this function belongs in objects-debug.cc, | 9093 // together, so even though this function belongs in objects-debug.cc, |
| 8121 // we keep it here instead to satisfy certain compilers. | 9094 // we keep it here instead to satisfy certain compilers. |
| 8122 #ifdef OBJECT_PRINT | 9095 #ifdef OBJECT_PRINT |
| 8123 template<typename Shape, typename Key> | 9096 template<typename Shape, typename Key> |
| 8124 void Dictionary<Shape, Key>::Print(FILE* out) { | 9097 void Dictionary<Shape, Key>::Print(FILE* out) { |
| 8125 int capacity = HashTable<Shape, Key>::Capacity(); | 9098 int capacity = HashTable<Shape, Key>::Capacity(); |
| 8126 for (int i = 0; i < capacity; i++) { | 9099 for (int i = 0; i < capacity; i++) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8171 ASSERT(map()->has_indexed_interceptor()); | 9144 ASSERT(map()->has_indexed_interceptor()); |
| 8172 JSFunction* constructor = JSFunction::cast(map()->constructor()); | 9145 JSFunction* constructor = JSFunction::cast(map()->constructor()); |
| 8173 ASSERT(constructor->shared()->IsApiFunction()); | 9146 ASSERT(constructor->shared()->IsApiFunction()); |
| 8174 Object* result = | 9147 Object* result = |
| 8175 constructor->shared()->get_api_func_data()->indexed_property_handler(); | 9148 constructor->shared()->get_api_func_data()->indexed_property_handler(); |
| 8176 return InterceptorInfo::cast(result); | 9149 return InterceptorInfo::cast(result); |
| 8177 } | 9150 } |
| 8178 | 9151 |
| 8179 | 9152 |
| 8180 MaybeObject* JSObject::GetPropertyPostInterceptor( | 9153 MaybeObject* JSObject::GetPropertyPostInterceptor( |
| 8181 JSObject* receiver, | 9154 JSReceiver* receiver, |
| 8182 String* name, | 9155 String* name, |
| 8183 PropertyAttributes* attributes) { | 9156 PropertyAttributes* attributes) { |
| 8184 // Check local property in holder, ignore interceptor. | 9157 // Check local property in holder, ignore interceptor. |
| 8185 LookupResult result; | 9158 LookupResult result; |
| 8186 LocalLookupRealNamedProperty(name, &result); | 9159 LocalLookupRealNamedProperty(name, &result); |
| 8187 if (result.IsProperty()) { | 9160 if (result.IsProperty()) { |
| 8188 return GetProperty(receiver, &result, name, attributes); | 9161 return GetProperty(receiver, &result, name, attributes); |
| 8189 } | 9162 } |
| 8190 // Continue searching via the prototype chain. | 9163 // Continue searching via the prototype chain. |
| 8191 Object* pt = GetPrototype(); | 9164 Object* pt = GetPrototype(); |
| 8192 *attributes = ABSENT; | 9165 *attributes = ABSENT; |
| 8193 if (pt->IsNull()) return GetHeap()->undefined_value(); | 9166 if (pt->IsNull()) return GetHeap()->undefined_value(); |
| 8194 return pt->GetPropertyWithReceiver(receiver, name, attributes); | 9167 return pt->GetPropertyWithReceiver(receiver, name, attributes); |
| 8195 } | 9168 } |
| 8196 | 9169 |
| 8197 | 9170 |
| 8198 MaybeObject* JSObject::GetLocalPropertyPostInterceptor( | 9171 MaybeObject* JSObject::GetLocalPropertyPostInterceptor( |
| 8199 JSObject* receiver, | 9172 JSReceiver* receiver, |
| 8200 String* name, | 9173 String* name, |
| 8201 PropertyAttributes* attributes) { | 9174 PropertyAttributes* attributes) { |
| 8202 // Check local property in holder, ignore interceptor. | 9175 // Check local property in holder, ignore interceptor. |
| 8203 LookupResult result; | 9176 LookupResult result; |
| 8204 LocalLookupRealNamedProperty(name, &result); | 9177 LocalLookupRealNamedProperty(name, &result); |
| 8205 if (result.IsProperty()) { | 9178 if (result.IsProperty()) { |
| 8206 return GetProperty(receiver, &result, name, attributes); | 9179 return GetProperty(receiver, &result, name, attributes); |
| 8207 } | 9180 } |
| 8208 return GetHeap()->undefined_value(); | 9181 return GetHeap()->undefined_value(); |
| 8209 } | 9182 } |
| 8210 | 9183 |
| 8211 | 9184 |
| 8212 MaybeObject* JSObject::GetPropertyWithInterceptor( | 9185 MaybeObject* JSObject::GetPropertyWithInterceptor( |
| 8213 JSObject* receiver, | 9186 JSReceiver* receiver, |
| 8214 String* name, | 9187 String* name, |
| 8215 PropertyAttributes* attributes) { | 9188 PropertyAttributes* attributes) { |
| 8216 Isolate* isolate = GetIsolate(); | 9189 Isolate* isolate = GetIsolate(); |
| 8217 InterceptorInfo* interceptor = GetNamedInterceptor(); | 9190 InterceptorInfo* interceptor = GetNamedInterceptor(); |
| 8218 HandleScope scope(isolate); | 9191 HandleScope scope(isolate); |
| 8219 Handle<JSObject> receiver_handle(receiver); | 9192 Handle<JSReceiver> receiver_handle(receiver); |
| 8220 Handle<JSObject> holder_handle(this); | 9193 Handle<JSObject> holder_handle(this); |
| 8221 Handle<String> name_handle(name); | 9194 Handle<String> name_handle(name); |
| 8222 | 9195 |
| 8223 if (!interceptor->getter()->IsUndefined()) { | 9196 if (!interceptor->getter()->IsUndefined()) { |
| 8224 v8::NamedPropertyGetter getter = | 9197 v8::NamedPropertyGetter getter = |
| 8225 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); | 9198 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); |
| 8226 LOG(isolate, | 9199 LOG(isolate, |
| 8227 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name)); | 9200 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name)); |
| 8228 CustomArguments args(isolate, interceptor->data(), receiver, this); | 9201 CustomArguments args(isolate, interceptor->data(), receiver, this); |
| 8229 v8::AccessorInfo info(args.end()); | 9202 v8::AccessorInfo info(args.end()); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8295 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 9268 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 8296 case EXTERNAL_SHORT_ELEMENTS: | 9269 case EXTERNAL_SHORT_ELEMENTS: |
| 8297 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 9270 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 8298 case EXTERNAL_INT_ELEMENTS: | 9271 case EXTERNAL_INT_ELEMENTS: |
| 8299 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 9272 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 8300 case EXTERNAL_FLOAT_ELEMENTS: | 9273 case EXTERNAL_FLOAT_ELEMENTS: |
| 8301 case EXTERNAL_DOUBLE_ELEMENTS: { | 9274 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 8302 ExternalArray* array = ExternalArray::cast(elements()); | 9275 ExternalArray* array = ExternalArray::cast(elements()); |
| 8303 return index < static_cast<uint32_t>(array->length()); | 9276 return index < static_cast<uint32_t>(array->length()); |
| 8304 } | 9277 } |
| 9278 case FAST_DOUBLE_ELEMENTS: |
| 9279 UNREACHABLE(); |
| 9280 break; |
| 8305 case DICTIONARY_ELEMENTS: { | 9281 case DICTIONARY_ELEMENTS: { |
| 8306 return element_dictionary()->FindEntry(index) | 9282 return element_dictionary()->FindEntry(index) |
| 8307 != NumberDictionary::kNotFound; | 9283 != NumberDictionary::kNotFound; |
| 8308 } | 9284 } |
| 8309 default: | 9285 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 8310 UNREACHABLE(); | 9286 UNIMPLEMENTED(); |
| 8311 break; | 9287 break; |
| 8312 } | 9288 } |
| 8313 // All possibilities have been handled above already. | 9289 // All possibilities have been handled above already. |
| 8314 UNREACHABLE(); | 9290 UNREACHABLE(); |
| 8315 return GetHeap()->null_value(); | 9291 return GetHeap()->null_value(); |
| 8316 } | 9292 } |
| 8317 | 9293 |
| 8318 | 9294 |
| 8319 bool JSObject::HasRealNamedCallbackProperty(String* key) { | 9295 bool JSObject::HasRealNamedCallbackProperty(String* key) { |
| 8320 // Check access rights if needed. | 9296 // Check access rights if needed. |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8472 // mirrors. | 9448 // mirrors. |
| 8473 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { | 9449 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { |
| 8474 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index)); | 9450 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index)); |
| 8475 if (HasFastProperties()) { | 9451 if (HasFastProperties()) { |
| 8476 DescriptorArray* descs = map()->instance_descriptors(); | 9452 DescriptorArray* descs = map()->instance_descriptors(); |
| 8477 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 9453 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 8478 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i)); | 9454 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i)); |
| 8479 } | 9455 } |
| 8480 ASSERT(storage->length() >= index); | 9456 ASSERT(storage->length() >= index); |
| 8481 } else { | 9457 } else { |
| 8482 property_dictionary()->CopyKeysTo(storage); | 9458 property_dictionary()->CopyKeysTo(storage, StringDictionary::UNSORTED); |
| 8483 } | 9459 } |
| 8484 } | 9460 } |
| 8485 | 9461 |
| 8486 | 9462 |
| 8487 int JSObject::NumberOfLocalElements(PropertyAttributes filter) { | 9463 int JSObject::NumberOfLocalElements(PropertyAttributes filter) { |
| 8488 return GetLocalElementKeys(NULL, filter); | 9464 return GetLocalElementKeys(NULL, filter); |
| 8489 } | 9465 } |
| 8490 | 9466 |
| 8491 | 9467 |
| 8492 int JSObject::NumberOfEnumElements() { | 9468 int JSObject::NumberOfEnumElements() { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8544 int length = ExternalArray::cast(elements())->length(); | 9520 int length = ExternalArray::cast(elements())->length(); |
| 8545 while (counter < length) { | 9521 while (counter < length) { |
| 8546 if (storage != NULL) { | 9522 if (storage != NULL) { |
| 8547 storage->set(counter, Smi::FromInt(counter)); | 9523 storage->set(counter, Smi::FromInt(counter)); |
| 8548 } | 9524 } |
| 8549 counter++; | 9525 counter++; |
| 8550 } | 9526 } |
| 8551 ASSERT(!storage || storage->length() >= counter); | 9527 ASSERT(!storage || storage->length() >= counter); |
| 8552 break; | 9528 break; |
| 8553 } | 9529 } |
| 9530 case FAST_DOUBLE_ELEMENTS: |
| 9531 UNREACHABLE(); |
| 9532 break; |
| 8554 case DICTIONARY_ELEMENTS: { | 9533 case DICTIONARY_ELEMENTS: { |
| 8555 if (storage != NULL) { | 9534 if (storage != NULL) { |
| 8556 element_dictionary()->CopyKeysTo(storage, filter); | 9535 element_dictionary()->CopyKeysTo(storage, |
| 9536 filter, |
| 9537 NumberDictionary::SORTED); |
| 8557 } | 9538 } |
| 8558 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); | 9539 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter); |
| 8559 break; | 9540 break; |
| 8560 } | 9541 } |
| 8561 default: | 9542 case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| 8562 UNREACHABLE(); | 9543 FixedArray* parameter_map = FixedArray::cast(elements()); |
| 9544 int mapped_length = parameter_map->length() - 2; |
| 9545 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| 9546 if (arguments->IsDictionary()) { |
| 9547 // Copy the keys from arguments first, because Dictionary::CopyKeysTo |
| 9548 // will insert in storage starting at index 0. |
| 9549 NumberDictionary* dictionary = NumberDictionary::cast(arguments); |
| 9550 if (storage != NULL) { |
| 9551 dictionary->CopyKeysTo(storage, filter, NumberDictionary::UNSORTED); |
| 9552 } |
| 9553 counter += dictionary->NumberOfElementsFilterAttributes(filter); |
| 9554 for (int i = 0; i < mapped_length; ++i) { |
| 9555 if (!parameter_map->get(i + 2)->IsTheHole()) { |
| 9556 if (storage != NULL) storage->set(counter, Smi::FromInt(i)); |
| 9557 ++counter; |
| 9558 } |
| 9559 } |
| 9560 if (storage != NULL) storage->SortPairs(storage, counter); |
| 9561 |
| 9562 } else { |
| 9563 int backing_length = arguments->length(); |
| 9564 int i = 0; |
| 9565 for (; i < mapped_length; ++i) { |
| 9566 if (!parameter_map->get(i + 2)->IsTheHole()) { |
| 9567 if (storage != NULL) storage->set(counter, Smi::FromInt(i)); |
| 9568 ++counter; |
| 9569 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) { |
| 9570 if (storage != NULL) storage->set(counter, Smi::FromInt(i)); |
| 9571 ++counter; |
| 9572 } |
| 9573 } |
| 9574 for (; i < backing_length; ++i) { |
| 9575 if (storage != NULL) storage->set(counter, Smi::FromInt(i)); |
| 9576 ++counter; |
| 9577 } |
| 9578 } |
| 8563 break; | 9579 break; |
| 9580 } |
| 8564 } | 9581 } |
| 8565 | 9582 |
| 8566 if (this->IsJSValue()) { | 9583 if (this->IsJSValue()) { |
| 8567 Object* val = JSValue::cast(this)->value(); | 9584 Object* val = JSValue::cast(this)->value(); |
| 8568 if (val->IsString()) { | 9585 if (val->IsString()) { |
| 8569 String* str = String::cast(val); | 9586 String* str = String::cast(val); |
| 8570 if (storage) { | 9587 if (storage) { |
| 8571 for (int i = 0; i < str->length(); i++) { | 9588 for (int i = 0; i < str->length(); i++) { |
| 8572 storage->set(counter + i, Smi::FromInt(i)); | 9589 storage->set(counter + i, Smi::FromInt(i)); |
| 8573 } | 9590 } |
| (...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9020 return entry; | 10037 return entry; |
| 9021 } | 10038 } |
| 9022 ASSERT(element->IsNull() || !String::cast(element)->Equals(key)); | 10039 ASSERT(element->IsNull() || !String::cast(element)->Equals(key)); |
| 9023 entry = NextProbe(entry, count++, capacity); | 10040 entry = NextProbe(entry, count++, capacity); |
| 9024 } | 10041 } |
| 9025 return kNotFound; | 10042 return kNotFound; |
| 9026 } | 10043 } |
| 9027 | 10044 |
| 9028 | 10045 |
| 9029 template<typename Shape, typename Key> | 10046 template<typename Shape, typename Key> |
| 10047 MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) { |
| 10048 ASSERT(NumberOfElements() < new_table->Capacity()); |
| 10049 |
| 10050 AssertNoAllocation no_gc; |
| 10051 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc); |
| 10052 |
| 10053 // Copy prefix to new array. |
| 10054 for (int i = kPrefixStartIndex; |
| 10055 i < kPrefixStartIndex + Shape::kPrefixSize; |
| 10056 i++) { |
| 10057 new_table->set(i, get(i), mode); |
| 10058 } |
| 10059 |
| 10060 // Rehash the elements. |
| 10061 int capacity = Capacity(); |
| 10062 for (int i = 0; i < capacity; i++) { |
| 10063 uint32_t from_index = EntryToIndex(i); |
| 10064 Object* k = get(from_index); |
| 10065 if (IsKey(k)) { |
| 10066 uint32_t hash = Shape::HashForObject(key, k); |
| 10067 uint32_t insertion_index = |
| 10068 EntryToIndex(new_table->FindInsertionEntry(hash)); |
| 10069 for (int j = 0; j < Shape::kEntrySize; j++) { |
| 10070 new_table->set(insertion_index + j, get(from_index + j), mode); |
| 10071 } |
| 10072 } |
| 10073 } |
| 10074 new_table->SetNumberOfElements(NumberOfElements()); |
| 10075 new_table->SetNumberOfDeletedElements(0); |
| 10076 return new_table; |
| 10077 } |
| 10078 |
| 10079 |
| 10080 template<typename Shape, typename Key> |
| 9030 MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) { | 10081 MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) { |
| 9031 int capacity = Capacity(); | 10082 int capacity = Capacity(); |
| 9032 int nof = NumberOfElements() + n; | 10083 int nof = NumberOfElements() + n; |
| 9033 int nod = NumberOfDeletedElements(); | 10084 int nod = NumberOfDeletedElements(); |
| 9034 // Return if: | 10085 // Return if: |
| 9035 // 50% is still free after adding n elements and | 10086 // 50% is still free after adding n elements and |
| 9036 // at most 50% of the free elements are deleted elements. | 10087 // at most 50% of the free elements are deleted elements. |
| 9037 if (nod <= (capacity - nof) >> 1) { | 10088 if (nod <= (capacity - nof) >> 1) { |
| 9038 int needed_free = nof >> 1; | 10089 int needed_free = nof >> 1; |
| 9039 if (nof + needed_free <= capacity) return this; | 10090 if (nof + needed_free <= capacity) return this; |
| 9040 } | 10091 } |
| 9041 | 10092 |
| 9042 const int kMinCapacityForPretenure = 256; | 10093 const int kMinCapacityForPretenure = 256; |
| 9043 bool pretenure = | 10094 bool pretenure = |
| 9044 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this); | 10095 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this); |
| 9045 Object* obj; | 10096 Object* obj; |
| 9046 { MaybeObject* maybe_obj = | 10097 { MaybeObject* maybe_obj = |
| 9047 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED); | 10098 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED); |
| 9048 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 10099 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 9049 } | 10100 } |
| 9050 | 10101 |
| 9051 AssertNoAllocation no_gc; | 10102 return Rehash(HashTable::cast(obj), key); |
| 9052 HashTable* table = HashTable::cast(obj); | |
| 9053 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc); | |
| 9054 | |
| 9055 // Copy prefix to new array. | |
| 9056 for (int i = kPrefixStartIndex; | |
| 9057 i < kPrefixStartIndex + Shape::kPrefixSize; | |
| 9058 i++) { | |
| 9059 table->set(i, get(i), mode); | |
| 9060 } | |
| 9061 // Rehash the elements. | |
| 9062 for (int i = 0; i < capacity; i++) { | |
| 9063 uint32_t from_index = EntryToIndex(i); | |
| 9064 Object* k = get(from_index); | |
| 9065 if (IsKey(k)) { | |
| 9066 uint32_t hash = Shape::HashForObject(key, k); | |
| 9067 uint32_t insertion_index = | |
| 9068 EntryToIndex(table->FindInsertionEntry(hash)); | |
| 9069 for (int j = 0; j < Shape::kEntrySize; j++) { | |
| 9070 table->set(insertion_index + j, get(from_index + j), mode); | |
| 9071 } | |
| 9072 } | |
| 9073 } | |
| 9074 table->SetNumberOfElements(NumberOfElements()); | |
| 9075 table->SetNumberOfDeletedElements(0); | |
| 9076 return table; | |
| 9077 } | 10103 } |
| 9078 | 10104 |
| 9079 | 10105 |
| 10106 template<typename Shape, typename Key> |
| 10107 MaybeObject* HashTable<Shape, Key>::Shrink(Key key) { |
| 10108 int capacity = Capacity(); |
| 10109 int nof = NumberOfElements(); |
| 10110 |
| 10111 // Shrink to fit the number of elements if only a quarter of the |
| 10112 // capacity is filled with elements. |
| 10113 if (nof > (capacity >> 2)) return this; |
| 10114 // Allocate a new dictionary with room for at least the current |
| 10115 // number of elements. The allocation method will make sure that |
| 10116 // there is extra room in the dictionary for additions. Don't go |
| 10117 // lower than room for 16 elements. |
| 10118 int at_least_room_for = nof; |
| 10119 if (at_least_room_for < 16) return this; |
| 10120 |
| 10121 const int kMinCapacityForPretenure = 256; |
| 10122 bool pretenure = |
| 10123 (at_least_room_for > kMinCapacityForPretenure) && |
| 10124 !GetHeap()->InNewSpace(this); |
| 10125 Object* obj; |
| 10126 { MaybeObject* maybe_obj = |
| 10127 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED); |
| 10128 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 10129 } |
| 10130 |
| 10131 return Rehash(HashTable::cast(obj), key); |
| 10132 } |
| 10133 |
| 10134 |
| 9080 template<typename Shape, typename Key> | 10135 template<typename Shape, typename Key> |
| 9081 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) { | 10136 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) { |
| 9082 uint32_t capacity = Capacity(); | 10137 uint32_t capacity = Capacity(); |
| 9083 uint32_t entry = FirstProbe(hash, capacity); | 10138 uint32_t entry = FirstProbe(hash, capacity); |
| 9084 uint32_t count = 1; | 10139 uint32_t count = 1; |
| 9085 // EnsureCapacity will guarantee the hash table is never full. | 10140 // EnsureCapacity will guarantee the hash table is never full. |
| 9086 while (true) { | 10141 while (true) { |
| 9087 Object* element = KeyAt(entry); | 10142 Object* element = KeyAt(entry); |
| 9088 if (element->IsUndefined() || element->IsNull()) break; | 10143 if (element->IsUndefined() || element->IsNull()) break; |
| 9089 entry = NextProbe(entry, count++, capacity); | 10144 entry = NextProbe(entry, count++, capacity); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 9113 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut( | 10168 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut( |
| 9114 uint32_t, Object*); | 10169 uint32_t, Object*); |
| 9115 | 10170 |
| 9116 template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup( | 10171 template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup( |
| 9117 Object*); | 10172 Object*); |
| 9118 | 10173 |
| 9119 template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup( | 10174 template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup( |
| 9120 Object*); | 10175 Object*); |
| 9121 | 10176 |
| 9122 template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo( | 10177 template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo( |
| 9123 FixedArray*, PropertyAttributes); | 10178 FixedArray*, |
| 10179 PropertyAttributes, |
| 10180 Dictionary<NumberDictionaryShape, uint32_t>::SortMode); |
| 9124 | 10181 |
| 9125 template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty( | 10182 template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty( |
| 9126 int, JSObject::DeleteMode); | 10183 int, JSObject::DeleteMode); |
| 9127 | 10184 |
| 9128 template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty( | 10185 template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty( |
| 9129 int, JSObject::DeleteMode); | 10186 int, JSObject::DeleteMode); |
| 9130 | 10187 |
| 10188 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink( |
| 10189 String*); |
| 10190 |
| 10191 template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink( |
| 10192 uint32_t); |
| 10193 |
| 9131 template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo( | 10194 template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo( |
| 9132 FixedArray*); | 10195 FixedArray*, |
| 10196 Dictionary<StringDictionaryShape, String*>::SortMode); |
| 9133 | 10197 |
| 9134 template int | 10198 template int |
| 9135 Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes( | 10199 Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes( |
| 9136 PropertyAttributes); | 10200 PropertyAttributes); |
| 9137 | 10201 |
| 9138 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add( | 10202 template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add( |
| 9139 String*, Object*, PropertyDetails); | 10203 String*, Object*, PropertyDetails); |
| 9140 | 10204 |
| 9141 template MaybeObject* | 10205 template MaybeObject* |
| 9142 Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices(); | 10206 Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices(); |
| (...skipping 484 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9627 if (!key->IsString()) return 0; | 10691 if (!key->IsString()) return 0; |
| 9628 return String::cast(key)->Hash(); | 10692 return String::cast(key)->Hash(); |
| 9629 } | 10693 } |
| 9630 | 10694 |
| 9631 Object* AsObject() { | 10695 Object* AsObject() { |
| 9632 // The TwoCharHashTableKey is only used for looking in the symbol | 10696 // The TwoCharHashTableKey is only used for looking in the symbol |
| 9633 // table, not for adding to it. | 10697 // table, not for adding to it. |
| 9634 UNREACHABLE(); | 10698 UNREACHABLE(); |
| 9635 return NULL; | 10699 return NULL; |
| 9636 } | 10700 } |
| 10701 |
| 9637 private: | 10702 private: |
| 9638 uint32_t c1_; | 10703 uint32_t c1_; |
| 9639 uint32_t c2_; | 10704 uint32_t c2_; |
| 9640 uint32_t hash_; | 10705 uint32_t hash_; |
| 9641 }; | 10706 }; |
| 9642 | 10707 |
| 9643 | 10708 |
| 9644 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { | 10709 bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) { |
| 9645 SymbolKey key(string); | 10710 SymbolKey key(string); |
| 9646 int entry = FindEntry(&key); | 10711 int entry = FindEntry(&key); |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10019 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) { | 11084 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) { |
| 10020 return heap->false_value(); | 11085 return heap->false_value(); |
| 10021 } | 11086 } |
| 10022 SetEntry(entry, heap->null_value(), heap->null_value()); | 11087 SetEntry(entry, heap->null_value(), heap->null_value()); |
| 10023 HashTable<Shape, Key>::ElementRemoved(); | 11088 HashTable<Shape, Key>::ElementRemoved(); |
| 10024 return heap->true_value(); | 11089 return heap->true_value(); |
| 10025 } | 11090 } |
| 10026 | 11091 |
| 10027 | 11092 |
| 10028 template<typename Shape, typename Key> | 11093 template<typename Shape, typename Key> |
| 11094 MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) { |
| 11095 return HashTable<Shape, Key>::Shrink(key); |
| 11096 } |
| 11097 |
| 11098 |
| 11099 template<typename Shape, typename Key> |
| 10029 MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) { | 11100 MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) { |
| 10030 int entry = this->FindEntry(key); | 11101 int entry = this->FindEntry(key); |
| 10031 | 11102 |
| 10032 // If the entry is present set the value; | 11103 // If the entry is present set the value; |
| 10033 if (entry != Dictionary<Shape, Key>::kNotFound) { | 11104 if (entry != Dictionary<Shape, Key>::kNotFound) { |
| 10034 ValueAtPut(entry, value); | 11105 ValueAtPut(entry, value); |
| 10035 return this; | 11106 return this; |
| 10036 } | 11107 } |
| 10037 | 11108 |
| 10038 // Check whether the dictionary should be extended. | 11109 // Check whether the dictionary should be extended. |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10167 | 11238 |
| 10168 | 11239 |
| 10169 template<typename Shape, typename Key> | 11240 template<typename Shape, typename Key> |
| 10170 int Dictionary<Shape, Key>::NumberOfEnumElements() { | 11241 int Dictionary<Shape, Key>::NumberOfEnumElements() { |
| 10171 return NumberOfElementsFilterAttributes( | 11242 return NumberOfElementsFilterAttributes( |
| 10172 static_cast<PropertyAttributes>(DONT_ENUM)); | 11243 static_cast<PropertyAttributes>(DONT_ENUM)); |
| 10173 } | 11244 } |
| 10174 | 11245 |
| 10175 | 11246 |
| 10176 template<typename Shape, typename Key> | 11247 template<typename Shape, typename Key> |
| 10177 void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage, | 11248 void Dictionary<Shape, Key>::CopyKeysTo( |
| 10178 PropertyAttributes filter) { | 11249 FixedArray* storage, |
| 11250 PropertyAttributes filter, |
| 11251 typename Dictionary<Shape, Key>::SortMode sort_mode) { |
| 10179 ASSERT(storage->length() >= NumberOfEnumElements()); | 11252 ASSERT(storage->length() >= NumberOfEnumElements()); |
| 10180 int capacity = HashTable<Shape, Key>::Capacity(); | 11253 int capacity = HashTable<Shape, Key>::Capacity(); |
| 10181 int index = 0; | 11254 int index = 0; |
| 10182 for (int i = 0; i < capacity; i++) { | 11255 for (int i = 0; i < capacity; i++) { |
| 10183 Object* k = HashTable<Shape, Key>::KeyAt(i); | 11256 Object* k = HashTable<Shape, Key>::KeyAt(i); |
| 10184 if (HashTable<Shape, Key>::IsKey(k)) { | 11257 if (HashTable<Shape, Key>::IsKey(k)) { |
| 10185 PropertyDetails details = DetailsAt(i); | 11258 PropertyDetails details = DetailsAt(i); |
| 10186 if (details.IsDeleted()) continue; | 11259 if (details.IsDeleted()) continue; |
| 10187 PropertyAttributes attr = details.attributes(); | 11260 PropertyAttributes attr = details.attributes(); |
| 10188 if ((attr & filter) == 0) storage->set(index++, k); | 11261 if ((attr & filter) == 0) storage->set(index++, k); |
| 10189 } | 11262 } |
| 10190 } | 11263 } |
| 10191 storage->SortPairs(storage, index); | 11264 if (sort_mode == Dictionary<Shape, Key>::SORTED) { |
| 11265 storage->SortPairs(storage, index); |
| 11266 } |
| 10192 ASSERT(storage->length() >= index); | 11267 ASSERT(storage->length() >= index); |
| 10193 } | 11268 } |
| 10194 | 11269 |
| 10195 | 11270 |
| 10196 void StringDictionary::CopyEnumKeysTo(FixedArray* storage, | 11271 void StringDictionary::CopyEnumKeysTo(FixedArray* storage, |
| 10197 FixedArray* sort_array) { | 11272 FixedArray* sort_array) { |
| 10198 ASSERT(storage->length() >= NumberOfEnumElements()); | 11273 ASSERT(storage->length() >= NumberOfEnumElements()); |
| 10199 int capacity = Capacity(); | 11274 int capacity = Capacity(); |
| 10200 int index = 0; | 11275 int index = 0; |
| 10201 for (int i = 0; i < capacity; i++) { | 11276 for (int i = 0; i < capacity; i++) { |
| 10202 Object* k = KeyAt(i); | 11277 Object* k = KeyAt(i); |
| 10203 if (IsKey(k)) { | 11278 if (IsKey(k)) { |
| 10204 PropertyDetails details = DetailsAt(i); | 11279 PropertyDetails details = DetailsAt(i); |
| 10205 if (details.IsDeleted() || details.IsDontEnum()) continue; | 11280 if (details.IsDeleted() || details.IsDontEnum()) continue; |
| 10206 storage->set(index, k); | 11281 storage->set(index, k); |
| 10207 sort_array->set(index, Smi::FromInt(details.index())); | 11282 sort_array->set(index, Smi::FromInt(details.index())); |
| 10208 index++; | 11283 index++; |
| 10209 } | 11284 } |
| 10210 } | 11285 } |
| 10211 storage->SortPairs(sort_array, sort_array->length()); | 11286 storage->SortPairs(sort_array, sort_array->length()); |
| 10212 ASSERT(storage->length() >= index); | 11287 ASSERT(storage->length() >= index); |
| 10213 } | 11288 } |
| 10214 | 11289 |
| 10215 | 11290 |
| 10216 template<typename Shape, typename Key> | 11291 template<typename Shape, typename Key> |
| 10217 void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) { | 11292 void Dictionary<Shape, Key>::CopyKeysTo( |
| 11293 FixedArray* storage, |
| 11294 typename Dictionary<Shape, Key>::SortMode sort_mode) { |
| 10218 ASSERT(storage->length() >= NumberOfElementsFilterAttributes( | 11295 ASSERT(storage->length() >= NumberOfElementsFilterAttributes( |
| 10219 static_cast<PropertyAttributes>(NONE))); | 11296 static_cast<PropertyAttributes>(NONE))); |
| 10220 int capacity = HashTable<Shape, Key>::Capacity(); | 11297 int capacity = HashTable<Shape, Key>::Capacity(); |
| 10221 int index = 0; | 11298 int index = 0; |
| 10222 for (int i = 0; i < capacity; i++) { | 11299 for (int i = 0; i < capacity; i++) { |
| 10223 Object* k = HashTable<Shape, Key>::KeyAt(i); | 11300 Object* k = HashTable<Shape, Key>::KeyAt(i); |
| 10224 if (HashTable<Shape, Key>::IsKey(k)) { | 11301 if (HashTable<Shape, Key>::IsKey(k)) { |
| 10225 PropertyDetails details = DetailsAt(i); | 11302 PropertyDetails details = DetailsAt(i); |
| 10226 if (details.IsDeleted()) continue; | 11303 if (details.IsDeleted()) continue; |
| 10227 storage->set(index++, k); | 11304 storage->set(index++, k); |
| 10228 } | 11305 } |
| 10229 } | 11306 } |
| 11307 if (sort_mode == Dictionary<Shape, Key>::SORTED) { |
| 11308 storage->SortPairs(storage, index); |
| 11309 } |
| 10230 ASSERT(storage->length() >= index); | 11310 ASSERT(storage->length() >= index); |
| 10231 } | 11311 } |
| 10232 | 11312 |
| 10233 | 11313 |
| 10234 // Backwards lookup (slow). | 11314 // Backwards lookup (slow). |
| 10235 template<typename Shape, typename Key> | 11315 template<typename Shape, typename Key> |
| 10236 Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) { | 11316 Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) { |
| 10237 int capacity = HashTable<Shape, Key>::Capacity(); | 11317 int capacity = HashTable<Shape, Key>::Capacity(); |
| 10238 for (int i = 0; i < capacity; i++) { | 11318 for (int i = 0; i < capacity; i++) { |
| 10239 Object* k = HashTable<Shape, Key>::KeyAt(i); | 11319 Object* k = HashTable<Shape, Key>::KeyAt(i); |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10633 if (break_point_objects()->IsUndefined()) return 0; | 11713 if (break_point_objects()->IsUndefined()) return 0; |
| 10634 // Single beak point. | 11714 // Single beak point. |
| 10635 if (!break_point_objects()->IsFixedArray()) return 1; | 11715 if (!break_point_objects()->IsFixedArray()) return 1; |
| 10636 // Multiple break points. | 11716 // Multiple break points. |
| 10637 return FixedArray::cast(break_point_objects())->length(); | 11717 return FixedArray::cast(break_point_objects())->length(); |
| 10638 } | 11718 } |
| 10639 #endif | 11719 #endif |
| 10640 | 11720 |
| 10641 | 11721 |
| 10642 } } // namespace v8::internal | 11722 } } // namespace v8::internal |
| OLD | NEW |