OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 1909 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1920 } | 1920 } |
1921 } | 1921 } |
1922 return true; | 1922 return true; |
1923 } | 1923 } |
1924 | 1924 |
1925 | 1925 |
1926 MaybeObject* JSObject::AddFastProperty(Name* name, | 1926 MaybeObject* JSObject::AddFastProperty(Name* name, |
1927 Object* value, | 1927 Object* value, |
1928 PropertyAttributes attributes, | 1928 PropertyAttributes attributes, |
1929 StoreFromKeyed store_mode, | 1929 StoreFromKeyed store_mode, |
1930 ValueType value_type) { | 1930 ValueType value_type, |
| 1931 TransitionFlag flag) { |
1931 ASSERT(!IsJSGlobalProxy()); | 1932 ASSERT(!IsJSGlobalProxy()); |
1932 ASSERT(DescriptorArray::kNotFound == | 1933 ASSERT(DescriptorArray::kNotFound == |
1933 map()->instance_descriptors()->Search( | 1934 map()->instance_descriptors()->Search( |
1934 name, map()->NumberOfOwnDescriptors())); | 1935 name, map()->NumberOfOwnDescriptors())); |
1935 | 1936 |
1936 // Normalize the object if the name is an actual name (not the | 1937 // Normalize the object if the name is an actual name (not the |
1937 // hidden strings) and is not a real identifier. | 1938 // hidden strings) and is not a real identifier. |
1938 // Normalize the object if it will have too many fast properties. | 1939 // Normalize the object if it will have too many fast properties. |
1939 Isolate* isolate = GetHeap()->isolate(); | 1940 Isolate* isolate = GetHeap()->isolate(); |
1940 if ((!name->IsSymbol() && !IsIdentifier(isolate->unicode_cache(), name) | 1941 if ((!name->IsSymbol() && |
1941 && name != isolate->heap()->hidden_string()) || | 1942 !IsIdentifier(isolate->unicode_cache(), name) && |
1942 (map()->unused_property_fields() == 0 && | 1943 name != isolate->heap()->hidden_string()) || |
1943 TooManyFastProperties(properties()->length(), store_mode))) { | 1944 TooManyFastProperties(store_mode)) { |
1944 Object* obj; | 1945 MaybeObject* maybe_failure = |
1945 MaybeObject* maybe_obj = | |
1946 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 1946 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
1947 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1947 if (maybe_failure->IsFailure()) return maybe_failure; |
1948 | |
1949 return AddSlowProperty(name, value, attributes); | 1948 return AddSlowProperty(name, value, attributes); |
1950 } | 1949 } |
1951 | 1950 |
1952 // Compute the new index for new field. | 1951 // Compute the new index for new field. |
1953 int index = map()->NextFreePropertyIndex(); | 1952 int index = map()->NextFreePropertyIndex(); |
1954 | 1953 |
1955 // Allocate new instance descriptors with (name, index) added | 1954 // Allocate new instance descriptors with (name, index) added |
1956 if (IsJSContextExtensionObject()) value_type = FORCE_TAGGED; | 1955 if (IsJSContextExtensionObject()) value_type = FORCE_TAGGED; |
1957 Representation representation = value->OptimalRepresentation(value_type); | 1956 Representation representation = value->OptimalRepresentation(value_type); |
1958 | 1957 |
1959 FieldDescriptor new_field(name, index, attributes, representation); | 1958 FieldDescriptor new_field(name, index, attributes, representation); |
1960 | 1959 |
1961 ASSERT(index < map()->inobject_properties() || | 1960 ASSERT(index < map()->inobject_properties() || |
1962 (index - map()->inobject_properties()) < properties()->length() || | 1961 (index - map()->inobject_properties()) < properties()->length() || |
1963 map()->unused_property_fields() == 0); | 1962 map()->unused_property_fields() == 0); |
1964 | 1963 |
1965 FixedArray* values = NULL; | 1964 FixedArray* values = NULL; |
1966 | 1965 |
1967 // TODO(verwaest): Merge with AddFastPropertyUsingMap. | 1966 // TODO(verwaest): Merge with AddFastPropertyUsingMap. |
1968 if (map()->unused_property_fields() == 0) { | 1967 if (map()->unused_property_fields() == 0) { |
1969 // Make room for the new value | 1968 // Make room for the new value |
1970 MaybeObject* maybe_values = | 1969 MaybeObject* maybe_values = |
1971 properties()->CopySize(properties()->length() + kFieldsAdded); | 1970 properties()->CopySize(properties()->length() + kFieldsAdded); |
1972 if (!maybe_values->To(&values)) return maybe_values; | 1971 if (!maybe_values->To(&values)) return maybe_values; |
1973 } | 1972 } |
1974 | 1973 |
1975 TransitionFlag flag = INSERT_TRANSITION; | |
1976 | |
1977 Heap* heap = isolate->heap(); | 1974 Heap* heap = isolate->heap(); |
1978 | 1975 |
1979 Object* storage; | 1976 Object* storage; |
1980 MaybeObject* maybe_storage = | 1977 MaybeObject* maybe_storage = |
1981 value->AllocateNewStorageFor(heap, representation); | 1978 value->AllocateNewStorageFor(heap, representation); |
1982 if (!maybe_storage->To(&storage)) return maybe_storage; | 1979 if (!maybe_storage->To(&storage)) return maybe_storage; |
1983 | 1980 |
1984 // Note that Map::CopyAddDescriptor has side-effects, the new map is already | 1981 // Note that Map::CopyAddDescriptor has side-effects, the new map is already |
1985 // inserted in the transition tree. No more allocations that might fail are | 1982 // inserted in the transition tree. No more allocations that might fail are |
1986 // allowed after this point. | 1983 // allowed after this point. |
(...skipping 12 matching lines...) Expand all Loading... |
1999 set_map(new_map); | 1996 set_map(new_map); |
2000 | 1997 |
2001 FastPropertyAtPut(index, storage); | 1998 FastPropertyAtPut(index, storage); |
2002 return value; | 1999 return value; |
2003 } | 2000 } |
2004 | 2001 |
2005 | 2002 |
2006 MaybeObject* JSObject::AddConstantProperty( | 2003 MaybeObject* JSObject::AddConstantProperty( |
2007 Name* name, | 2004 Name* name, |
2008 Object* constant, | 2005 Object* constant, |
2009 PropertyAttributes attributes) { | 2006 PropertyAttributes attributes, |
| 2007 TransitionFlag initial_flag) { |
2010 // Allocate new instance descriptors with (name, constant) added | 2008 // Allocate new instance descriptors with (name, constant) added |
2011 ConstantDescriptor d(name, constant, attributes); | 2009 ConstantDescriptor d(name, constant, attributes); |
2012 | 2010 |
2013 TransitionFlag flag = | 2011 TransitionFlag flag = |
2014 // Do not add transitions to global objects. | 2012 // Do not add transitions to global objects. |
2015 (IsGlobalObject() || | 2013 (IsGlobalObject() || |
2016 // Don't add transitions to special properties with non-trivial | 2014 // Don't add transitions to special properties with non-trivial |
2017 // attributes. | 2015 // attributes. |
2018 attributes != NONE) | 2016 attributes != NONE) |
2019 ? OMIT_TRANSITION | 2017 ? OMIT_TRANSITION |
2020 : INSERT_TRANSITION; | 2018 : initial_flag; |
2021 | 2019 |
2022 Map* new_map; | 2020 Map* new_map; |
2023 MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag); | 2021 MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag); |
2024 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | 2022 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
2025 | 2023 |
2026 set_map(new_map); | 2024 set_map(new_map); |
2027 return constant; | 2025 return constant; |
2028 } | 2026 } |
2029 | 2027 |
2030 | 2028 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2070 } | 2068 } |
2071 | 2069 |
2072 | 2070 |
2073 MaybeObject* JSObject::AddProperty(Name* name, | 2071 MaybeObject* JSObject::AddProperty(Name* name, |
2074 Object* value, | 2072 Object* value, |
2075 PropertyAttributes attributes, | 2073 PropertyAttributes attributes, |
2076 StrictModeFlag strict_mode, | 2074 StrictModeFlag strict_mode, |
2077 JSReceiver::StoreFromKeyed store_mode, | 2075 JSReceiver::StoreFromKeyed store_mode, |
2078 ExtensibilityCheck extensibility_check, | 2076 ExtensibilityCheck extensibility_check, |
2079 ValueType value_type, | 2077 ValueType value_type, |
2080 StoreMode mode) { | 2078 StoreMode mode, |
| 2079 TransitionFlag transition_flag) { |
2081 ASSERT(!IsJSGlobalProxy()); | 2080 ASSERT(!IsJSGlobalProxy()); |
2082 Map* map_of_this = map(); | 2081 Map* map_of_this = map(); |
2083 Heap* heap = GetHeap(); | 2082 Heap* heap = GetHeap(); |
2084 Isolate* isolate = heap->isolate(); | 2083 Isolate* isolate = heap->isolate(); |
2085 MaybeObject* result; | 2084 MaybeObject* result; |
2086 if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK && | 2085 if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK && |
2087 !map_of_this->is_extensible()) { | 2086 !map_of_this->is_extensible()) { |
2088 if (strict_mode == kNonStrictMode) { | 2087 if (strict_mode == kNonStrictMode) { |
2089 return value; | 2088 return value; |
2090 } else { | 2089 } else { |
2091 Handle<Object> args[1] = {Handle<Name>(name)}; | 2090 Handle<Object> args[1] = {Handle<Name>(name)}; |
2092 return isolate->Throw( | 2091 return isolate->Throw( |
2093 *isolate->factory()->NewTypeError("object_not_extensible", | 2092 *isolate->factory()->NewTypeError("object_not_extensible", |
2094 HandleVector(args, 1))); | 2093 HandleVector(args, 1))); |
2095 } | 2094 } |
2096 } | 2095 } |
2097 | 2096 |
2098 if (HasFastProperties()) { | 2097 if (HasFastProperties()) { |
2099 // Ensure the descriptor array does not get too big. | 2098 // Ensure the descriptor array does not get too big. |
2100 if (map_of_this->NumberOfOwnDescriptors() < | 2099 if (map_of_this->NumberOfOwnDescriptors() < |
2101 DescriptorArray::kMaxNumberOfDescriptors) { | 2100 DescriptorArray::kMaxNumberOfDescriptors) { |
2102 // TODO(verwaest): Support other constants. | 2101 // TODO(verwaest): Support other constants. |
2103 // if (mode == ALLOW_AS_CONSTANT && | 2102 // if (mode == ALLOW_AS_CONSTANT && |
2104 // !value->IsTheHole() && | 2103 // !value->IsTheHole() && |
2105 // !value->IsConsString()) { | 2104 // !value->IsConsString()) { |
2106 if (value->IsJSFunction()) { | 2105 if (value->IsJSFunction()) { |
2107 result = AddConstantProperty(name, value, attributes); | 2106 result = AddConstantProperty(name, value, attributes, transition_flag); |
2108 } else { | 2107 } else { |
2109 result = AddFastProperty( | 2108 result = AddFastProperty( |
2110 name, value, attributes, store_mode, value_type); | 2109 name, value, attributes, store_mode, value_type, transition_flag); |
2111 } | 2110 } |
2112 } else { | 2111 } else { |
2113 // Normalize the object to prevent very large instance descriptors. | 2112 // Normalize the object to prevent very large instance descriptors. |
2114 // This eliminates unwanted N^2 allocation and lookup behavior. | 2113 // This eliminates unwanted N^2 allocation and lookup behavior. |
2115 Object* obj; | 2114 Object* obj; |
2116 MaybeObject* maybe = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 2115 MaybeObject* maybe = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
2117 if (!maybe->To(&obj)) return maybe; | 2116 if (!maybe->To(&obj)) return maybe; |
2118 result = AddSlowProperty(name, value, attributes); | 2117 result = AddSlowProperty(name, value, attributes); |
2119 } | 2118 } |
2120 } else { | 2119 } else { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2204 if (old_index != -1) { | 2203 if (old_index != -1) { |
2205 // All calls to ReplaceSlowProperty have had all transitions removed. | 2204 // All calls to ReplaceSlowProperty have had all transitions removed. |
2206 new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index(); | 2205 new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index(); |
2207 } | 2206 } |
2208 | 2207 |
2209 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index); | 2208 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index); |
2210 return SetNormalizedProperty(name, value, new_details); | 2209 return SetNormalizedProperty(name, value, new_details); |
2211 } | 2210 } |
2212 | 2211 |
2213 | 2212 |
2214 MaybeObject* JSObject::ConvertDescriptorToField(Name* name, | |
2215 Object* new_value, | |
2216 PropertyAttributes attributes, | |
2217 TransitionFlag flag) { | |
2218 if (map()->unused_property_fields() == 0 && | |
2219 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) { | |
2220 Object* obj; | |
2221 MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | |
2222 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
2223 return ReplaceSlowProperty(name, new_value, attributes); | |
2224 } | |
2225 | |
2226 Representation representation = IsJSContextExtensionObject() | |
2227 ? Representation::Tagged() : new_value->OptimalRepresentation(); | |
2228 int index = map()->NextFreePropertyIndex(); | |
2229 FieldDescriptor new_field(name, index, attributes, representation); | |
2230 | |
2231 // Make a new map for the object. | |
2232 Map* new_map; | |
2233 MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field, flag); | |
2234 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | |
2235 | |
2236 // Make new properties array if necessary. | |
2237 FixedArray* new_properties = NULL; | |
2238 int new_unused_property_fields = map()->unused_property_fields() - 1; | |
2239 if (map()->unused_property_fields() == 0) { | |
2240 new_unused_property_fields = kFieldsAdded - 1; | |
2241 MaybeObject* maybe_new_properties = | |
2242 properties()->CopySize(properties()->length() + kFieldsAdded); | |
2243 if (!maybe_new_properties->To(&new_properties)) return maybe_new_properties; | |
2244 } | |
2245 | |
2246 Heap* heap = GetHeap(); | |
2247 Object* storage; | |
2248 MaybeObject* maybe_storage = | |
2249 new_value->AllocateNewStorageFor(heap, representation); | |
2250 if (!maybe_storage->To(&storage)) return maybe_storage; | |
2251 | |
2252 // Update pointers to commit changes. | |
2253 // Object points to the new map. | |
2254 new_map->set_unused_property_fields(new_unused_property_fields); | |
2255 set_map(new_map); | |
2256 if (new_properties != NULL) { | |
2257 set_properties(new_properties); | |
2258 } | |
2259 FastPropertyAtPut(index, storage); | |
2260 return new_value; | |
2261 } | |
2262 | |
2263 | |
2264 const char* Representation::Mnemonic() const { | 2213 const char* Representation::Mnemonic() const { |
2265 switch (kind_) { | 2214 switch (kind_) { |
2266 case kNone: return "v"; | 2215 case kNone: return "v"; |
2267 case kTagged: return "t"; | 2216 case kTagged: return "t"; |
2268 case kSmi: return "s"; | 2217 case kSmi: return "s"; |
2269 case kDouble: return "d"; | 2218 case kDouble: return "d"; |
2270 case kInteger32: return "i"; | 2219 case kInteger32: return "i"; |
2271 case kHeapObject: return "h"; | 2220 case kHeapObject: return "h"; |
2272 case kExternal: return "x"; | 2221 case kExternal: return "x"; |
2273 default: | 2222 default: |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2400 if (!maybe_array->To(&array)) return maybe_array; | 2349 if (!maybe_array->To(&array)) return maybe_array; |
2401 | 2350 |
2402 DescriptorArray* old_descriptors = old_map->instance_descriptors(); | 2351 DescriptorArray* old_descriptors = old_map->instance_descriptors(); |
2403 DescriptorArray* new_descriptors = new_map->instance_descriptors(); | 2352 DescriptorArray* new_descriptors = new_map->instance_descriptors(); |
2404 int descriptors = new_map->NumberOfOwnDescriptors(); | 2353 int descriptors = new_map->NumberOfOwnDescriptors(); |
2405 | 2354 |
2406 for (int i = 0; i < descriptors; i++) { | 2355 for (int i = 0; i < descriptors; i++) { |
2407 PropertyDetails details = new_descriptors->GetDetails(i); | 2356 PropertyDetails details = new_descriptors->GetDetails(i); |
2408 if (details.type() != FIELD) continue; | 2357 if (details.type() != FIELD) continue; |
2409 PropertyDetails old_details = old_descriptors->GetDetails(i); | 2358 PropertyDetails old_details = old_descriptors->GetDetails(i); |
| 2359 if (old_details.type() == CALLBACKS) { |
| 2360 ASSERT(details.representation().IsTagged()); |
| 2361 continue; |
| 2362 } |
2410 ASSERT(old_details.type() == CONSTANT || | 2363 ASSERT(old_details.type() == CONSTANT || |
2411 old_details.type() == FIELD); | 2364 old_details.type() == FIELD); |
2412 Object* value = old_details.type() == CONSTANT | 2365 Object* value = old_details.type() == CONSTANT |
2413 ? old_descriptors->GetValue(i) | 2366 ? old_descriptors->GetValue(i) |
2414 : RawFastPropertyAt(old_descriptors->GetFieldIndex(i)); | 2367 : RawFastPropertyAt(old_descriptors->GetFieldIndex(i)); |
2415 if (FLAG_track_double_fields && | 2368 if (FLAG_track_double_fields && |
2416 !old_details.representation().IsDouble() && | 2369 !old_details.representation().IsDouble() && |
2417 details.representation().IsDouble()) { | 2370 details.representation().IsDouble()) { |
2418 if (old_details.representation().IsNone()) value = Smi::FromInt(0); | 2371 if (old_details.representation().IsNone()) value = Smi::FromInt(0); |
2419 // Objects must be allocated in the old object space, since the | 2372 // Objects must be allocated in the old object space, since the |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2481 for (int i = 0; i < NumberOfOwnDescriptors(); i++) { | 2434 for (int i = 0; i < NumberOfOwnDescriptors(); i++) { |
2482 if (descriptors->GetDetails(i).type() == FIELD) result++; | 2435 if (descriptors->GetDetails(i).type() == FIELD) result++; |
2483 } | 2436 } |
2484 return result; | 2437 return result; |
2485 } | 2438 } |
2486 | 2439 |
2487 | 2440 |
2488 MaybeObject* Map::CopyGeneralizeAllRepresentations( | 2441 MaybeObject* Map::CopyGeneralizeAllRepresentations( |
2489 int modify_index, | 2442 int modify_index, |
2490 StoreMode store_mode, | 2443 StoreMode store_mode, |
| 2444 PropertyAttributes attributes, |
2491 const char* reason) { | 2445 const char* reason) { |
2492 Map* new_map; | 2446 Map* new_map; |
2493 MaybeObject* maybe_map = this->Copy(); | 2447 MaybeObject* maybe_map = this->Copy(); |
2494 if (!maybe_map->To(&new_map)) return maybe_map; | 2448 if (!maybe_map->To(&new_map)) return maybe_map; |
2495 | 2449 |
2496 DescriptorArray* descriptors = new_map->instance_descriptors(); | 2450 DescriptorArray* descriptors = new_map->instance_descriptors(); |
2497 descriptors->InitializeRepresentations(Representation::Tagged()); | 2451 descriptors->InitializeRepresentations(Representation::Tagged()); |
2498 | 2452 |
2499 // Unless the instance is being migrated, ensure that modify_index is a field. | 2453 // Unless the instance is being migrated, ensure that modify_index is a field. |
2500 PropertyDetails details = descriptors->GetDetails(modify_index); | 2454 PropertyDetails details = descriptors->GetDetails(modify_index); |
2501 if (store_mode == FORCE_FIELD && details.type() != FIELD) { | 2455 if (store_mode == FORCE_FIELD && details.type() != FIELD) { |
2502 FieldDescriptor d(descriptors->GetKey(modify_index), | 2456 FieldDescriptor d(descriptors->GetKey(modify_index), |
2503 new_map->NumberOfFields(), | 2457 new_map->NumberOfFields(), |
2504 details.attributes(), | 2458 attributes, |
2505 Representation::Tagged()); | 2459 Representation::Tagged()); |
2506 d.SetSortedKeyIndex(details.pointer()); | 2460 d.SetSortedKeyIndex(details.pointer()); |
2507 descriptors->Set(modify_index, &d); | 2461 descriptors->Set(modify_index, &d); |
2508 int unused_property_fields = new_map->unused_property_fields() - 1; | 2462 int unused_property_fields = new_map->unused_property_fields() - 1; |
2509 if (unused_property_fields < 0) { | 2463 if (unused_property_fields < 0) { |
2510 unused_property_fields += JSObject::kFieldsAdded; | 2464 unused_property_fields += JSObject::kFieldsAdded; |
2511 } | 2465 } |
2512 new_map->set_unused_property_fields(unused_property_fields); | 2466 new_map->set_unused_property_fields(unused_property_fields); |
2513 } | 2467 } |
2514 | 2468 |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2659 // |split_map|, the first map who's descriptor array does not match the merged | 2613 // |split_map|, the first map who's descriptor array does not match the merged |
2660 // descriptor array. | 2614 // descriptor array. |
2661 // - If |updated| == |split_map|, |updated| is in the expected state. Return it. | 2615 // - If |updated| == |split_map|, |updated| is in the expected state. Return it. |
2662 // - Otherwise, invalidate the outdated transition target from |updated|, and | 2616 // - Otherwise, invalidate the outdated transition target from |updated|, and |
2663 // replace its transition tree with a new branch for the updated descriptors. | 2617 // replace its transition tree with a new branch for the updated descriptors. |
2664 MaybeObject* Map::GeneralizeRepresentation(int modify_index, | 2618 MaybeObject* Map::GeneralizeRepresentation(int modify_index, |
2665 Representation new_representation, | 2619 Representation new_representation, |
2666 StoreMode store_mode) { | 2620 StoreMode store_mode) { |
2667 Map* old_map = this; | 2621 Map* old_map = this; |
2668 DescriptorArray* old_descriptors = old_map->instance_descriptors(); | 2622 DescriptorArray* old_descriptors = old_map->instance_descriptors(); |
2669 Representation old_representation = | 2623 PropertyDetails old_details = old_descriptors->GetDetails(modify_index); |
2670 old_descriptors->GetDetails(modify_index).representation(); | 2624 Representation old_representation = old_details.representation(); |
2671 | 2625 |
2672 // It's fine to transition from None to anything but double without any | 2626 // It's fine to transition from None to anything but double without any |
2673 // modification to the object, because the default uninitialized value for | 2627 // modification to the object, because the default uninitialized value for |
2674 // representation None can be overwritten by both smi and tagged values. | 2628 // representation None can be overwritten by both smi and tagged values. |
2675 // Doubles, however, would require a box allocation. | 2629 // Doubles, however, would require a box allocation. |
2676 if (old_representation.IsNone() && | 2630 if (old_representation.IsNone() && |
2677 !new_representation.IsNone() && | 2631 !new_representation.IsNone() && |
2678 !new_representation.IsDouble()) { | 2632 !new_representation.IsDouble()) { |
2679 old_descriptors->SetRepresentation(modify_index, new_representation); | 2633 old_descriptors->SetRepresentation(modify_index, new_representation); |
2680 return old_map; | 2634 return old_map; |
2681 } | 2635 } |
2682 | 2636 |
2683 int descriptors = old_map->NumberOfOwnDescriptors(); | 2637 int descriptors = old_map->NumberOfOwnDescriptors(); |
2684 Map* root_map = old_map->FindRootMap(); | 2638 Map* root_map = old_map->FindRootMap(); |
2685 | 2639 |
2686 // Check the state of the root map. | 2640 // Check the state of the root map. |
2687 if (!old_map->EquivalentToForTransition(root_map)) { | 2641 if (!old_map->EquivalentToForTransition(root_map)) { |
2688 return CopyGeneralizeAllRepresentations( | 2642 return CopyGeneralizeAllRepresentations( |
2689 modify_index, store_mode, "not equivalent"); | 2643 modify_index, store_mode, old_details.attributes(), "not equivalent"); |
2690 } | 2644 } |
2691 | 2645 |
2692 int verbatim = root_map->NumberOfOwnDescriptors(); | 2646 int verbatim = root_map->NumberOfOwnDescriptors(); |
2693 | 2647 |
2694 if (store_mode != ALLOW_AS_CONSTANT && modify_index < verbatim) { | 2648 if (store_mode != ALLOW_AS_CONSTANT && modify_index < verbatim) { |
2695 return CopyGeneralizeAllRepresentations( | 2649 return CopyGeneralizeAllRepresentations( |
2696 modify_index, store_mode, "root modification"); | 2650 modify_index, store_mode, |
| 2651 old_details.attributes(), "root modification"); |
2697 } | 2652 } |
2698 | 2653 |
2699 Map* updated = root_map->FindUpdatedMap( | 2654 Map* updated = root_map->FindUpdatedMap( |
2700 verbatim, descriptors, old_descriptors); | 2655 verbatim, descriptors, old_descriptors); |
2701 if (updated == NULL) { | 2656 if (updated == NULL) { |
2702 return CopyGeneralizeAllRepresentations( | 2657 return CopyGeneralizeAllRepresentations( |
2703 modify_index, store_mode, "incompatible"); | 2658 modify_index, store_mode, old_details.attributes(), "incompatible"); |
2704 } | 2659 } |
2705 | 2660 |
2706 DescriptorArray* updated_descriptors = updated->instance_descriptors(); | 2661 DescriptorArray* updated_descriptors = updated->instance_descriptors(); |
2707 | 2662 |
2708 int valid = updated->NumberOfOwnDescriptors(); | 2663 int valid = updated->NumberOfOwnDescriptors(); |
2709 | 2664 |
2710 // Directly change the map if the target map is more general. Ensure that the | 2665 // Directly change the map if the target map is more general. Ensure that the |
2711 // target type of the modify_index is a FIELD, unless we are migrating. | 2666 // target type of the modify_index is a FIELD, unless we are migrating. |
2712 if (updated_descriptors->IsMoreGeneralThan( | 2667 if (updated_descriptors->IsMoreGeneralThan( |
2713 verbatim, valid, descriptors, old_descriptors) && | 2668 verbatim, valid, descriptors, old_descriptors) && |
(...skipping 1095 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3809 Handle<Name> name, | 3764 Handle<Name> name, |
3810 Handle<Object> value, | 3765 Handle<Object> value, |
3811 PropertyAttributes attributes) { | 3766 PropertyAttributes attributes) { |
3812 Map* transition_map = lookup->GetTransitionTarget(); | 3767 Map* transition_map = lookup->GetTransitionTarget(); |
3813 int descriptor = transition_map->LastAdded(); | 3768 int descriptor = transition_map->LastAdded(); |
3814 | 3769 |
3815 DescriptorArray* descriptors = transition_map->instance_descriptors(); | 3770 DescriptorArray* descriptors = transition_map->instance_descriptors(); |
3816 PropertyDetails details = descriptors->GetDetails(descriptor); | 3771 PropertyDetails details = descriptors->GetDetails(descriptor); |
3817 | 3772 |
3818 if (details.type() == CALLBACKS || attributes != details.attributes()) { | 3773 if (details.type() == CALLBACKS || attributes != details.attributes()) { |
3819 return lookup->holder()->ConvertDescriptorToField( | 3774 // AddProperty will either normalize the object, or create a new fast copy |
3820 *name, *value, attributes); | 3775 // of the map. If we get a fast copy of the map, all field representations |
| 3776 // will be tagged since the transition is omitted. |
| 3777 return lookup->holder()->AddProperty( |
| 3778 *name, *value, attributes, kNonStrictMode, |
| 3779 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED, |
| 3780 JSReceiver::OMIT_EXTENSIBILITY_CHECK, |
| 3781 JSObject::FORCE_TAGGED, FORCE_FIELD, OMIT_TRANSITION); |
3821 } | 3782 } |
3822 | 3783 |
3823 // Keep the target CONSTANT if the same value is stored. | 3784 // Keep the target CONSTANT if the same value is stored. |
3824 // TODO(verwaest): Also support keeping the placeholder | 3785 // TODO(verwaest): Also support keeping the placeholder |
3825 // (value->IsUninitialized) as constant. | 3786 // (value->IsUninitialized) as constant. |
3826 if (details.type() == CONSTANT && | 3787 if (details.type() == CONSTANT && |
3827 descriptors->GetValue(descriptor) == *value) { | 3788 descriptors->GetValue(descriptor) == *value) { |
3828 lookup->holder()->set_map(transition_map); | 3789 lookup->holder()->set_map(transition_map); |
3829 return *value; | 3790 return *value; |
3830 } | 3791 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3875 storage->set_value(value->Number()); | 3836 storage->set_value(value->Number()); |
3876 return *value; | 3837 return *value; |
3877 } | 3838 } |
3878 | 3839 |
3879 lookup->holder()->FastPropertyAtPut( | 3840 lookup->holder()->FastPropertyAtPut( |
3880 lookup->GetFieldIndex().field_index(), *value); | 3841 lookup->GetFieldIndex().field_index(), *value); |
3881 return *value; | 3842 return *value; |
3882 } | 3843 } |
3883 | 3844 |
3884 | 3845 |
| 3846 static MaybeObject* ConvertAndSetLocalProperty(LookupResult* lookup, |
| 3847 Name* name, |
| 3848 Object* value, |
| 3849 PropertyAttributes attributes) { |
| 3850 JSObject* object = lookup->holder(); |
| 3851 if (object->TooManyFastProperties()) { |
| 3852 MaybeObject* maybe_failure = object->NormalizeProperties( |
| 3853 CLEAR_INOBJECT_PROPERTIES, 0); |
| 3854 if (maybe_failure->IsFailure()) return maybe_failure; |
| 3855 } |
| 3856 |
| 3857 if (!object->HasFastProperties()) { |
| 3858 return object->ReplaceSlowProperty(name, value, attributes); |
| 3859 } |
| 3860 |
| 3861 int descriptor_index = lookup->GetDescriptorIndex(); |
| 3862 if (lookup->GetAttributes() == attributes) { |
| 3863 MaybeObject* maybe_failure = object->GeneralizeFieldRepresentation( |
| 3864 descriptor_index, Representation::Tagged(), FORCE_FIELD); |
| 3865 if (maybe_failure->IsFailure()) return maybe_failure; |
| 3866 } else { |
| 3867 Map* map; |
| 3868 MaybeObject* maybe_map = object->map()->CopyGeneralizeAllRepresentations( |
| 3869 descriptor_index, FORCE_FIELD, attributes, "attributes mismatch"); |
| 3870 if (!maybe_map->To(&map)) return maybe_map; |
| 3871 MaybeObject* maybe_failure = object->MigrateToMap(map); |
| 3872 if (maybe_failure->IsFailure()) return maybe_failure; |
| 3873 } |
| 3874 |
| 3875 DescriptorArray* descriptors = object->map()->instance_descriptors(); |
| 3876 int index = descriptors->GetDetails(descriptor_index).field_index(); |
| 3877 object->FastPropertyAtPut(index, value); |
| 3878 return value; |
| 3879 } |
| 3880 |
| 3881 |
| 3882 static MaybeObject* SetPropertyToFieldWithAttributes( |
| 3883 LookupResult* lookup, |
| 3884 Handle<Name> name, |
| 3885 Handle<Object> value, |
| 3886 PropertyAttributes attributes) { |
| 3887 if (lookup->GetAttributes() == attributes) { |
| 3888 if (value->IsUninitialized()) return *value; |
| 3889 return SetPropertyToField(lookup, name, value); |
| 3890 } else { |
| 3891 return ConvertAndSetLocalProperty(lookup, *name, *value, attributes); |
| 3892 } |
| 3893 } |
| 3894 |
| 3895 |
3885 MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, | 3896 MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, |
3886 Name* name_raw, | 3897 Name* name_raw, |
3887 Object* value_raw, | 3898 Object* value_raw, |
3888 PropertyAttributes attributes, | 3899 PropertyAttributes attributes, |
3889 StrictModeFlag strict_mode, | 3900 StrictModeFlag strict_mode, |
3890 StoreFromKeyed store_mode) { | 3901 StoreFromKeyed store_mode) { |
3891 Heap* heap = GetHeap(); | 3902 Heap* heap = GetHeap(); |
3892 Isolate* isolate = heap->isolate(); | 3903 Isolate* isolate = heap->isolate(); |
3893 // Make sure that the top context does not change when doing callbacks or | 3904 // Make sure that the top context does not change when doing callbacks or |
3894 // interceptor calls. | 3905 // interceptor calls. |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4098 PropertyAttributes old_attributes = ABSENT; | 4109 PropertyAttributes old_attributes = ABSENT; |
4099 bool is_observed = FLAG_harmony_observation && self->map()->is_observed(); | 4110 bool is_observed = FLAG_harmony_observation && self->map()->is_observed(); |
4100 if (is_observed && lookup.IsProperty()) { | 4111 if (is_observed && lookup.IsProperty()) { |
4101 if (lookup.IsDataProperty()) old_value = Object::GetProperty(self, name); | 4112 if (lookup.IsDataProperty()) old_value = Object::GetProperty(self, name); |
4102 old_attributes = lookup.GetAttributes(); | 4113 old_attributes = lookup.GetAttributes(); |
4103 } | 4114 } |
4104 | 4115 |
4105 // Check of IsReadOnly removed from here in clone. | 4116 // Check of IsReadOnly removed from here in clone. |
4106 MaybeObject* result = *value; | 4117 MaybeObject* result = *value; |
4107 switch (lookup.type()) { | 4118 switch (lookup.type()) { |
4108 case NORMAL: { | 4119 case NORMAL: |
4109 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0); | 4120 result = self->ReplaceSlowProperty(*name, *value, attributes); |
4110 result = self->SetNormalizedProperty(*name, *value, details); | |
4111 break; | 4121 break; |
4112 } | |
4113 case FIELD: | 4122 case FIELD: |
4114 if (value->IsUninitialized()) break; | 4123 result = SetPropertyToFieldWithAttributes( |
4115 result = SetPropertyToField(&lookup, name, value); | 4124 &lookup, name, value, attributes); |
4116 break; | 4125 break; |
4117 case CONSTANT: | 4126 case CONSTANT: |
4118 // Only replace the constant if necessary. | 4127 // Only replace the constant if necessary. |
4119 if (*value == lookup.GetConstant()) return *value; | 4128 if (lookup.GetAttributes() != attributes || |
4120 if (value->IsUninitialized()) break; | 4129 *value != lookup.GetConstant()) { |
4121 result = SetPropertyToField(&lookup, name, value); | 4130 result = SetPropertyToFieldWithAttributes( |
| 4131 &lookup, name, value, attributes); |
| 4132 } |
4122 break; | 4133 break; |
4123 case CALLBACKS: | 4134 case CALLBACKS: |
| 4135 // Callbacks are not guaranteed to be installed on the receiver. Also |
| 4136 // perform a local lookup again. Fall through. |
4124 case INTERCEPTOR: | 4137 case INTERCEPTOR: |
4125 // Override callback in clone | 4138 self->LocalLookupRealNamedProperty(*name, &lookup); |
4126 result = self->ConvertDescriptorToField(*name, *value, attributes); | 4139 if (lookup.IsFound()) { |
| 4140 if (lookup.IsPropertyCallbacks()) { |
| 4141 result = ConvertAndSetLocalProperty( |
| 4142 &lookup, *name, *value, attributes); |
| 4143 } else if (lookup.IsNormal()) { |
| 4144 result = self->ReplaceSlowProperty(*name, *value, attributes); |
| 4145 } else { |
| 4146 result = SetPropertyToFieldWithAttributes( |
| 4147 &lookup, name, value, attributes); |
| 4148 } |
| 4149 } else { |
| 4150 result = self->AddProperty( |
| 4151 *name, *value, attributes, kNonStrictMode, MAY_BE_STORE_FROM_KEYED, |
| 4152 extensibility_check, value_type, mode); |
| 4153 } |
4127 break; | 4154 break; |
4128 case TRANSITION: | 4155 case TRANSITION: |
4129 result = SetPropertyUsingTransition(&lookup, name, value, attributes); | 4156 result = SetPropertyUsingTransition(&lookup, name, value, attributes); |
4130 break; | 4157 break; |
4131 case HANDLER: | 4158 case HANDLER: |
4132 case NONEXISTENT: | 4159 case NONEXISTENT: |
4133 UNREACHABLE(); | 4160 UNREACHABLE(); |
4134 } | 4161 } |
4135 | 4162 |
4136 Handle<Object> hresult; | 4163 Handle<Object> hresult; |
(...skipping 11845 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15982 #define ERROR_MESSAGES_TEXTS(C, T) T, | 16009 #define ERROR_MESSAGES_TEXTS(C, T) T, |
15983 static const char* error_messages_[] = { | 16010 static const char* error_messages_[] = { |
15984 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) | 16011 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) |
15985 }; | 16012 }; |
15986 #undef ERROR_MESSAGES_TEXTS | 16013 #undef ERROR_MESSAGES_TEXTS |
15987 return error_messages_[reason]; | 16014 return error_messages_[reason]; |
15988 } | 16015 } |
15989 | 16016 |
15990 | 16017 |
15991 } } // namespace v8::internal | 16018 } } // namespace v8::internal |
OLD | NEW |