Chromium Code Reviews| 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 1981 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1992 PrototypeIterator iter(isolate, object, kStartAtReceiver); | 1992 PrototypeIterator iter(isolate, object, kStartAtReceiver); |
| 1993 while (true) { | 1993 while (true) { |
| 1994 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); | 1994 if (!iter.AdvanceFollowingProxies()) return Nothing<bool>(); |
| 1995 if (iter.IsAtEnd()) return Just(false); | 1995 if (iter.IsAtEnd()) return Just(false); |
| 1996 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) { | 1996 if (PrototypeIterator::GetCurrent(iter).is_identical_to(proto)) { |
| 1997 return Just(true); | 1997 return Just(true); |
| 1998 } | 1998 } |
| 1999 } | 1999 } |
| 2000 } | 2000 } |
| 2001 | 2001 |
| 2002 namespace { | |
| 2003 | |
| 2004 MUST_USE_RESULT Maybe<bool> FastAssign(Handle<JSReceiver> target, | |
| 2005 Handle<Object> source, bool use_set) { | |
| 2006 // Non-empty strings are the only non-JSReceivers that need to be handled | |
| 2007 // explicitly by Object.assign. | |
| 2008 if (!source->IsJSReceiver()) { | |
| 2009 return Just(!source->IsString() || String::cast(*source)->length() == 0); | |
| 2010 } | |
| 2011 | |
| 2012 // If the target is deprecated, the object will be updated on first store. If | |
| 2013 // the source for that store equals the target, this will invalidate the | |
| 2014 // cached representation of the source. Preventively upgrade the target. | |
| 2015 // Do this on each iteration since any property load could cause deprecation. | |
| 2016 if (target->map()->is_deprecated()) { | |
| 2017 JSObject::MigrateInstance(Handle<JSObject>::cast(target)); | |
| 2018 } | |
| 2019 | |
| 2020 Isolate* isolate = target->GetIsolate(); | |
| 2021 Handle<Map> map(JSReceiver::cast(*source)->map(), isolate); | |
| 2022 | |
| 2023 if (!map->IsJSObjectMap()) return Just(false); | |
| 2024 if (!map->OnlyHasSimpleProperties()) return Just(false); | |
| 2025 | |
| 2026 Handle<JSObject> from = Handle<JSObject>::cast(source); | |
| 2027 if (from->elements() != isolate->heap()->empty_fixed_array()) { | |
| 2028 return Just(false); | |
| 2029 } | |
| 2030 | |
| 2031 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); | |
| 2032 int length = map->NumberOfOwnDescriptors(); | |
| 2033 | |
| 2034 bool stable = true; | |
| 2035 | |
| 2036 for (int i = 0; i < length; i++) { | |
| 2037 Handle<Name> next_key(descriptors->GetKey(i), isolate); | |
| 2038 Handle<Object> prop_value; | |
| 2039 // Directly decode from the descriptor array if |from| did not change shape. | |
| 2040 if (stable) { | |
| 2041 PropertyDetails details = descriptors->GetDetails(i); | |
| 2042 if (!details.IsEnumerable()) continue; | |
| 2043 if (details.kind() == kData) { | |
| 2044 if (details.location() == kDescriptor) { | |
| 2045 prop_value = handle(descriptors->GetValue(i), isolate); | |
| 2046 } else { | |
| 2047 Representation representation = details.representation(); | |
| 2048 FieldIndex index = FieldIndex::ForDescriptor(*map, i); | |
| 2049 prop_value = JSObject::FastPropertyAt(from, representation, index); | |
| 2050 } | |
| 2051 } else { | |
| 2052 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 2053 isolate, prop_value, JSReceiver::GetProperty(from, next_key), | |
| 2054 Nothing<bool>()); | |
| 2055 stable = from->map() == *map; | |
| 2056 } | |
| 2057 } else { | |
| 2058 // If the map did change, do a slower lookup. We are still guaranteed that | |
| 2059 // the object has a simple shape, and that the key is a name. | |
| 2060 LookupIterator it(from, next_key, from, | |
| 2061 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
| 2062 if (!it.IsFound()) continue; | |
| 2063 DCHECK(it.state() == LookupIterator::DATA || | |
| 2064 it.state() == LookupIterator::ACCESSOR); | |
| 2065 if (!it.IsEnumerable()) continue; | |
| 2066 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 2067 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); | |
| 2068 } | |
| 2069 | |
| 2070 if (use_set) { | |
| 2071 LookupIterator it(target, next_key, target); | |
| 2072 bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA; | |
| 2073 Maybe<bool> result = Object::SetProperty( | |
| 2074 &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED); | |
| 2075 if (result.IsNothing()) return result; | |
| 2076 if (stable && call_to_js) stable = from->map() == *map; | |
| 2077 } else { | |
| 2078 // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue). | |
| 2079 bool success; | |
| 2080 LookupIterator it = LookupIterator::PropertyOrElement( | |
| 2081 isolate, target, next_key, &success, LookupIterator::OWN); | |
| 2082 if (!success) return Nothing<bool>(); | |
| 2083 MAYBE_RETURN(JSReceiver::CreateDataProperty(&it, prop_value, | |
| 2084 Object::THROW_ON_ERROR), | |
| 2085 Nothing<bool>()); | |
| 2086 } | |
| 2087 } | |
| 2088 | |
| 2089 return Just(true); | |
| 2090 } | |
| 2091 | |
| 2092 } // namespace | |
| 2093 | |
| 2094 // static | |
| 2095 Maybe<bool> JSReceiver::SetOrCopyDataProperties(Isolate* isolate, | |
| 2096 Handle<JSReceiver> target, | |
| 2097 Handle<Object> source, | |
| 2098 bool use_set) { | |
|
Dan Ehrenberg
2016/12/29 17:31:03
I'm slightly worried that checking use_set paramet
gsathya
2017/01/05 22:18:36
Acknowledged.
| |
| 2099 Maybe<bool> fast_assign = FastAssign(target, source, use_set); | |
| 2100 if (fast_assign.IsNothing()) return Nothing<bool>(); | |
| 2101 if (fast_assign.FromJust()) return Just(true); | |
| 2102 | |
| 2103 Handle<JSReceiver> from = Object::ToObject(isolate, source).ToHandleChecked(); | |
| 2104 // 3b. Let keys be ? from.[[OwnPropertyKeys]](). | |
| 2105 Handle<FixedArray> keys; | |
| 2106 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 2107 isolate, keys, | |
| 2108 KeyAccumulator::GetKeys(from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, | |
| 2109 GetKeysConversion::kKeepNumbers), | |
| 2110 Nothing<bool>()); | |
| 2111 | |
| 2112 // 4. Repeat for each element nextKey of keys in List order, | |
| 2113 for (int j = 0; j < keys->length(); ++j) { | |
|
adamk
2016/12/29 18:32:46
s/j/i/ now that this isn't a nested loop.
gsathya
2017/01/05 22:18:36
Done.
| |
| 2114 Handle<Object> next_key(keys->get(j), isolate); | |
| 2115 // 4a i. Let desc be ? from.[[GetOwnProperty]](nextKey). | |
| 2116 PropertyDescriptor desc; | |
| 2117 Maybe<bool> found = | |
| 2118 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc); | |
| 2119 if (found.IsNothing()) return Nothing<bool>(); | |
| 2120 // 4a ii. If desc is not undefined and desc.[[Enumerable]] is true, then | |
| 2121 if (found.FromJust() && desc.enumerable()) { | |
| 2122 // 4a ii 1. Let propValue be ? Get(from, nextKey). | |
| 2123 Handle<Object> prop_value; | |
| 2124 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 2125 isolate, prop_value, | |
| 2126 Runtime::GetObjectProperty(isolate, from, next_key), Nothing<bool>()); | |
| 2127 | |
| 2128 if (use_set) { | |
| 2129 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true). | |
| 2130 Handle<Object> status; | |
| 2131 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 2132 isolate, status, Runtime::SetObjectProperty( | |
| 2133 isolate, target, next_key, prop_value, STRICT), | |
| 2134 Nothing<bool>()); | |
| 2135 } else { | |
| 2136 // 4a ii 2. Perform ? CreateDataProperty(target, nextKey, propValue). | |
| 2137 bool success; | |
| 2138 LookupIterator it = LookupIterator::PropertyOrElement( | |
| 2139 isolate, target, next_key, &success, LookupIterator::OWN); | |
| 2140 if (!success) return Nothing<bool>(); | |
|
adamk
2016/12/29 18:32:46
How could this fail?
gsathya
2017/01/05 22:18:36
Changed to CHECK.
| |
| 2141 MAYBE_RETURN(JSReceiver::CreateDataProperty(&it, prop_value, | |
|
adamk
2016/12/29 18:32:46
Or this?
I think it's quite likely you could use
gsathya
2017/01/05 22:18:36
Changed to CHECK.
| |
| 2142 Object::THROW_ON_ERROR), | |
| 2143 Nothing<bool>()); | |
| 2144 } | |
| 2145 } | |
| 2146 } | |
| 2147 | |
| 2148 return Just(true); | |
| 2149 } | |
| 2150 | |
| 2002 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) { | 2151 Map* Object::GetPrototypeChainRootMap(Isolate* isolate) { |
| 2003 DisallowHeapAllocation no_alloc; | 2152 DisallowHeapAllocation no_alloc; |
| 2004 if (IsSmi()) { | 2153 if (IsSmi()) { |
| 2005 Context* native_context = isolate->context()->native_context(); | 2154 Context* native_context = isolate->context()->native_context(); |
| 2006 return native_context->number_function()->initial_map(); | 2155 return native_context->number_function()->initial_map(); |
| 2007 } | 2156 } |
| 2008 | 2157 |
| 2009 // The object is either a number, a string, a symbol, a boolean, a SIMD value, | 2158 // The object is either a number, a string, a symbol, a boolean, a SIMD value, |
| 2010 // a real JS object, or a Harmony proxy. | 2159 // a real JS object, or a Harmony proxy. |
| 2011 HeapObject* heap_object = HeapObject::cast(this); | 2160 HeapObject* heap_object = HeapObject::cast(this); |
| (...skipping 18350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 20362 // depend on this. | 20511 // depend on this. |
| 20363 return DICTIONARY_ELEMENTS; | 20512 return DICTIONARY_ELEMENTS; |
| 20364 } | 20513 } |
| 20365 DCHECK_LE(kind, LAST_ELEMENTS_KIND); | 20514 DCHECK_LE(kind, LAST_ELEMENTS_KIND); |
| 20366 return kind; | 20515 return kind; |
| 20367 } | 20516 } |
| 20368 } | 20517 } |
| 20369 | 20518 |
| 20370 } // namespace internal | 20519 } // namespace internal |
| 20371 } // namespace v8 | 20520 } // namespace v8 |
| OLD | NEW |