OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <memory> | 9 #include <memory> |
10 #include <sstream> | 10 #include <sstream> |
(...skipping 1984 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1995 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); | 1995 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); |
1996 if (iter.IsAtEnd()) return Just(false); | 1996 if (iter.IsAtEnd()) return Just(false); |
1997 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) { | 1997 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) { |
1998 return Just(true); | 1998 return Just(true); |
1999 } | 1999 } |
2000 } | 2000 } |
2001 } | 2001 } |
2002 | 2002 |
2003 namespace { | 2003 namespace { |
2004 | 2004 |
2005 MUST_USE_RESULT Maybe<bool> FastAssign(Handle<JSReceiver> target, | 2005 bool HasElementInJSArray(Isolate* isolate, Handle<JSArray> array, |
2006 Handle<Object> source, bool use_set) { | 2006 Handle<Object> search_element) { |
2007 uint32_t len = 0; | |
2008 bool success = array->length()->ToArrayLength(&len); | |
2009 DCHECK(success); | |
2010 | |
2011 if (len == 0) return false; | |
2012 | |
2013 int32_t start = 0; | |
2014 ElementsAccessor* elements = array->GetElementsAccessor(); | |
2015 Maybe<bool> result = | |
2016 elements->IncludesValue(isolate, array, search_element, start, len); | |
2017 return result.FromJust(); | |
2018 } | |
2019 | |
2020 MUST_USE_RESULT Maybe<bool> FastAssign( | |
2021 Handle<JSReceiver> target, Handle<Object> source, | |
2022 MaybeHandle<JSArray> maybe_excluded_properties, bool use_set) { | |
2007 // Non-empty strings are the only non-JSReceivers that need to be handled | 2023 // Non-empty strings are the only non-JSReceivers that need to be handled |
2008 // explicitly by Object.assign. | 2024 // explicitly by Object.assign. |
2009 if (!source->IsJSReceiver()) { | 2025 if (!source->IsJSReceiver()) { |
2010 return Just(!source->IsString() || String::cast(*source)->length() == 0); | 2026 return Just(!source->IsString() || String::cast(*source)->length() == 0); |
2011 } | 2027 } |
2012 | 2028 |
2013 // If the target is deprecated, the object will be updated on first store. If | 2029 // If the target is deprecated, the object will be updated on first store. If |
2014 // the source for that store equals the target, this will invalidate the | 2030 // the source for that store equals the target, this will invalidate the |
2015 // cached representation of the source. Preventively upgrade the target. | 2031 // cached representation of the source. Preventively upgrade the target. |
2016 // Do this on each iteration since any property load could cause deprecation. | 2032 // Do this on each iteration since any property load could cause deprecation. |
2017 if (target->map()->is_deprecated()) { | 2033 if (target->map()->is_deprecated()) { |
2018 JSObject::MigrateInstance(Handle<JSObject>::cast(target)); | 2034 JSObject::MigrateInstance(Handle<JSObject>::cast(target)); |
2019 } | 2035 } |
2020 | 2036 |
2021 Isolate* isolate = target->GetIsolate(); | 2037 Isolate* isolate = target->GetIsolate(); |
2022 Handle<Map> map(JSReceiver::cast(*source)->map(), isolate); | 2038 Handle<Map> map(JSReceiver::cast(*source)->map(), isolate); |
2023 | 2039 |
2024 if (!map->IsJSObjectMap()) return Just(false); | 2040 if (!map->IsJSObjectMap()) return Just(false); |
2025 if (!map->OnlyHasSimpleProperties()) return Just(false); | 2041 if (!map->OnlyHasSimpleProperties()) return Just(false); |
2026 | 2042 |
2027 Handle<JSObject> from = Handle<JSObject>::cast(source); | 2043 Handle<JSObject> from = Handle<JSObject>::cast(source); |
2028 if (from->elements() != isolate->heap()->empty_fixed_array()) { | 2044 if (from->elements() != isolate->heap()->empty_fixed_array()) { |
2029 return Just(false); | 2045 return Just(false); |
2030 } | 2046 } |
2031 | 2047 |
2032 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); | 2048 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); |
2033 int length = map->NumberOfOwnDescriptors(); | 2049 int length = map->NumberOfOwnDescriptors(); |
2034 | 2050 |
2035 bool stable = true; | 2051 bool stable = true; |
2052 Handle<JSArray> excluded_properties; | |
2053 if (!maybe_excluded_properties.is_null()) { | |
2054 excluded_properties = maybe_excluded_properties.ToHandleChecked(); | |
adamk
2017/01/10 23:22:56
Pattern for this is:
const bool has_excluded_prop
| |
2055 } | |
2036 | 2056 |
2037 for (int i = 0; i < length; i++) { | 2057 for (int i = 0; i < length; i++) { |
2038 Handle<Name> next_key(descriptors->GetKey(i), isolate); | 2058 Handle<Name> next_key(descriptors->GetKey(i), isolate); |
2039 Handle<Object> prop_value; | 2059 Handle<Object> prop_value; |
2040 // Directly decode from the descriptor array if |from| did not change shape. | 2060 // Directly decode from the descriptor array if |from| did not change shape. |
2041 if (stable) { | 2061 if (stable) { |
2042 PropertyDetails details = descriptors->GetDetails(i); | 2062 PropertyDetails details = descriptors->GetDetails(i); |
2043 if (!details.IsEnumerable()) continue; | 2063 if (!details.IsEnumerable()) continue; |
2044 if (details.kind() == kData) { | 2064 if (details.kind() == kData) { |
2045 if (details.location() == kDescriptor) { | 2065 if (details.location() == kDescriptor) { |
(...skipping 23 matching lines...) Expand all Loading... | |
2069 } | 2089 } |
2070 | 2090 |
2071 if (use_set) { | 2091 if (use_set) { |
2072 LookupIterator it(target, next_key, target); | 2092 LookupIterator it(target, next_key, target); |
2073 bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA; | 2093 bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA; |
2074 Maybe<bool> result = Object::SetProperty( | 2094 Maybe<bool> result = Object::SetProperty( |
2075 &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED); | 2095 &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED); |
2076 if (result.IsNothing()) return result; | 2096 if (result.IsNothing()) return result; |
2077 if (stable && call_to_js) stable = from->map() == *map; | 2097 if (stable && call_to_js) stable = from->map() == *map; |
2078 } else { | 2098 } else { |
2099 if (!maybe_excluded_properties.is_null() && | |
adamk
2017/01/10 23:22:56
and then this would be
if (has_excluded_propertie
| |
2100 HasElementInJSArray(isolate, excluded_properties, next_key)) { | |
2101 continue; | |
2102 } | |
2103 | |
2079 // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue). | 2104 // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue). |
2080 bool success; | 2105 bool success; |
2081 LookupIterator it = LookupIterator::PropertyOrElement( | 2106 LookupIterator it = LookupIterator::PropertyOrElement( |
2082 isolate, target, next_key, &success, LookupIterator::OWN); | 2107 isolate, target, next_key, &success, LookupIterator::OWN); |
2083 CHECK(success); | 2108 CHECK(success); |
2084 CHECK( | 2109 CHECK( |
2085 JSObject::CreateDataProperty(&it, prop_value, Object::THROW_ON_ERROR) | 2110 JSObject::CreateDataProperty(&it, prop_value, Object::THROW_ON_ERROR) |
2086 .FromJust()); | 2111 .FromJust()); |
2087 } | 2112 } |
2088 } | 2113 } |
2089 | 2114 |
2090 return Just(true); | 2115 return Just(true); |
2091 } | 2116 } |
2092 | |
2093 } // namespace | 2117 } // namespace |
2094 | 2118 |
2095 // static | 2119 // static |
2096 Maybe<bool> JSReceiver::SetOrCopyDataProperties(Isolate* isolate, | 2120 Maybe<bool> JSReceiver::SetOrCopyDataProperties( |
2097 Handle<JSReceiver> target, | 2121 Isolate* isolate, Handle<JSReceiver> target, Handle<Object> source, |
2098 Handle<Object> source, | 2122 MaybeHandle<JSArray> maybe_excluded_properties, bool use_set) { |
2099 bool use_set) { | 2123 Maybe<bool> fast_assign = |
2100 Maybe<bool> fast_assign = FastAssign(target, source, use_set); | 2124 FastAssign(target, source, maybe_excluded_properties, use_set); |
2101 if (fast_assign.IsNothing()) return Nothing<bool>(); | 2125 if (fast_assign.IsNothing()) return Nothing<bool>(); |
2102 if (fast_assign.FromJust()) return Just(true); | 2126 if (fast_assign.FromJust()) return Just(true); |
2103 | 2127 |
2104 Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked(); | 2128 Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked(); |
2105 // 3b. Let keys be ? from.[[OwnPropertyKeys]](). | 2129 // 3b. Let keys be ? from.[[OwnPropertyKeys]](). |
2106 Handle<FixedArray> keys; | 2130 Handle<FixedArray> keys; |
2107 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 2131 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
2108 isolate, keys, | 2132 isolate, keys, |
2109 KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, | 2133 KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, |
2110 GetKeysConversion::kKeepNumbers), | 2134 GetKeysConversion::kKeepNumbers), |
2111 Nothing<bool>()); | 2135 Nothing<bool>()); |
2112 | 2136 |
2137 Handle<JSArray> excluded_properties; | |
2138 if (!maybe_excluded_properties.is_null()) { | |
2139 excluded_properties = maybe_excluded_properties.ToHandleChecked(); | |
adamk
2017/01/10 23:22:56
Same here as above
| |
2140 } | |
2141 | |
2113 // 4. Repeat for each element nextKey of keys in List order, | 2142 // 4. Repeat for each element nextKey of keys in List order, |
2114 for (int j = 0; j < keys->length(); ++j) { | 2143 for (int j = 0; j < keys->length(); ++j) { |
2115 Handle<Object> next_key(keys->get(j), isolate); | 2144 Handle<Object> next_key(keys->get(j), isolate); |
2116 // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey). | 2145 // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey). |
2117 PropertyDescriptor desc; | 2146 PropertyDescriptor desc; |
2118 Maybe<bool> found = | 2147 Maybe<bool> found = |
2119 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc); | 2148 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc); |
2120 if (found.IsNothing()) return Nothing<bool>(); | 2149 if (found.IsNothing()) return Nothing<bool>(); |
2121 // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then | 2150 // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then |
2122 if (found.FromJust() && desc.enumerable()) { | 2151 if (found.FromJust() && desc.enumerable()) { |
2123 // 4a ii 1. Let propValue be ? Get(from, nextKey). | 2152 // 4a ii 1. Let propValue be ? Get(from, nextKey). |
2124 Handle<Object> prop_value; | 2153 Handle<Object> prop_value; |
2125 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 2154 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
2126 isolate, prop_value, | 2155 isolate, prop_value, |
2127 Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>()); | 2156 Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>()); |
2128 | 2157 |
2129 if (use_set) { | 2158 if (use_set) { |
2130 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true). | 2159 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true). |
2131 Handle<Object> status; | 2160 Handle<Object> status; |
2132 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 2161 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
2133 isolate, status, Runtime::SetObjectProperty( | 2162 isolate, status, Runtime::SetObjectProperty( |
2134 isolate, target, next_key, prop_value, STRICT), | 2163 isolate, target, next_key, prop_value, STRICT), |
2135 Nothing<bool>()); | 2164 Nothing<bool>()); |
2136 } else { | 2165 } else { |
2166 if (!maybe_excluded_properties.is_null() && | |
adamk
2017/01/10 23:22:55
And here.
| |
2167 HasElementInJSArray(isolate, excluded_properties, next_key)) { | |
2168 continue; | |
2169 } | |
2170 | |
2137 // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue). | 2171 // 4a ii 2. Perform ! CreateDataProperty(target, nextKey, propValue). |
2138 bool success; | 2172 bool success; |
2139 LookupIterator it = LookupIterator::PropertyOrElement( | 2173 LookupIterator it = LookupIterator::PropertyOrElement( |
2140 isolate, target, next_key, &success, LookupIterator::OWN); | 2174 isolate, target, next_key, &success, LookupIterator::OWN); |
2141 CHECK(success); | 2175 CHECK(success); |
2142 CHECK(JSObject::CreateDataProperty(&it, prop_value, | 2176 CHECK(JSObject::CreateDataProperty(&it, prop_value, |
2143 Object::THROW_ON_ERROR) | 2177 Object::THROW_ON_ERROR) |
2144 .FromJust()); | 2178 .FromJust()); |
2145 } | 2179 } |
2146 } | 2180 } |
(...skipping 17806 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
19953 // depend on this. | 19987 // depend on this. |
19954 return DICTIONARY_ELEMENTS; | 19988 return DICTIONARY_ELEMENTS; |
19955 } | 19989 } |
19956 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 19990 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
19957 return kind; | 19991 return kind; |
19958 } | 19992 } |
19959 } | 19993 } |
19960 | 19994 |
19961 } // namespace internal | 19995 } // namespace internal |
19962 } // namespace v8 | 19996 } // namespace v8 |
OLD | NEW |