OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
9 #include "src/property-descriptor.h" | 9 #include "src/property-descriptor.h" |
10 | 10 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 assembler.Return(assembler.BooleanConstant(true)); | 59 assembler.Return(assembler.BooleanConstant(true)); |
60 | 60 |
61 assembler.Bind(&return_false); | 61 assembler.Bind(&return_false); |
62 assembler.Return(assembler.BooleanConstant(false)); | 62 assembler.Return(assembler.BooleanConstant(false)); |
63 | 63 |
64 assembler.Bind(&call_runtime); | 64 assembler.Bind(&call_runtime); |
65 assembler.Return(assembler.CallRuntime(Runtime::kObjectHasOwnProperty, | 65 assembler.Return(assembler.CallRuntime(Runtime::kObjectHasOwnProperty, |
66 context, object, key)); | 66 context, object, key)); |
67 } | 67 } |
68 | 68 |
69 namespace { | |
70 | |
71 MUST_USE_RESULT Maybe<bool> FastAssign(Handle<JSReceiver> to, | |
72 Handle<Object> next_source) { | |
73 // Non-empty strings are the only non-JSReceivers that need to be handled | |
74 // explicitly by Object.assign. | |
75 if (!next_source->IsJSReceiver()) { | |
76 return Just(!next_source->IsString() || | |
77 String::cast(*next_source)->length() == 0); | |
78 } | |
79 | |
80 // If the target is deprecated, the object will be updated on first store. If | |
81 // the source for that store equals the target, this will invalidate the | |
82 // cached representation of the source. Preventively upgrade the target. | |
83 // Do this on each iteration since any property load could cause deprecation. | |
84 if (to->map()->is_deprecated()) { | |
85 JSObject::MigrateInstance(Handle<JSObject>::cast(to)); | |
86 } | |
87 | |
88 Isolate* isolate = to->GetIsolate(); | |
89 Handle<Map> map(JSReceiver::cast(*next_source)->map(), isolate); | |
90 | |
91 if (!map->IsJSObjectMap()) return Just(false); | |
92 if (!map->OnlyHasSimpleProperties()) return Just(false); | |
93 | |
94 Handle<JSObject> from = Handle<JSObject>::cast(next_source); | |
95 if (from->elements() != isolate->heap()->empty_fixed_array()) { | |
96 return Just(false); | |
97 } | |
98 | |
99 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); | |
100 int length = map->NumberOfOwnDescriptors(); | |
101 | |
102 bool stable = true; | |
103 | |
104 for (int i = 0; i < length; i++) { | |
105 Handle<Name> next_key(descriptors->GetKey(i), isolate); | |
106 Handle<Object> prop_value; | |
107 // Directly decode from the descriptor array if |from| did not change shape. | |
108 if (stable) { | |
109 PropertyDetails details = descriptors->GetDetails(i); | |
110 if (!details.IsEnumerable()) continue; | |
111 if (details.kind() == kData) { | |
112 if (details.location() == kDescriptor) { | |
113 prop_value = handle(descriptors->GetValue(i), isolate); | |
114 } else { | |
115 Representation representation = details.representation(); | |
116 FieldIndex index = FieldIndex::ForDescriptor(*map, i); | |
117 prop_value = JSObject::FastPropertyAt(from, representation, index); | |
118 } | |
119 } else { | |
120 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
121 isolate, prop_value, JSReceiver::GetProperty(from, next_key), | |
122 Nothing<bool>()); | |
123 stable = from->map() == *map; | |
124 } | |
125 } else { | |
126 // If the map did change, do a slower lookup. We are still guaranteed that | |
127 // the object has a simple shape, and that the key is a name. | |
128 LookupIterator it(from, next_key, from, | |
129 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
130 if (!it.IsFound()) continue; | |
131 DCHECK(it.state() == LookupIterator::DATA || | |
132 it.state() == LookupIterator::ACCESSOR); | |
133 if (!it.IsEnumerable()) continue; | |
134 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
135 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); | |
136 } | |
137 LookupIterator it(to, next_key, to); | |
138 bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA; | |
139 Maybe<bool> result = Object::SetProperty( | |
140 &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED); | |
141 if (result.IsNothing()) return result; | |
142 if (stable && call_to_js) stable = from->map() == *map; | |
143 } | |
144 | |
145 return Just(true); | |
146 } | |
147 | |
148 } // namespace | |
149 | |
150 // ES6 19.1.2.1 Object.assign | 69 // ES6 19.1.2.1 Object.assign |
151 BUILTIN(ObjectAssign) { | 70 BUILTIN(ObjectAssign) { |
152 HandleScope scope(isolate); | 71 HandleScope scope(isolate); |
153 Handle<Object> target = args.atOrUndefined(isolate, 1); | 72 Handle<Object> target = args.atOrUndefined(isolate, 1); |
154 | 73 |
155 // 1. Let to be ? ToObject(target). | 74 // 1. Let to be ? ToObject(target). |
156 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target, | 75 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target, |
157 Object::ToObject(isolate, target)); | 76 Object::ToObject(isolate, target)); |
158 Handle<JSReceiver> to = Handle<JSReceiver>::cast(target); | 77 Handle<JSReceiver> to = Handle<JSReceiver>::cast(target); |
159 // 2. If only one argument was passed, return to. | 78 // 2. If only one argument was passed, return to. |
160 if (args.length() == 2) return *to; | 79 if (args.length() == 2) return *to; |
161 // 3. Let sources be the List of argument values starting with the | 80 // 3. Let sources be the List of argument values starting with the |
162 // second argument. | 81 // second argument. |
163 // 4. For each element nextSource of sources, in ascending index order, | 82 // 4. For each element nextSource of sources, in ascending index order, |
164 for (int i = 2; i < args.length(); ++i) { | 83 for (int i = 2; i < args.length(); ++i) { |
165 Handle<Object> next_source = args.at(i); | 84 Handle<Object> next_source = args.at(i); |
166 Maybe<bool> fast_assign = FastAssign(to, next_source); | 85 MAYBE_RETURN( |
167 if (fast_assign.IsNothing()) return isolate->heap()->exception(); | 86 JSReceiver::SetOrCopyDataProperties(isolate, to, next_source, true), |
168 if (fast_assign.FromJust()) continue; | 87 isolate->heap()->exception()); |
169 // 4a. If nextSource is undefined or null, let keys be an empty List. | |
170 // 4b. Else, | |
171 // 4b i. Let from be ToObject(nextSource). | |
172 // Only non-empty strings and JSReceivers have enumerable properties. | |
173 Handle<JSReceiver> from = | |
174 Object::ToObject(isolate, next_source).ToHandleChecked(); | |
175 // 4b ii. Let keys be ? from.[[OwnPropertyKeys]](). | |
176 Handle<FixedArray> keys; | |
177 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
178 isolate, keys, KeyAccumulator::GetKeys( | |
179 from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, | |
180 GetKeysConversion::kKeepNumbers)); | |
181 // 4c. Repeat for each element nextKey of keys in List order, | |
182 for (int j = 0; j < keys->length(); ++j) { | |
183 Handle<Object> next_key(keys->get(j), isolate); | |
184 // 4c i. Let desc be ? from.[[GetOwnProperty]](nextKey). | |
185 PropertyDescriptor desc; | |
186 Maybe<bool> found = | |
187 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc); | |
188 if (found.IsNothing()) return isolate->heap()->exception(); | |
189 // 4c ii. If desc is not undefined and desc.[[Enumerable]] is true, then | |
190 if (found.FromJust() && desc.enumerable()) { | |
191 // 4c ii 1. Let propValue be ? Get(from, nextKey). | |
192 Handle<Object> prop_value; | |
193 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
194 isolate, prop_value, | |
195 Runtime::GetObjectProperty(isolate, from, next_key)); | |
196 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true). | |
197 Handle<Object> status; | |
198 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
199 isolate, status, Runtime::SetObjectProperty(isolate, to, next_key, | |
200 prop_value, STRICT)); | |
201 } | |
202 } | |
203 } | 88 } |
204 // 5. Return to. | 89 // 5. Return to. |
205 return *to; | 90 return *to; |
206 } | 91 } |
207 | 92 |
208 // ES6 section 19.1.3.4 Object.prototype.propertyIsEnumerable ( V ) | 93 // ES6 section 19.1.3.4 Object.prototype.propertyIsEnumerable ( V ) |
209 BUILTIN(ObjectPrototypePropertyIsEnumerable) { | 94 BUILTIN(ObjectPrototypePropertyIsEnumerable) { |
210 HandleScope scope(isolate); | 95 HandleScope scope(isolate); |
211 Handle<JSReceiver> object; | 96 Handle<JSReceiver> object; |
212 Handle<Name> name; | 97 Handle<Name> name; |
(...skipping 887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1100 CodeStubAssembler assembler(state); | 985 CodeStubAssembler assembler(state); |
1101 | 986 |
1102 Node* object = assembler.Parameter(Descriptor::kObject); | 987 Node* object = assembler.Parameter(Descriptor::kObject); |
1103 Node* context = assembler.Parameter(Descriptor::kContext); | 988 Node* context = assembler.Parameter(Descriptor::kContext); |
1104 | 989 |
1105 assembler.Return(assembler.GetSuperConstructor(object, context)); | 990 assembler.Return(assembler.GetSuperConstructor(object, context)); |
1106 } | 991 } |
1107 | 992 |
1108 } // namespace internal | 993 } // namespace internal |
1109 } // namespace v8 | 994 } // namespace v8 |
OLD | NEW |