blob: 16f81dc3d0f739b36f14290e1fedc30af9d46219 [file] [log] [blame]
Kaido Kertf309f9a2021-04-30 12:09:15 -07001// 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
16namespace v8 {
17namespace internal {
18
19// -----------------------------------------------------------------------------
20// ES6 section 19.1 Object Objects
21
22// ES6 section 19.1.3.4 Object.prototype.propertyIsEnumerable ( V )
23BUILTIN(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
39BUILTIN(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
50BUILTIN(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
60namespace {
61
62template <AccessorComponent which_accessor>
63Object 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
104Object 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): LookupIterator::Key(..., 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 LookupIterator::Key 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 =
161 it.GetHolder<JSReceiver>()->GetCreationContext();
162 return *AccessorPair::GetComponent(
163 isolate, native_context, Handle<AccessorPair>::cast(maybe_pair),
164 component);
165 }
166 }
167 }
168 }
169
170 return ReadOnlyRoots(isolate).undefined_value();
171}
172
173} // namespace
174
175// ES6 B.2.2.2 a.k.a.
176// https://tc39.github.io/ecma262/#sec-object.prototype.__defineGetter__
177BUILTIN(ObjectDefineGetter) {
178 HandleScope scope(isolate);
179 Handle<Object> object = args.at(0); // Receiver.
180 Handle<Object> name = args.at(1);
181 Handle<Object> getter = args.at(2);
182 return ObjectDefineAccessor<ACCESSOR_GETTER>(isolate, object, name, getter);
183}
184
185// ES6 B.2.2.3 a.k.a.
186// https://tc39.github.io/ecma262/#sec-object.prototype.__defineSetter__
187BUILTIN(ObjectDefineSetter) {
188 HandleScope scope(isolate);
189 Handle<Object> object = args.at(0); // Receiver.
190 Handle<Object> name = args.at(1);
191 Handle<Object> setter = args.at(2);
192 return ObjectDefineAccessor<ACCESSOR_SETTER>(isolate, object, name, setter);
193}
194
195// ES6 B.2.2.4 a.k.a.
196// https://tc39.github.io/ecma262/#sec-object.prototype.__lookupGetter__
197BUILTIN(ObjectLookupGetter) {
198 HandleScope scope(isolate);
199 Handle<Object> object = args.at(0);
200 Handle<Object> name = args.at(1);
201 return ObjectLookupAccessor(isolate, object, name, ACCESSOR_GETTER);
202}
203
204// ES6 B.2.2.5 a.k.a.
205// https://tc39.github.io/ecma262/#sec-object.prototype.__lookupSetter__
206BUILTIN(ObjectLookupSetter) {
207 HandleScope scope(isolate);
208 Handle<Object> object = args.at(0);
209 Handle<Object> name = args.at(1);
210 return ObjectLookupAccessor(isolate, object, name, ACCESSOR_SETTER);
211}
212
213// ES6 section 19.1.2.5 Object.freeze ( O )
214BUILTIN(ObjectFreeze) {
215 HandleScope scope(isolate);
216 Handle<Object> object = args.atOrUndefined(isolate, 1);
217 if (object->IsJSReceiver()) {
218 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object),
219 FROZEN, kThrowOnError),
220 ReadOnlyRoots(isolate).exception());
221 }
222 return *object;
223}
224
225// ES6 section B.2.2.1.1 get Object.prototype.__proto__
226BUILTIN(ObjectPrototypeGetProto) {
227 HandleScope scope(isolate);
228 // 1. Let O be ? ToObject(this value).
229 Handle<JSReceiver> receiver;
230 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
231 isolate, receiver, Object::ToObject(isolate, args.receiver()));
232
233 // 2. Return ? O.[[GetPrototypeOf]]().
234 RETURN_RESULT_OR_FAILURE(isolate,
235 JSReceiver::GetPrototype(isolate, receiver));
236}
237
238// ES6 section B.2.2.1.2 set Object.prototype.__proto__
239BUILTIN(ObjectPrototypeSetProto) {
240 HandleScope scope(isolate);
241 // 1. Let O be ? RequireObjectCoercible(this value).
242 Handle<Object> object = args.receiver();
243 if (object->IsNullOrUndefined(isolate)) {
244 THROW_NEW_ERROR_RETURN_FAILURE(
245 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
246 isolate->factory()->NewStringFromAsciiChecked(
247 "set Object.prototype.__proto__")));
248 }
249
250 // 2. If Type(proto) is neither Object nor Null, return undefined.
251 Handle<Object> proto = args.at(1);
252 if (!proto->IsNull(isolate) && !proto->IsJSReceiver()) {
253 return ReadOnlyRoots(isolate).undefined_value();
254 }
255
256 // 3. If Type(O) is not Object, return undefined.
257 if (!object->IsJSReceiver()) return ReadOnlyRoots(isolate).undefined_value();
258 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
259
260 // 4. Let status be ? O.[[SetPrototypeOf]](proto).
261 // 5. If status is false, throw a TypeError exception.
262 MAYBE_RETURN(JSReceiver::SetPrototype(receiver, proto, true, kThrowOnError),
263 ReadOnlyRoots(isolate).exception());
264
265 // Return undefined.
266 return ReadOnlyRoots(isolate).undefined_value();
267}
268
269namespace {
270
271Object GetOwnPropertyKeys(Isolate* isolate, BuiltinArguments args,
272 PropertyFilter filter) {
273 HandleScope scope(isolate);
274 Handle<Object> object = args.atOrUndefined(isolate, 1);
275 Handle<JSReceiver> receiver;
276 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
277 Object::ToObject(isolate, object));
278 Handle<FixedArray> keys;
279 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
280 isolate, keys,
281 KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter,
282 GetKeysConversion::kConvertToString));
283 return *isolate->factory()->NewJSArrayWithElements(keys);
284}
285
286} // namespace
287
288// ES6 section 19.1.2.8 Object.getOwnPropertySymbols ( O )
289BUILTIN(ObjectGetOwnPropertySymbols) {
290 return GetOwnPropertyKeys(isolate, args, SKIP_STRINGS);
291}
292
293// ES6 section 19.1.2.12 Object.isFrozen ( O )
294BUILTIN(ObjectIsFrozen) {
295 HandleScope scope(isolate);
296 Handle<Object> object = args.atOrUndefined(isolate, 1);
297 Maybe<bool> result = object->IsJSReceiver()
298 ? JSReceiver::TestIntegrityLevel(
299 Handle<JSReceiver>::cast(object), FROZEN)
300 : Just(true);
301 MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
302 return isolate->heap()->ToBoolean(result.FromJust());
303}
304
305// ES6 section 19.1.2.13 Object.isSealed ( O )
306BUILTIN(ObjectIsSealed) {
307 HandleScope scope(isolate);
308 Handle<Object> object = args.atOrUndefined(isolate, 1);
309 Maybe<bool> result = object->IsJSReceiver()
310 ? JSReceiver::TestIntegrityLevel(
311 Handle<JSReceiver>::cast(object), SEALED)
312 : Just(true);
313 MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
314 return isolate->heap()->ToBoolean(result.FromJust());
315}
316
317BUILTIN(ObjectGetOwnPropertyDescriptors) {
318 HandleScope scope(isolate);
319 Handle<Object> object = args.atOrUndefined(isolate, 1);
320
321 Handle<JSReceiver> receiver;
322 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
323 Object::ToObject(isolate, object));
324
325 Handle<FixedArray> keys;
326 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
327 isolate, keys, KeyAccumulator::GetKeys(
328 receiver, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
329 GetKeysConversion::kConvertToString));
330
331 Handle<JSObject> descriptors =
332 isolate->factory()->NewJSObject(isolate->object_function());
333
334 for (int i = 0; i < keys->length(); ++i) {
335 Handle<Name> key = Handle<Name>::cast(FixedArray::get(*keys, i, isolate));
336 PropertyDescriptor descriptor;
337 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor(
338 isolate, receiver, key, &descriptor);
339 MAYBE_RETURN(did_get_descriptor, ReadOnlyRoots(isolate).exception());
340
341 if (!did_get_descriptor.FromJust()) continue;
342 Handle<Object> from_descriptor = descriptor.ToObject(isolate);
343
344 Maybe<bool> success = JSReceiver::CreateDataProperty(
345 isolate, descriptors, key, from_descriptor, Just(kDontThrow));
346 CHECK(success.FromJust());
347 }
348
349 return *descriptors;
350}
351
352// ES6 section 19.1.2.17 Object.seal ( O )
353BUILTIN(ObjectSeal) {
354 HandleScope scope(isolate);
355 Handle<Object> object = args.atOrUndefined(isolate, 1);
356 if (object->IsJSReceiver()) {
357 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object),
358 SEALED, kThrowOnError),
359 ReadOnlyRoots(isolate).exception());
360 }
361 return *object;
362}
363
364} // namespace internal
365} // namespace v8