1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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 "builtin/Array.h"
10 
11 #include "jit/InlinableNatives.h"
12 #include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_NOT_EXPECTED_TYPE
13 #include "js/PropertySpec.h"
14 #include "vm/ArgumentsObject.h"
15 #include "vm/JSContext.h"
16 #include "vm/Stack.h"
17 
18 #include "vm/Interpreter-inl.h"
19 
20 using namespace js;
21 
22 /*** Reflect methods ********************************************************/
23 
24 /* ES6 26.1.4 Reflect.deleteProperty (target, propertyKey) */
Reflect_deleteProperty(JSContext * cx,unsigned argc,Value * vp)25 static bool Reflect_deleteProperty(JSContext* cx, unsigned argc, Value* vp) {
26   CallArgs args = CallArgsFromVp(argc, vp);
27 
28   // Step 1.
29   RootedObject target(
30       cx,
31       RequireObjectArg(cx, "`target`", "Reflect.deleteProperty", args.get(0)));
32   if (!target) {
33     return false;
34   }
35 
36   // Steps 2-3.
37   RootedValue propertyKey(cx, args.get(1));
38   RootedId key(cx);
39   if (!ToPropertyKey(cx, propertyKey, &key)) {
40     return false;
41   }
42 
43   // Step 4.
44   ObjectOpResult result;
45   if (!DeleteProperty(cx, target, key, result)) {
46     return false;
47   }
48   args.rval().setBoolean(result.ok());
49   return true;
50 }
51 
52 /* ES6 26.1.8 Reflect.getPrototypeOf(target) */
Reflect_getPrototypeOf(JSContext * cx,unsigned argc,Value * vp)53 bool js::Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp) {
54   CallArgs args = CallArgsFromVp(argc, vp);
55 
56   // Step 1.
57   RootedObject target(
58       cx,
59       RequireObjectArg(cx, "`target`", "Reflect.getPrototypeOf", args.get(0)));
60   if (!target) {
61     return false;
62   }
63 
64   // Step 2.
65   RootedObject proto(cx);
66   if (!GetPrototype(cx, target, &proto)) {
67     return false;
68   }
69   args.rval().setObjectOrNull(proto);
70   return true;
71 }
72 
73 /* ES6 draft 26.1.10 Reflect.isExtensible(target) */
Reflect_isExtensible(JSContext * cx,unsigned argc,Value * vp)74 bool js::Reflect_isExtensible(JSContext* cx, unsigned argc, Value* vp) {
75   CallArgs args = CallArgsFromVp(argc, vp);
76 
77   // Step 1.
78   RootedObject target(
79       cx,
80       RequireObjectArg(cx, "`target`", "Reflect.isExtensible", args.get(0)));
81   if (!target) {
82     return false;
83   }
84 
85   // Step 2.
86   bool extensible;
87   if (!IsExtensible(cx, target, &extensible)) {
88     return false;
89   }
90   args.rval().setBoolean(extensible);
91   return true;
92 }
93 
94 // ES2018 draft rev c164be80f7ea91de5526b33d54e5c9321ed03d3f
95 // 26.1.10 Reflect.ownKeys ( target )
Reflect_ownKeys(JSContext * cx,unsigned argc,Value * vp)96 bool js::Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp) {
97   CallArgs args = CallArgsFromVp(argc, vp);
98 
99   // Step 1.
100   RootedObject target(
101       cx, RequireObjectArg(cx, "`target`", "Reflect.ownKeys", args.get(0)));
102   if (!target) {
103     return false;
104   }
105 
106   // Steps 2-3.
107   return GetOwnPropertyKeys(
108       cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, args.rval());
109 }
110 
111 /* ES6 26.1.12 Reflect.preventExtensions(target) */
Reflect_preventExtensions(JSContext * cx,unsigned argc,Value * vp)112 static bool Reflect_preventExtensions(JSContext* cx, unsigned argc, Value* vp) {
113   CallArgs args = CallArgsFromVp(argc, vp);
114 
115   // Step 1.
116   RootedObject target(
117       cx, RequireObjectArg(cx, "`target`", "Reflect.preventExtensions",
118                            args.get(0)));
119   if (!target) {
120     return false;
121   }
122 
123   // Step 2.
124   ObjectOpResult result;
125   if (!PreventExtensions(cx, target, result)) {
126     return false;
127   }
128   args.rval().setBoolean(result.ok());
129   return true;
130 }
131 
132 /* ES6 26.1.13 Reflect.set(target, propertyKey, V [, receiver]) */
Reflect_set(JSContext * cx,unsigned argc,Value * vp)133 static bool Reflect_set(JSContext* cx, unsigned argc, Value* vp) {
134   CallArgs args = CallArgsFromVp(argc, vp);
135 
136   // Step 1.
137   RootedObject target(
138       cx, RequireObjectArg(cx, "`target`", "Reflect.set", args.get(0)));
139   if (!target) {
140     return false;
141   }
142 
143   // Steps 2-3.
144   RootedValue propertyKey(cx, args.get(1));
145   RootedId key(cx);
146   if (!ToPropertyKey(cx, propertyKey, &key)) {
147     return false;
148   }
149 
150   // Step 4.
151   RootedValue receiver(cx, args.length() > 3 ? args[3] : args.get(0));
152 
153   // Step 5.
154   ObjectOpResult result;
155   RootedValue value(cx, args.get(2));
156   if (!SetProperty(cx, target, key, value, receiver, result)) {
157     return false;
158   }
159   args.rval().setBoolean(result.ok());
160   return true;
161 }
162 
163 /*
164  * ES6 26.1.3 Reflect.setPrototypeOf(target, proto)
165  *
166  * The specification is not quite similar enough to Object.setPrototypeOf to
167  * share code.
168  */
Reflect_setPrototypeOf(JSContext * cx,unsigned argc,Value * vp)169 static bool Reflect_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp) {
170   CallArgs args = CallArgsFromVp(argc, vp);
171 
172   // Step 1.
173   RootedObject obj(cx, RequireObjectArg(cx, "`target`",
174                                         "Reflect.setPrototypeOf", args.get(0)));
175   if (!obj) {
176     return false;
177   }
178 
179   // Step 2.
180   if (!args.get(1).isObjectOrNull()) {
181     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
182                               JSMSG_NOT_EXPECTED_TYPE, "Reflect.setPrototypeOf",
183                               "an object or null",
184                               InformalValueTypeName(args.get(1)));
185     return false;
186   }
187   RootedObject proto(cx, args.get(1).toObjectOrNull());
188 
189   // Step 4.
190   ObjectOpResult result;
191   if (!SetPrototype(cx, obj, proto, result)) {
192     return false;
193   }
194   args.rval().setBoolean(result.ok());
195   return true;
196 }
197 
198 static const JSFunctionSpec reflect_methods[] = {
199     JS_SELF_HOSTED_FN("apply", "Reflect_apply", 3, 0),
200     JS_SELF_HOSTED_FN("construct", "Reflect_construct", 2, 0),
201     JS_SELF_HOSTED_FN("defineProperty", "Reflect_defineProperty", 3, 0),
202     JS_FN("deleteProperty", Reflect_deleteProperty, 2, 0),
203     JS_SELF_HOSTED_FN("get", "Reflect_get", 2, 0),
204     JS_SELF_HOSTED_FN("getOwnPropertyDescriptor",
205                       "Reflect_getOwnPropertyDescriptor", 2, 0),
206     JS_INLINABLE_FN("getPrototypeOf", Reflect_getPrototypeOf, 1, 0,
207                     ReflectGetPrototypeOf),
208     JS_SELF_HOSTED_FN("has", "Reflect_has", 2, 0),
209     JS_FN("isExtensible", Reflect_isExtensible, 1, 0),
210     JS_FN("ownKeys", Reflect_ownKeys, 1, 0),
211     JS_FN("preventExtensions", Reflect_preventExtensions, 1, 0),
212     JS_FN("set", Reflect_set, 3, 0),
213     JS_FN("setPrototypeOf", Reflect_setPrototypeOf, 2, 0),
214     JS_FS_END};
215 
216 static const JSPropertySpec reflect_properties[] = {
217     JS_STRING_SYM_PS(toStringTag, "Reflect", JSPROP_READONLY), JS_PS_END};
218 
219 /*** Setup ******************************************************************/
220 
CreateReflectObject(JSContext * cx,JSProtoKey key)221 static JSObject* CreateReflectObject(JSContext* cx, JSProtoKey key) {
222   Handle<GlobalObject*> global = cx->global();
223   RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
224   if (!proto) {
225     return nullptr;
226   }
227   return NewTenuredObjectWithGivenProto<PlainObject>(cx, proto);
228 }
229 
230 static const ClassSpec ReflectClassSpec = {CreateReflectObject, nullptr,
231                                            reflect_methods, reflect_properties};
232 
233 const JSClass js::ReflectClass = {"Reflect", 0, JS_NULL_CLASS_OPS,
234                                   &ReflectClassSpec};
235