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
3 // found in the LICENSE file.
4
5 #include "src/builtins/builtins-utils-inl.h"
6 #include "src/builtins/builtins.h"
7 #include "src/codegen/code-factory.h"
8 #include "src/common/message-template.h"
9 #include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
10 #include "src/logging/counters.h"
11 #include "src/objects/keys.h"
12 #include "src/objects/lookup.h"
13 #include "src/objects/objects-inl.h"
14 #include "src/objects/property-descriptor.h"
15
16 namespace v8 {
17 namespace internal {
18
19 // -----------------------------------------------------------------------------
20 // ES6 section 19.1 Object Objects
21
22 // ES6 section 19.1.3.4 Object.prototype.propertyIsEnumerable ( V )
BUILTIN(ObjectPrototypePropertyIsEnumerable)23 BUILTIN(ObjectPrototypePropertyIsEnumerable) {
24 HandleScope scope(isolate);
25 Handle<JSReceiver> object;
26 Handle<Name> name;
27 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
28 isolate, name, Object::ToName(isolate, args.atOrUndefined(isolate, 1)));
29 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
30 isolate, object, Object::ToObject(isolate, args.receiver()));
31 Maybe<PropertyAttributes> maybe =
32 JSReceiver::GetOwnPropertyAttributes(object, name);
33 if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
34 if (maybe.FromJust() == ABSENT) return ReadOnlyRoots(isolate).false_value();
35 return isolate->heap()->ToBoolean((maybe.FromJust() & DONT_ENUM) == 0);
36 }
37
38 // ES6 section 19.1.2.3 Object.defineProperties
BUILTIN(ObjectDefineProperties)39 BUILTIN(ObjectDefineProperties) {
40 HandleScope scope(isolate);
41 DCHECK_LE(3, args.length());
42 Handle<Object> target = args.at(1);
43 Handle<Object> properties = args.at(2);
44
45 RETURN_RESULT_OR_FAILURE(
46 isolate, JSReceiver::DefineProperties(isolate, target, properties));
47 }
48
49 // ES6 section 19.1.2.4 Object.defineProperty
BUILTIN(ObjectDefineProperty)50 BUILTIN(ObjectDefineProperty) {
51 HandleScope scope(isolate);
52 DCHECK_LE(4, args.length());
53 Handle<Object> target = args.at(1);
54 Handle<Object> key = args.at(2);
55 Handle<Object> attributes = args.at(3);
56
57 return JSReceiver::DefineProperty(isolate, target, key, attributes);
58 }
59
60 namespace {
61
62 template <AccessorComponent which_accessor>
ObjectDefineAccessor(Isolate * isolate,Handle<Object> object,Handle<Object> name,Handle<Object> accessor)63 Object ObjectDefineAccessor(Isolate* isolate, Handle<Object> object,
64 Handle<Object> name, Handle<Object> accessor) {
65 // 1. Let O be ? ToObject(this value).
66 Handle<JSReceiver> receiver;
67 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
68 Object::ToObject(isolate, object));
69 // 2. If IsCallable(getter) is false, throw a TypeError exception.
70 if (!accessor->IsCallable()) {
71 MessageTemplate message =
72 which_accessor == ACCESSOR_GETTER
73 ? MessageTemplate::kObjectGetterExpectingFunction
74 : MessageTemplate::kObjectSetterExpectingFunction;
75 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(message));
76 }
77 // 3. Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true,
78 // [[Configurable]]: true}.
79 PropertyDescriptor desc;
80 if (which_accessor == ACCESSOR_GETTER) {
81 desc.set_get(accessor);
82 } else {
83 DCHECK(which_accessor == ACCESSOR_SETTER);
84 desc.set_set(accessor);
85 }
86 desc.set_enumerable(true);
87 desc.set_configurable(true);
88 // 4. Let key be ? ToPropertyKey(P).
89 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
90 Object::ToPropertyKey(isolate, name));
91 // 5. Perform ? DefinePropertyOrThrow(O, key, desc).
92 // To preserve legacy behavior, we ignore errors silently rather than
93 // throwing an exception.
94 Maybe<bool> success = JSReceiver::DefineOwnProperty(
95 isolate, receiver, name, &desc, Just(kThrowOnError));
96 MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
97 if (!success.FromJust()) {
98 isolate->CountUsage(v8::Isolate::kDefineGetterOrSetterWouldThrow);
99 }
100 // 6. Return undefined.
101 return ReadOnlyRoots(isolate).undefined_value();
102 }
103
ObjectLookupAccessor(Isolate * isolate,Handle<Object> object,Handle<Object> key,AccessorComponent component)104 Object ObjectLookupAccessor(Isolate* isolate, Handle<Object> object,
105 Handle<Object> key, AccessorComponent component) {
106 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, object,
107 Object::ToObject(isolate, object));
108 // TODO(jkummerow/verwaest): PropertyKey(..., bool*) performs a
109 // functionally equivalent conversion, but handles element indices slightly
110 // differently. Does one of the approaches have a performance advantage?
111 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key,
112 Object::ToPropertyKey(isolate, key));
113 PropertyKey lookup_key(isolate, key);
114 LookupIterator it(isolate, object, lookup_key,
115 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
116
117 for (; it.IsFound(); it.Next()) {
118 switch (it.state()) {
119 case LookupIterator::INTERCEPTOR:
120 case LookupIterator::NOT_FOUND:
121 case LookupIterator::TRANSITION:
122 UNREACHABLE();
123
124 case LookupIterator::ACCESS_CHECK:
125 if (it.HasAccess()) continue;
126 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>());
127 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
128 return ReadOnlyRoots(isolate).undefined_value();
129
130 case LookupIterator::JSPROXY: {
131 PropertyDescriptor desc;
132 Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
133 isolate, it.GetHolder<JSProxy>(), it.GetName(), &desc);
134 MAYBE_RETURN(found, ReadOnlyRoots(isolate).exception());
135 if (found.FromJust()) {
136 if (component == ACCESSOR_GETTER && desc.has_get()) {
137 return *desc.get();
138 }
139 if (component == ACCESSOR_SETTER && desc.has_set()) {
140 return *desc.set();
141 }
142 return ReadOnlyRoots(isolate).undefined_value();
143 }
144 Handle<Object> prototype;
145 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
146 isolate, prototype, JSProxy::GetPrototype(it.GetHolder<JSProxy>()));
147 if (prototype->IsNull(isolate)) {
148 return ReadOnlyRoots(isolate).undefined_value();
149 }
150 return ObjectLookupAccessor(isolate, prototype, key, component);
151 }
152
153 case LookupIterator::INTEGER_INDEXED_EXOTIC:
154 case LookupIterator::DATA:
155 return ReadOnlyRoots(isolate).undefined_value();
156
157 case LookupIterator::ACCESSOR: {
158 Handle<Object> maybe_pair = it.GetAccessors();
159 if (maybe_pair->IsAccessorPair()) {
160 Handle<NativeContext> native_context = it.GetHolder<JSReceiver>()
161 ->GetCreationContext()
162 .ToHandleChecked();
163 return *AccessorPair::GetComponent(
164 isolate, native_context, Handle<AccessorPair>::cast(maybe_pair),
165 component);
166 }
167 }
168 }
169 }
170
171 return ReadOnlyRoots(isolate).undefined_value();
172 }
173
174 } // namespace
175
176 // ES6 B.2.2.2 a.k.a.
177 // https://tc39.github.io/ecma262/#sec-object.prototype.__defineGetter__
BUILTIN(ObjectDefineGetter)178 BUILTIN(ObjectDefineGetter) {
179 HandleScope scope(isolate);
180 Handle<Object> object = args.at(0); // Receiver.
181 Handle<Object> name = args.at(1);
182 Handle<Object> getter = args.at(2);
183 return ObjectDefineAccessor<ACCESSOR_GETTER>(isolate, object, name, getter);
184 }
185
186 // ES6 B.2.2.3 a.k.a.
187 // https://tc39.github.io/ecma262/#sec-object.prototype.__defineSetter__
BUILTIN(ObjectDefineSetter)188 BUILTIN(ObjectDefineSetter) {
189 HandleScope scope(isolate);
190 Handle<Object> object = args.at(0); // Receiver.
191 Handle<Object> name = args.at(1);
192 Handle<Object> setter = args.at(2);
193 return ObjectDefineAccessor<ACCESSOR_SETTER>(isolate, object, name, setter);
194 }
195
196 // ES6 B.2.2.4 a.k.a.
197 // https://tc39.github.io/ecma262/#sec-object.prototype.__lookupGetter__
BUILTIN(ObjectLookupGetter)198 BUILTIN(ObjectLookupGetter) {
199 HandleScope scope(isolate);
200 Handle<Object> object = args.at(0);
201 Handle<Object> name = args.at(1);
202 return ObjectLookupAccessor(isolate, object, name, ACCESSOR_GETTER);
203 }
204
205 // ES6 B.2.2.5 a.k.a.
206 // https://tc39.github.io/ecma262/#sec-object.prototype.__lookupSetter__
BUILTIN(ObjectLookupSetter)207 BUILTIN(ObjectLookupSetter) {
208 HandleScope scope(isolate);
209 Handle<Object> object = args.at(0);
210 Handle<Object> name = args.at(1);
211 return ObjectLookupAccessor(isolate, object, name, ACCESSOR_SETTER);
212 }
213
214 // ES6 section 19.1.2.5 Object.freeze ( O )
BUILTIN(ObjectFreeze)215 BUILTIN(ObjectFreeze) {
216 HandleScope scope(isolate);
217 Handle<Object> object = args.atOrUndefined(isolate, 1);
218 if (object->IsJSReceiver()) {
219 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object),
220 FROZEN, kThrowOnError),
221 ReadOnlyRoots(isolate).exception());
222 }
223 return *object;
224 }
225
226 // ES6 section B.2.2.1.1 get Object.prototype.__proto__
BUILTIN(ObjectPrototypeGetProto)227 BUILTIN(ObjectPrototypeGetProto) {
228 HandleScope scope(isolate);
229 // 1. Let O be ? ToObject(this value).
230 Handle<JSReceiver> receiver;
231 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
232 isolate, receiver, Object::ToObject(isolate, args.receiver()));
233
234 // 2. Return ? O.[[GetPrototypeOf]]().
235 RETURN_RESULT_OR_FAILURE(isolate,
236 JSReceiver::GetPrototype(isolate, receiver));
237 }
238
239 // ES6 section B.2.2.1.2 set Object.prototype.__proto__
BUILTIN(ObjectPrototypeSetProto)240 BUILTIN(ObjectPrototypeSetProto) {
241 HandleScope scope(isolate);
242 // 1. Let O be ? RequireObjectCoercible(this value).
243 Handle<Object> object = args.receiver();
244 if (object->IsNullOrUndefined(isolate)) {
245 THROW_NEW_ERROR_RETURN_FAILURE(
246 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
247 isolate->factory()->NewStringFromAsciiChecked(
248 "set Object.prototype.__proto__")));
249 }
250
251 // 2. If Type(proto) is neither Object nor Null, return undefined.
252 Handle<Object> proto = args.at(1);
253 if (!proto->IsNull(isolate) && !proto->IsJSReceiver()) {
254 return ReadOnlyRoots(isolate).undefined_value();
255 }
256
257 // 3. If Type(O) is not Object, return undefined.
258 if (!object->IsJSReceiver()) return ReadOnlyRoots(isolate).undefined_value();
259 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
260
261 // 4. Let status be ? O.[[SetPrototypeOf]](proto).
262 // 5. If status is false, throw a TypeError exception.
263 MAYBE_RETURN(
264 JSReceiver::SetPrototype(isolate, receiver, proto, true, kThrowOnError),
265 ReadOnlyRoots(isolate).exception());
266
267 // Return undefined.
268 return ReadOnlyRoots(isolate).undefined_value();
269 }
270
271 namespace {
272
GetOwnPropertyKeys(Isolate * isolate,BuiltinArguments args,PropertyFilter filter)273 Object GetOwnPropertyKeys(Isolate* isolate, BuiltinArguments args,
274 PropertyFilter filter) {
275 HandleScope scope(isolate);
276 Handle<Object> object = args.atOrUndefined(isolate, 1);
277 Handle<JSReceiver> receiver;
278 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
279 Object::ToObject(isolate, object));
280 Handle<FixedArray> keys;
281 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
282 isolate, keys,
283 KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter,
284 GetKeysConversion::kConvertToString));
285 return *isolate->factory()->NewJSArrayWithElements(keys);
286 }
287
288 } // namespace
289
290 // ES6 section 19.1.2.8 Object.getOwnPropertySymbols ( O )
BUILTIN(ObjectGetOwnPropertySymbols)291 BUILTIN(ObjectGetOwnPropertySymbols) {
292 return GetOwnPropertyKeys(isolate, args, SKIP_STRINGS);
293 }
294
295 // ES6 section 19.1.2.12 Object.isFrozen ( O )
BUILTIN(ObjectIsFrozen)296 BUILTIN(ObjectIsFrozen) {
297 HandleScope scope(isolate);
298 Handle<Object> object = args.atOrUndefined(isolate, 1);
299 Maybe<bool> result = object->IsJSReceiver()
300 ? JSReceiver::TestIntegrityLevel(
301 Handle<JSReceiver>::cast(object), FROZEN)
302 : Just(true);
303 MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
304 return isolate->heap()->ToBoolean(result.FromJust());
305 }
306
307 // ES6 section 19.1.2.13 Object.isSealed ( O )
BUILTIN(ObjectIsSealed)308 BUILTIN(ObjectIsSealed) {
309 HandleScope scope(isolate);
310 Handle<Object> object = args.atOrUndefined(isolate, 1);
311 Maybe<bool> result = object->IsJSReceiver()
312 ? JSReceiver::TestIntegrityLevel(
313 Handle<JSReceiver>::cast(object), SEALED)
314 : Just(true);
315 MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
316 return isolate->heap()->ToBoolean(result.FromJust());
317 }
318
BUILTIN(ObjectGetOwnPropertyDescriptors)319 BUILTIN(ObjectGetOwnPropertyDescriptors) {
320 HandleScope scope(isolate);
321 Handle<Object> object = args.atOrUndefined(isolate, 1);
322
323 Handle<JSReceiver> receiver;
324 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
325 Object::ToObject(isolate, object));
326
327 Handle<FixedArray> keys;
328 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
329 isolate, keys, KeyAccumulator::GetKeys(
330 receiver, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
331 GetKeysConversion::kConvertToString));
332
333 Handle<JSObject> descriptors =
334 isolate->factory()->NewJSObject(isolate->object_function());
335
336 for (int i = 0; i < keys->length(); ++i) {
337 Handle<Name> key = Handle<Name>::cast(FixedArray::get(*keys, i, isolate));
338 PropertyDescriptor descriptor;
339 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
340 isolate, receiver, key, &descriptor);
341 MAYBE_RETURN(did_get_descriptor, ReadOnlyRoots(isolate).exception());
342
343 if (!did_get_descriptor.FromJust()) continue;
344 Handle<Object> from_descriptor = descriptor.ToObject(isolate);
345
346 Maybe<bool> success = JSReceiver::CreateDataProperty(
347 isolate, descriptors, key, from_descriptor, Just(kDontThrow));
348 CHECK(success.FromJust());
349 }
350
351 return *descriptors;
352 }
353
354 // ES6 section 19.1.2.17 Object.seal ( O )
BUILTIN(ObjectSeal)355 BUILTIN(ObjectSeal) {
356 HandleScope scope(isolate);
357 Handle<Object> object = args.atOrUndefined(isolate, 1);
358 if (object->IsJSReceiver()) {
359 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object),
360 SEALED, kThrowOnError),
361 ReadOnlyRoots(isolate).exception());
362 }
363 return *object;
364 }
365
366 } // namespace internal
367 } // namespace v8
368