1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "builtin/Reflect.h"
8
9 #include "jsarray.h"
10 #include "jscntxt.h"
11
12 #include "vm/ArgumentsObject.h"
13 #include "vm/Stack.h"
14
15 #include "vm/Interpreter-inl.h"
16
17 using namespace js;
18
19
20 /*** Reflect methods *****************************************************************************/
21
22 /* ES6 26.1.3 Reflect.defineProperty(target, propertyKey, attributes) */
23 static bool
Reflect_defineProperty(JSContext * cx,unsigned argc,Value * vp)24 Reflect_defineProperty(JSContext* cx, unsigned argc, Value* vp)
25 {
26 CallArgs args = CallArgsFromVp(argc, vp);
27
28 // Step 1.
29 RootedObject obj(cx, NonNullObject(cx, args.get(0)));
30 if (!obj)
31 return false;
32
33 // Steps 2-3.
34 RootedValue propertyKey(cx, args.get(1));
35 RootedId key(cx);
36 if (!ToPropertyKey(cx, propertyKey, &key))
37 return false;
38
39 // Steps 4-5.
40 Rooted<PropertyDescriptor> desc(cx);
41 if (!ToPropertyDescriptor(cx, args.get(2), true, &desc))
42 return false;
43
44 // Step 6.
45 ObjectOpResult result;
46 if (!DefineProperty(cx, obj, key, desc, result))
47 return false;
48 args.rval().setBoolean(bool(result));
49 return true;
50 }
51
52 /* ES6 26.1.4 Reflect.deleteProperty (target, propertyKey) */
53 static bool
Reflect_deleteProperty(JSContext * cx,unsigned argc,Value * vp)54 Reflect_deleteProperty(JSContext* cx, unsigned argc, Value* vp)
55 {
56 CallArgs args = CallArgsFromVp(argc, vp);
57
58 // Step 1.
59 RootedObject target(cx, NonNullObject(cx, args.get(0)));
60 if (!target)
61 return false;
62
63 // Steps 2-3.
64 RootedValue propertyKey(cx, args.get(1));
65 RootedId key(cx);
66 if (!ToPropertyKey(cx, propertyKey, &key))
67 return false;
68
69 // Step 4.
70 ObjectOpResult result;
71 if (!DeleteProperty(cx, target, key, result))
72 return false;
73 args.rval().setBoolean(bool(result));
74 return true;
75 }
76
77 /* ES6 26.1.6 Reflect.get(target, propertyKey [, receiver]) */
78 static bool
Reflect_get(JSContext * cx,unsigned argc,Value * vp)79 Reflect_get(JSContext* cx, unsigned argc, Value* vp)
80 {
81 CallArgs args = CallArgsFromVp(argc, vp);
82
83 // Step 1.
84 RootedObject obj(cx, NonNullObject(cx, args.get(0)));
85 if (!obj)
86 return false;
87
88 // Steps 2-3.
89 RootedValue propertyKey(cx, args.get(1));
90 RootedId key(cx);
91 if (!ToPropertyKey(cx, propertyKey, &key))
92 return false;
93
94 // Step 4.
95 RootedValue receiver(cx, args.length() > 2 ? args[2] : args.get(0));
96
97 // Step 5.
98 return GetProperty(cx, obj, receiver, key, args.rval());
99 }
100
101 /* ES6 26.1.7 Reflect.getOwnPropertyDescriptor(target, propertyKey) */
102 static bool
Reflect_getOwnPropertyDescriptor(JSContext * cx,unsigned argc,Value * vp)103 Reflect_getOwnPropertyDescriptor(JSContext* cx, unsigned argc, Value* vp)
104 {
105 // Step 1.
106 CallArgs args = CallArgsFromVp(argc, vp);
107 if (!NonNullObject(cx, args.get(0)))
108 return false;
109
110 // The other steps are identical to ES6 draft rev 32 (2015 Feb 2) 19.1.2.6
111 // Object.getOwnPropertyDescriptor.
112 return js::obj_getOwnPropertyDescriptor(cx, argc, vp);
113 }
114
115 /* ES6 26.1.8 Reflect.getPrototypeOf(target) */
116 bool
Reflect_getPrototypeOf(JSContext * cx,unsigned argc,Value * vp)117 js::Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
118 {
119 CallArgs args = CallArgsFromVp(argc, vp);
120
121 // Step 1.
122 RootedObject target(cx, NonNullObject(cx, args.get(0)));
123 if (!target)
124 return false;
125
126 // Step 2.
127 RootedObject proto(cx);
128 if (!GetPrototype(cx, target, &proto))
129 return false;
130 args.rval().setObjectOrNull(proto);
131 return true;
132 }
133
134 /* ES6 draft 26.1.10 Reflect.isExtensible(target) */
135 bool
Reflect_isExtensible(JSContext * cx,unsigned argc,Value * vp)136 js::Reflect_isExtensible(JSContext* cx, unsigned argc, Value* vp)
137 {
138 CallArgs args = CallArgsFromVp(argc, vp);
139
140 // Step 1.
141 RootedObject target(cx, NonNullObject(cx, args.get(0)));
142 if (!target)
143 return false;
144
145 // Step 2.
146 bool extensible;
147 if (!IsExtensible(cx, target, &extensible))
148 return false;
149 args.rval().setBoolean(extensible);
150 return true;
151 }
152
153 /* ES6 26.1.11 Reflect.ownKeys(target) */
154 static bool
Reflect_ownKeys(JSContext * cx,unsigned argc,Value * vp)155 Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp)
156 {
157 CallArgs args = CallArgsFromVp(argc, vp);
158
159 // Step 1.
160 if (!NonNullObject(cx, args.get(0)))
161 return false;
162
163 // Steps 2-4.
164 return GetOwnPropertyKeys(cx, args, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS);
165 }
166
167 /* ES6 26.1.12 Reflect.preventExtensions(target) */
168 static bool
Reflect_preventExtensions(JSContext * cx,unsigned argc,Value * vp)169 Reflect_preventExtensions(JSContext* cx, unsigned argc, Value* vp)
170 {
171 CallArgs args = CallArgsFromVp(argc, vp);
172
173 // Step 1.
174 RootedObject target(cx, NonNullObject(cx, args.get(0)));
175 if (!target)
176 return false;
177
178 // Step 2.
179 ObjectOpResult result;
180 if (!PreventExtensions(cx, target, result))
181 return false;
182 args.rval().setBoolean(bool(result));
183 return true;
184 }
185
186 /* ES6 26.1.13 Reflect.set(target, propertyKey, V [, receiver]) */
187 static bool
Reflect_set(JSContext * cx,unsigned argc,Value * vp)188 Reflect_set(JSContext* cx, unsigned argc, Value* vp)
189 {
190 CallArgs args = CallArgsFromVp(argc, vp);
191
192 // Step 1.
193 RootedObject target(cx, NonNullObject(cx, args.get(0)));
194 if (!target)
195 return false;
196
197 // Steps 2-3.
198 RootedValue propertyKey(cx, args.get(1));
199 RootedId key(cx);
200 if (!ToPropertyKey(cx, propertyKey, &key))
201 return false;
202
203 // Step 4.
204 RootedValue receiver(cx, args.length() > 3 ? args[3] : args.get(0));
205
206 // Step 5.
207 ObjectOpResult result;
208 RootedValue value(cx, args.get(2));
209 if (!SetProperty(cx, target, key, value, receiver, result))
210 return false;
211 args.rval().setBoolean(bool(result));
212 return true;
213 }
214
215 /*
216 * ES6 26.1.3 Reflect.setPrototypeOf(target, proto)
217 *
218 * The specification is not quite similar enough to Object.setPrototypeOf to
219 * share code.
220 */
221 static bool
Reflect_setPrototypeOf(JSContext * cx,unsigned argc,Value * vp)222 Reflect_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
223 {
224 CallArgs args = CallArgsFromVp(argc, vp);
225
226 // Step 1.
227 RootedObject obj(cx, NonNullObject(cx, args.get(0)));
228 if (!obj)
229 return false;
230
231 // Step 2.
232 if (!args.get(1).isObjectOrNull()) {
233 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
234 "Reflect.setPrototypeOf", "an object or null",
235 InformalValueTypeName(args.get(1)));
236 return false;
237 }
238 RootedObject proto(cx, args.get(1).toObjectOrNull());
239
240 // Step 4.
241 ObjectOpResult result;
242 if (!SetPrototype(cx, obj, proto, result))
243 return false;
244 args.rval().setBoolean(bool(result));
245 return true;
246 }
247
248 static const JSFunctionSpec methods[] = {
249 JS_SELF_HOSTED_FN("apply", "Reflect_apply", 3, 0),
250 JS_SELF_HOSTED_FN("construct", "Reflect_construct", 2, 0),
251 JS_FN("defineProperty", Reflect_defineProperty, 3, 0),
252 JS_FN("deleteProperty", Reflect_deleteProperty, 2, 0),
253 JS_FN("get", Reflect_get, 2, 0),
254 JS_FN("getOwnPropertyDescriptor", Reflect_getOwnPropertyDescriptor, 2, 0),
255 JS_FN("getPrototypeOf", Reflect_getPrototypeOf, 1, 0),
256 JS_SELF_HOSTED_FN("has", "Reflect_has", 2, 0),
257 JS_FN("isExtensible", Reflect_isExtensible, 1, 0),
258 JS_FN("ownKeys", Reflect_ownKeys, 1, 0),
259 JS_FN("preventExtensions", Reflect_preventExtensions, 1, 0),
260 JS_FN("set", Reflect_set, 3, 0),
261 JS_FN("setPrototypeOf", Reflect_setPrototypeOf, 2, 0),
262 JS_FS_END
263 };
264
265
266 /*** Setup **************************************************************************************/
267
268 JSObject*
InitReflect(JSContext * cx,HandleObject obj)269 js::InitReflect(JSContext* cx, HandleObject obj)
270 {
271 RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
272 if (!proto)
273 return nullptr;
274
275 RootedObject reflect(cx, NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject));
276 if (!reflect)
277 return nullptr;
278 if (!JS_DefineFunctions(cx, reflect, methods))
279 return nullptr;
280
281 RootedValue value(cx, ObjectValue(*reflect));
282 if (!DefineProperty(cx, obj, cx->names().Reflect, value, nullptr, nullptr, JSPROP_RESOLVING))
283 return nullptr;
284
285 obj->as<GlobalObject>().setConstructor(JSProto_Reflect, value);
286
287 return reflect;
288 }
289