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