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