1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qv4reflect_p.h"
41 #include "qv4symbol_p.h"
42 #include "qv4runtimeapi_p.h"
43 #include "qv4objectproto_p.h"
44 #include "qv4propertykey_p.h"
45 #include "qv4objectiterator_p.h"
46
47 using namespace QV4;
48
49 DEFINE_OBJECT_VTABLE(Reflect);
50
init()51 void Heap::Reflect::init()
52 {
53 Object::init();
54 Scope scope(internalClass->engine);
55 ScopedObject r(scope, this);
56
57 r->defineDefaultProperty(QStringLiteral("apply"), QV4::Reflect::method_apply, 3);
58 r->defineDefaultProperty(QStringLiteral("construct"), QV4::Reflect::method_construct, 2);
59 r->defineDefaultProperty(QStringLiteral("defineProperty"), QV4::Reflect::method_defineProperty, 3);
60 r->defineDefaultProperty(QStringLiteral("deleteProperty"), QV4::Reflect::method_deleteProperty, 2);
61 r->defineDefaultProperty(QStringLiteral("get"), QV4::Reflect::method_get, 2);
62 r->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), QV4::Reflect::method_getOwnPropertyDescriptor, 2);
63 r->defineDefaultProperty(QStringLiteral("getPrototypeOf"), QV4::Reflect::method_getPrototypeOf, 1);
64 r->defineDefaultProperty(QStringLiteral("has"), QV4::Reflect::method_has, 2);
65 r->defineDefaultProperty(QStringLiteral("isExtensible"), QV4::Reflect::method_isExtensible, 1);
66 r->defineDefaultProperty(QStringLiteral("ownKeys"), QV4::Reflect::method_ownKeys, 1);
67 r->defineDefaultProperty(QStringLiteral("preventExtensions"), QV4::Reflect::method_preventExtensions, 1);
68 r->defineDefaultProperty(QStringLiteral("set"), QV4::Reflect::method_set, 3);
69 r->defineDefaultProperty(QStringLiteral("setPrototypeOf"), QV4::Reflect::method_setPrototypeOf, 2);
70 }
71
72 struct CallArgs {
73 Value *argv;
74 int argc;
75 };
76
createListFromArrayLike(Scope & scope,const Object * o)77 static CallArgs createListFromArrayLike(Scope &scope, const Object *o)
78 {
79 int len = o->getLength();
80 Value *arguments = scope.alloc(len);
81
82 for (int i = 0; i < len; ++i) {
83 arguments[i] = o->get(i);
84 if (scope.hasException())
85 return { nullptr, 0 };
86 }
87 return { arguments, len };
88 }
89
method_apply(const FunctionObject * f,const Value *,const Value * argv,int argc)90 ReturnedValue Reflect::method_apply(const FunctionObject *f, const Value *, const Value *argv, int argc)
91 {
92 Scope scope(f);
93 if (argc < 3 || !argv[0].isFunctionObject() || !argv[2].isObject())
94 return scope.engine->throwTypeError();
95
96 const Object *o = static_cast<const Object *>(argv + 2);
97 CallArgs arguments = createListFromArrayLike(scope, o);
98 if (scope.hasException())
99 return Encode::undefined();
100
101 return checkedResult(scope.engine, static_cast<const FunctionObject &>(argv[0]).call(
102 &argv[1], arguments.argv, arguments.argc));
103 }
104
method_construct(const FunctionObject * f,const Value *,const Value * argv,int argc)105 ReturnedValue Reflect::method_construct(const FunctionObject *f, const Value *, const Value *argv, int argc)
106 {
107 Scope scope(f);
108 if (argc < 2 || !argv[1].isObject())
109 return scope.engine->throwTypeError();
110 const FunctionObject *target = argv[0].as<FunctionObject>();
111 const FunctionObject *newTarget = argc == 3 ? argv[2].as<FunctionObject>() : target;
112 if (!target || !target->isConstructor() || !newTarget || !newTarget->isConstructor())
113 return scope.engine->throwTypeError();
114
115 const Object *o = static_cast<const Object *>(argv + 1);
116 CallArgs arguments = createListFromArrayLike(scope, o);
117 if (scope.hasException())
118 return Encode::undefined();
119
120 return target->callAsConstructor(arguments.argv, arguments.argc, newTarget);
121 }
122
method_defineProperty(const FunctionObject * f,const Value *,const Value * argv,int argc)123 ReturnedValue Reflect::method_defineProperty(const FunctionObject *f, const Value *, const Value *argv, int argc)
124 {
125 Scope scope(f);
126 if (!argc || !argv[0].isObject())
127 return scope.engine->throwTypeError();
128
129 ScopedObject O(scope, argv[0]);
130 ScopedPropertyKey name(scope, (argc > 1 ? argv[1] : Value::undefinedValue()).toPropertyKey(scope.engine));
131 if (scope.engine->hasException)
132 return QV4::Encode::undefined();
133
134 ScopedValue attributes(scope, argc > 2 ? argv[2] : Value::undefinedValue());
135 ScopedProperty pd(scope);
136 PropertyAttributes attrs;
137 ObjectPrototype::toPropertyDescriptor(scope.engine, attributes, pd, &attrs);
138 if (scope.engine->hasException)
139 return QV4::Encode::undefined();
140
141 bool result = O->defineOwnProperty(name, pd, attrs);
142
143 return Encode(result);
144 }
145
method_deleteProperty(const FunctionObject * f,const Value *,const Value * argv,int argc)146 ReturnedValue Reflect::method_deleteProperty(const FunctionObject *f, const Value *, const Value *argv, int argc)
147 {
148 ExecutionEngine *e = f->engine();
149 if (!argc || !argv[0].isObject())
150 return e->throwTypeError();
151
152 bool result = Runtime::DeleteProperty_NoThrow::call(e, argv[0], argc > 1 ? argv[1] : Value::undefinedValue());
153 return Encode(result);
154 }
155
method_get(const FunctionObject * f,const Value *,const Value * argv,int argc)156 ReturnedValue Reflect::method_get(const FunctionObject *f, const Value *, const Value *argv, int argc)
157 {
158 Scope scope(f);
159 if (!argc || !argv[0].isObject())
160 return scope.engine->throwTypeError();
161
162 ScopedObject o(scope, static_cast<const Object *>(argv));
163 Value undef = Value::undefinedValue();
164 const Value *index = argc > 1 ? &argv[1] : &undef;
165 ScopedPropertyKey name(scope, index->toPropertyKey(scope.engine));
166 if (scope.hasException())
167 return Encode::undefined();
168 ScopedValue receiver(scope, argc > 2 ? argv[2] : *o);
169
170 return Encode(o->get(name, receiver));
171 }
172
method_getOwnPropertyDescriptor(const FunctionObject * f,const Value * thisObject,const Value * argv,int argc)173 ReturnedValue Reflect::method_getOwnPropertyDescriptor(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
174 {
175 if (!argc || !argv[0].isObject())
176 return f->engine()->throwTypeError();
177
178 return ObjectPrototype::method_getOwnPropertyDescriptor(f, thisObject, argv, argc);
179 }
180
method_getPrototypeOf(const FunctionObject * f,const Value *,const Value * argv,int argc)181 ReturnedValue Reflect::method_getPrototypeOf(const FunctionObject *f, const Value *, const Value *argv, int argc)
182 {
183 if (!argc || !argv[0].isObject())
184 return f->engine()->throwTypeError();
185
186 const Object *o = static_cast<const Object *>(argv);
187 Heap::Object *p = o->getPrototypeOf();
188 return (p ? p->asReturnedValue() : Encode::null());
189 }
190
method_has(const FunctionObject * f,const Value *,const Value * argv,int argc)191 ReturnedValue Reflect::method_has(const FunctionObject *f, const Value *, const Value *argv, int argc)
192 {
193 Scope scope(f);
194 if (!argc || !argv[0].isObject())
195 return scope.engine->throwTypeError();
196
197 ScopedObject o(scope, static_cast<const Object *>(argv));
198 Value undef = Value::undefinedValue();
199 const Value *index = argc > 1 ? &argv[1] : &undef;
200
201 ScopedPropertyKey name(scope, index->toPropertyKey(scope.engine));
202 if (scope.engine->hasException)
203 return false;
204
205 return Encode(o->hasProperty(name));
206 }
207
method_isExtensible(const FunctionObject * f,const Value *,const Value * argv,int argc)208 ReturnedValue Reflect::method_isExtensible(const FunctionObject *f, const Value *, const Value *argv, int argc)
209 {
210 if (!argc || !argv[0].isObject())
211 return f->engine()->throwTypeError();
212
213 const Object *o = static_cast<const Object *>(argv);
214 return Encode(o->isExtensible());
215 }
216
217
method_ownKeys(const FunctionObject * f,const Value *,const Value * argv,int argc)218 ReturnedValue Reflect::method_ownKeys(const FunctionObject *f, const Value *, const Value *argv, int argc)
219 {
220 if (!argc || !argv[0].isObject())
221 return f->engine()->throwTypeError();
222
223 Scope scope(f);
224 if (!argc)
225 return scope.engine->throwTypeError();
226
227 ScopedObject O(scope, argv[0].toObject(scope.engine));
228 if (!O)
229 return Encode::undefined();
230
231 ScopedArrayObject keys(scope, scope.engine->newArrayObject());
232
233 ObjectIterator it(scope, O, ObjectIterator::WithSymbols);
234 ScopedPropertyKey key(scope);
235 ScopedValue v(scope);
236 while (1) {
237 key = it.next();
238 if (!key->isValid())
239 break;
240 v = key->toStringOrSymbol(scope.engine);
241 keys->push_back(v);
242 }
243
244 return keys->asReturnedValue();
245
246 }
247
method_preventExtensions(const FunctionObject * f,const Value *,const Value * argv,int argc)248 ReturnedValue Reflect::method_preventExtensions(const FunctionObject *f, const Value *, const Value *argv, int argc)
249 {
250 Scope scope(f);
251 if (!argc || !argv[0].isObject())
252 return scope.engine->throwTypeError();
253
254 ScopedObject o(scope, static_cast<const Object *>(argv));
255 return Encode(o->preventExtensions());
256 }
257
method_set(const FunctionObject * f,const Value *,const Value * argv,int argc)258 ReturnedValue Reflect::method_set(const FunctionObject *f, const Value *, const Value *argv, int argc)
259 {
260 Scope scope(f);
261 if (!argc || !argv[0].isObject())
262 return scope.engine->throwTypeError();
263
264 ScopedObject o(scope, static_cast<const Object *>(argv));
265 Value undef = Value::undefinedValue();
266 const Value *index = argc > 1 ? &argv[1] : &undef;
267 const Value &val = argc > 2 ? argv[2] : undef;
268 ScopedValue receiver(scope, argc >3 ? argv[3] : argv[0]);
269
270 ScopedPropertyKey propertyKey(scope, index->toPropertyKey(scope.engine));
271 if (scope.engine->hasException)
272 return false;
273 bool result = o->put(propertyKey, val, receiver);
274 return Encode(result);
275 }
276
method_setPrototypeOf(const FunctionObject * f,const Value *,const Value * argv,int argc)277 ReturnedValue Reflect::method_setPrototypeOf(const FunctionObject *f, const Value *, const Value *argv, int argc)
278 {
279 if (argc < 2 || !argv[0].isObject() || (!argv[1].isNull() && !argv[1].isObject()))
280 return f->engine()->throwTypeError();
281
282 Scope scope(f);
283 ScopedObject o(scope, static_cast<const Object *>(argv));
284 const Object *proto = argv[1].isNull() ? nullptr : static_cast<const Object *>(argv + 1);
285 return Encode(o->setPrototypeOf(proto));
286 }
287