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