1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 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 #include <qv4argumentsobject_p.h>
40 #include <qv4arrayobject_p.h>
41 #include <qv4scopedvalue_p.h>
42 #include <qv4string_p.h>
43 #include <qv4function_p.h>
44 #include <qv4jscall_p.h>
45 #include <qv4symbol_p.h>
46
47 #include <private/qv4alloca_p.h>
48
49 using namespace QV4;
50
51 DEFINE_OBJECT_VTABLE(ArgumentsObject);
52 DEFINE_OBJECT_VTABLE(StrictArgumentsObject);
53
init(QV4::CppStackFrame * frame)54 void Heap::StrictArgumentsObject::init(QV4::CppStackFrame *frame)
55
56 {
57 Q_ASSERT(vtable() == QV4::StrictArgumentsObject::staticVTable());
58 ExecutionEngine *v4 = internalClass->engine;
59
60 Object::init();
61
62 Q_ASSERT(internalClass->verifyIndex(v4->id_callee()->propertyKey(), CalleePropertyIndex));
63 Q_ASSERT(internalClass->findValueOrSetter(v4->id_callee()->propertyKey()).index == CalleeSetterPropertyIndex);
64 Q_ASSERT(internalClass->verifyIndex(v4->symbol_iterator()->propertyKey(), SymbolIteratorPropertyIndex));
65 setProperty(v4, SymbolIteratorPropertyIndex, *v4->arrayProtoValues());
66 setProperty(v4, CalleePropertyIndex, *v4->thrower());
67 setProperty(v4, CalleeSetterPropertyIndex, *v4->thrower());
68
69 Scope scope(v4);
70 Scoped<QV4::StrictArgumentsObject> args(scope, this);
71 args->arrayReserve(frame->originalArgumentsCount);
72 args->arrayPut(0, frame->originalArguments, frame->originalArgumentsCount);
73
74 Q_ASSERT(args->internalClass()->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex));
75 setProperty(v4, LengthPropertyIndex, Value::fromInt32(frame->originalArgumentsCount));
76 }
77
init(QV4::CppStackFrame * frame)78 void Heap::ArgumentsObject::init(QV4::CppStackFrame *frame)
79 {
80 ExecutionEngine *v4 = internalClass->engine;
81
82 QV4::CallContext *context = static_cast<QV4::CallContext *>(frame->context());
83
84 Object::init();
85 this->context.set(v4, context->d());
86 Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
87
88 Q_ASSERT(internalClass->verifyIndex(v4->id_callee()->propertyKey(), CalleePropertyIndex));
89 setProperty(v4, CalleePropertyIndex, context->d()->function);
90 Q_ASSERT(internalClass->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex));
91 setProperty(v4, LengthPropertyIndex, Value::fromInt32(context->argc()));
92 Q_ASSERT(internalClass->verifyIndex(v4->symbol_iterator()->propertyKey(), SymbolIteratorPropertyIndex));
93 setProperty(v4, SymbolIteratorPropertyIndex, *v4->arrayProtoValues());
94
95 fullyCreated = false;
96 argCount = frame->originalArgumentsCount;
97 uint nFormals = frame->v4Function->nFormals;
98 mapped = nFormals > 63 ? std::numeric_limits<quint64>::max() : (1ull << nFormals) - 1;
99 }
100
fullyCreate()101 void ArgumentsObject::fullyCreate()
102 {
103 if (d()->fullyCreated)
104 return;
105
106 Scope scope(engine());
107
108 arrayReserve(d()->argCount);
109 arrayPut(0, context()->args(), d()->argCount);
110 // Use a sparse array, so that method_getElement() doesn't shortcut
111 initSparseArray();
112
113 d()->fullyCreated = true;
114 }
115
virtualDefineOwnProperty(Managed * m,PropertyKey id,const Property * desc,PropertyAttributes attrs)116 bool ArgumentsObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *desc, PropertyAttributes attrs)
117 {
118 ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
119 args->fullyCreate();
120 if (!id.isArrayIndex())
121 return Object::virtualDefineOwnProperty(m, id, desc, attrs);
122
123 uint index = id.asArrayIndex();
124
125 if (!args->isMapped(index))
126 return Object::virtualDefineOwnProperty(m, id, desc, attrs);
127
128 Scope scope(args);
129 PropertyAttributes cAttrs = attrs;
130 ScopedProperty cDesc(scope);
131 cDesc->copy(desc, attrs);
132
133 if (attrs.isData() && desc->value.isEmpty() && attrs.hasWritable() && !attrs.isWritable()) {
134 cDesc->value = args->context()->args()[index];
135 cAttrs.setType(PropertyAttributes::Data);
136 }
137
138 bool allowed = Object::virtualDefineOwnProperty(m, id, cDesc, cAttrs);
139 if (!allowed)
140 return false;
141
142 if (attrs.isAccessor()) {
143 args->removeMapping(index);
144 } else {
145 if (!desc->value.isEmpty())
146 args->context()->setArg(index, desc->value);
147 if (attrs.hasWritable() && !attrs.isWritable())
148 args->removeMapping(index);
149 }
150 return true;
151 }
152
virtualGet(const Managed * m,PropertyKey id,const Value * receiver,bool * hasProperty)153 ReturnedValue ArgumentsObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
154 {
155 if (id.isArrayIndex()) {
156 const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
157 uint index = id.asArrayIndex();
158 if (index < args->d()->argCount && !args->d()->fullyCreated) {
159 if (hasProperty)
160 *hasProperty = true;
161 return args->context()->args()[index].asReturnedValue();
162 }
163
164 if (args->isMapped(index)) {
165 Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount()));
166 if (hasProperty)
167 *hasProperty = true;
168 return args->context()->args()[index].asReturnedValue();
169 }
170 }
171
172 return Object::virtualGet(m, id, receiver, hasProperty);
173 }
174
virtualPut(Managed * m,PropertyKey id,const Value & value,Value * receiver)175 bool ArgumentsObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
176 {
177 if (id.isArrayIndex()) {
178 ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
179 uint index = id.asArrayIndex();
180
181 if (args == receiver && index < args->d()->argCount && !args->d()->fullyCreated) {
182 args->context()->setArg(index, value);
183 return true;
184 }
185
186 bool isMapped = (args == receiver && args->isMapped(index));
187 if (isMapped)
188 args->context()->setArg(index, value);
189 }
190
191 return Object::virtualPut(m, id, value, receiver);
192 }
193
virtualDeleteProperty(Managed * m,PropertyKey id)194 bool ArgumentsObject::virtualDeleteProperty(Managed *m, PropertyKey id)
195 {
196 ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
197 args->fullyCreate();
198 bool result = Object::virtualDeleteProperty(m, id);
199 if (result && id.isArrayIndex())
200 args->removeMapping(id.asArrayIndex());
201 return result;
202 }
203
virtualGetOwnProperty(const Managed * m,PropertyKey id,Property * p)204 PropertyAttributes ArgumentsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
205 {
206 if (!id.isArrayIndex())
207 return Object::virtualGetOwnProperty(m, id, p);
208
209 const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
210 uint index = id.asArrayIndex();
211 if (index < args->d()->argCount && !args->d()->fullyCreated) {
212 p->value = args->context()->args()[index];
213 return Attr_Data;
214 }
215
216 PropertyAttributes attrs = Object::virtualGetOwnProperty(m, id, p);
217 if (attrs.isEmpty() || !args->isMapped(index))
218 return attrs;
219
220 Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount()));
221 if (p)
222 p->value = args->context()->args()[index];
223 return attrs;
224 }
225
virtualGetLength(const Managed * m)226 qint64 ArgumentsObject::virtualGetLength(const Managed *m)
227 {
228 const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m);
229 return a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->toLength();
230 }
231
virtualOwnPropertyKeys(const Object * m,Value * target)232 OwnPropertyKeyIterator *ArgumentsObject::virtualOwnPropertyKeys(const Object *m, Value *target)
233 {
234 static_cast<ArgumentsObject *>(const_cast<Object *>(m))->fullyCreate();
235 return Object::virtualOwnPropertyKeys(m, target);
236 }
237