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.h"
6 #include "src/builtins/builtins-utils.h"
7 
8 #include "src/property-descriptor.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 // -----------------------------------------------------------------------------
14 // ES6 section 26.1 The Reflect Object
15 
16 // ES6 section 26.1.3 Reflect.defineProperty
BUILTIN(ReflectDefineProperty)17 BUILTIN(ReflectDefineProperty) {
18   HandleScope scope(isolate);
19   DCHECK_EQ(4, args.length());
20   Handle<Object> target = args.at<Object>(1);
21   Handle<Object> key = args.at<Object>(2);
22   Handle<Object> attributes = args.at<Object>(3);
23 
24   if (!target->IsJSReceiver()) {
25     THROW_NEW_ERROR_RETURN_FAILURE(
26         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
27                               isolate->factory()->NewStringFromAsciiChecked(
28                                   "Reflect.defineProperty")));
29   }
30 
31   Handle<Name> name;
32   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
33                                      Object::ToName(isolate, key));
34 
35   PropertyDescriptor desc;
36   if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
37     return isolate->heap()->exception();
38   }
39 
40   Maybe<bool> result =
41       JSReceiver::DefineOwnProperty(isolate, Handle<JSReceiver>::cast(target),
42                                     name, &desc, Object::DONT_THROW);
43   MAYBE_RETURN(result, isolate->heap()->exception());
44   return *isolate->factory()->ToBoolean(result.FromJust());
45 }
46 
47 // ES6 section 26.1.4 Reflect.deleteProperty
BUILTIN(ReflectDeleteProperty)48 BUILTIN(ReflectDeleteProperty) {
49   HandleScope scope(isolate);
50   DCHECK_EQ(3, args.length());
51   Handle<Object> target = args.at<Object>(1);
52   Handle<Object> key = args.at<Object>(2);
53 
54   if (!target->IsJSReceiver()) {
55     THROW_NEW_ERROR_RETURN_FAILURE(
56         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
57                               isolate->factory()->NewStringFromAsciiChecked(
58                                   "Reflect.deleteProperty")));
59   }
60 
61   Handle<Name> name;
62   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
63                                      Object::ToName(isolate, key));
64 
65   Maybe<bool> result = JSReceiver::DeletePropertyOrElement(
66       Handle<JSReceiver>::cast(target), name, SLOPPY);
67   MAYBE_RETURN(result, isolate->heap()->exception());
68   return *isolate->factory()->ToBoolean(result.FromJust());
69 }
70 
71 // ES6 section 26.1.6 Reflect.get
BUILTIN(ReflectGet)72 BUILTIN(ReflectGet) {
73   HandleScope scope(isolate);
74   Handle<Object> target = args.atOrUndefined(isolate, 1);
75   Handle<Object> key = args.atOrUndefined(isolate, 2);
76   Handle<Object> receiver = args.length() > 3 ? args.at<Object>(3) : target;
77 
78   if (!target->IsJSReceiver()) {
79     THROW_NEW_ERROR_RETURN_FAILURE(
80         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
81                               isolate->factory()->NewStringFromAsciiChecked(
82                                   "Reflect.get")));
83   }
84 
85   Handle<Name> name;
86   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
87                                      Object::ToName(isolate, key));
88 
89   RETURN_RESULT_OR_FAILURE(
90       isolate, Object::GetPropertyOrElement(receiver, name,
91                                             Handle<JSReceiver>::cast(target)));
92 }
93 
94 // ES6 section 26.1.7 Reflect.getOwnPropertyDescriptor
BUILTIN(ReflectGetOwnPropertyDescriptor)95 BUILTIN(ReflectGetOwnPropertyDescriptor) {
96   HandleScope scope(isolate);
97   DCHECK_EQ(3, args.length());
98   Handle<Object> target = args.at<Object>(1);
99   Handle<Object> key = args.at<Object>(2);
100 
101   if (!target->IsJSReceiver()) {
102     THROW_NEW_ERROR_RETURN_FAILURE(
103         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
104                               isolate->factory()->NewStringFromAsciiChecked(
105                                   "Reflect.getOwnPropertyDescriptor")));
106   }
107 
108   Handle<Name> name;
109   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
110                                      Object::ToName(isolate, key));
111 
112   PropertyDescriptor desc;
113   Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
114       isolate, Handle<JSReceiver>::cast(target), name, &desc);
115   MAYBE_RETURN(found, isolate->heap()->exception());
116   if (!found.FromJust()) return isolate->heap()->undefined_value();
117   return *desc.ToObject(isolate);
118 }
119 
120 // ES6 section 26.1.8 Reflect.getPrototypeOf
BUILTIN(ReflectGetPrototypeOf)121 BUILTIN(ReflectGetPrototypeOf) {
122   HandleScope scope(isolate);
123   DCHECK_EQ(2, args.length());
124   Handle<Object> target = args.at<Object>(1);
125 
126   if (!target->IsJSReceiver()) {
127     THROW_NEW_ERROR_RETURN_FAILURE(
128         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
129                               isolate->factory()->NewStringFromAsciiChecked(
130                                   "Reflect.getPrototypeOf")));
131   }
132   Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(target);
133   RETURN_RESULT_OR_FAILURE(isolate,
134                            JSReceiver::GetPrototype(isolate, receiver));
135 }
136 
137 // ES6 section 26.1.9 Reflect.has
BUILTIN(ReflectHas)138 BUILTIN(ReflectHas) {
139   HandleScope scope(isolate);
140   DCHECK_EQ(3, args.length());
141   Handle<Object> target = args.at<Object>(1);
142   Handle<Object> key = args.at<Object>(2);
143 
144   if (!target->IsJSReceiver()) {
145     THROW_NEW_ERROR_RETURN_FAILURE(
146         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
147                               isolate->factory()->NewStringFromAsciiChecked(
148                                   "Reflect.has")));
149   }
150 
151   Handle<Name> name;
152   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
153                                      Object::ToName(isolate, key));
154 
155   Maybe<bool> result =
156       JSReceiver::HasProperty(Handle<JSReceiver>::cast(target), name);
157   return result.IsJust() ? *isolate->factory()->ToBoolean(result.FromJust())
158                          : isolate->heap()->exception();
159 }
160 
161 // ES6 section 26.1.10 Reflect.isExtensible
BUILTIN(ReflectIsExtensible)162 BUILTIN(ReflectIsExtensible) {
163   HandleScope scope(isolate);
164   DCHECK_EQ(2, args.length());
165   Handle<Object> target = args.at<Object>(1);
166 
167   if (!target->IsJSReceiver()) {
168     THROW_NEW_ERROR_RETURN_FAILURE(
169         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
170                               isolate->factory()->NewStringFromAsciiChecked(
171                                   "Reflect.isExtensible")));
172   }
173 
174   Maybe<bool> result =
175       JSReceiver::IsExtensible(Handle<JSReceiver>::cast(target));
176   MAYBE_RETURN(result, isolate->heap()->exception());
177   return *isolate->factory()->ToBoolean(result.FromJust());
178 }
179 
180 // ES6 section 26.1.11 Reflect.ownKeys
BUILTIN(ReflectOwnKeys)181 BUILTIN(ReflectOwnKeys) {
182   HandleScope scope(isolate);
183   DCHECK_EQ(2, args.length());
184   Handle<Object> target = args.at<Object>(1);
185 
186   if (!target->IsJSReceiver()) {
187     THROW_NEW_ERROR_RETURN_FAILURE(
188         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
189                               isolate->factory()->NewStringFromAsciiChecked(
190                                   "Reflect.ownKeys")));
191   }
192 
193   Handle<FixedArray> keys;
194   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
195       isolate, keys,
196       KeyAccumulator::GetKeys(Handle<JSReceiver>::cast(target),
197                               KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
198                               GetKeysConversion::kConvertToString));
199   return *isolate->factory()->NewJSArrayWithElements(keys);
200 }
201 
202 // ES6 section 26.1.12 Reflect.preventExtensions
BUILTIN(ReflectPreventExtensions)203 BUILTIN(ReflectPreventExtensions) {
204   HandleScope scope(isolate);
205   DCHECK_EQ(2, args.length());
206   Handle<Object> target = args.at<Object>(1);
207 
208   if (!target->IsJSReceiver()) {
209     THROW_NEW_ERROR_RETURN_FAILURE(
210         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
211                               isolate->factory()->NewStringFromAsciiChecked(
212                                   "Reflect.preventExtensions")));
213   }
214 
215   Maybe<bool> result = JSReceiver::PreventExtensions(
216       Handle<JSReceiver>::cast(target), Object::DONT_THROW);
217   MAYBE_RETURN(result, isolate->heap()->exception());
218   return *isolate->factory()->ToBoolean(result.FromJust());
219 }
220 
221 // ES6 section 26.1.13 Reflect.set
BUILTIN(ReflectSet)222 BUILTIN(ReflectSet) {
223   HandleScope scope(isolate);
224   Handle<Object> target = args.atOrUndefined(isolate, 1);
225   Handle<Object> key = args.atOrUndefined(isolate, 2);
226   Handle<Object> value = args.atOrUndefined(isolate, 3);
227   Handle<Object> receiver = args.length() > 4 ? args.at<Object>(4) : target;
228 
229   if (!target->IsJSReceiver()) {
230     THROW_NEW_ERROR_RETURN_FAILURE(
231         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
232                               isolate->factory()->NewStringFromAsciiChecked(
233                                   "Reflect.set")));
234   }
235 
236   Handle<Name> name;
237   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
238                                      Object::ToName(isolate, key));
239 
240   LookupIterator it = LookupIterator::PropertyOrElement(
241       isolate, receiver, name, Handle<JSReceiver>::cast(target));
242   Maybe<bool> result = Object::SetSuperProperty(
243       &it, value, SLOPPY, Object::MAY_BE_STORE_FROM_KEYED);
244   MAYBE_RETURN(result, isolate->heap()->exception());
245   return *isolate->factory()->ToBoolean(result.FromJust());
246 }
247 
248 // ES6 section 26.1.14 Reflect.setPrototypeOf
BUILTIN(ReflectSetPrototypeOf)249 BUILTIN(ReflectSetPrototypeOf) {
250   HandleScope scope(isolate);
251   DCHECK_EQ(3, args.length());
252   Handle<Object> target = args.at<Object>(1);
253   Handle<Object> proto = args.at<Object>(2);
254 
255   if (!target->IsJSReceiver()) {
256     THROW_NEW_ERROR_RETURN_FAILURE(
257         isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
258                               isolate->factory()->NewStringFromAsciiChecked(
259                                   "Reflect.setPrototypeOf")));
260   }
261 
262   if (!proto->IsJSReceiver() && !proto->IsNull(isolate)) {
263     THROW_NEW_ERROR_RETURN_FAILURE(
264         isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, proto));
265   }
266 
267   Maybe<bool> result = JSReceiver::SetPrototype(
268       Handle<JSReceiver>::cast(target), proto, true, Object::DONT_THROW);
269   MAYBE_RETURN(result, isolate->heap()->exception());
270   return *isolate->factory()->ToBoolean(result.FromJust());
271 }
272 
273 }  // namespace internal
274 }  // namespace v8
275