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