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
49using namespace QV4;
50
51DEFINE_OBJECT_VTABLE(ArgumentsObject);
52DEFINE_OBJECT_VTABLE(StrictArgumentsObject);
53
54void 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(e: v4, index: SymbolIteratorPropertyIndex, v: *v4->arrayProtoValues());
66 setProperty(e: v4, index: CalleePropertyIndex, v: *v4->thrower());
67 setProperty(e: v4, index: CalleeSetterPropertyIndex, v: *v4->thrower());
68
69 Scope scope(v4);
70 Scoped<QV4::StrictArgumentsObject> args(scope, this);
71 args->arrayReserve(n: frame->originalArgumentsCount);
72 args->arrayPut(index: 0, values: frame->originalArguments, n: frame->originalArgumentsCount);
73
74 Q_ASSERT(args->internalClass()->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex));
75 setProperty(e: v4, index: LengthPropertyIndex, v: Value::fromInt32(i: frame->originalArgumentsCount));
76}
77
78void 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(e: v4, newVal: context->d());
86 Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
87
88 Q_ASSERT(internalClass->verifyIndex(v4->id_callee()->propertyKey(), CalleePropertyIndex));
89 setProperty(e: v4, index: CalleePropertyIndex, b: context->d()->function);
90 Q_ASSERT(internalClass->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex));
91 setProperty(e: v4, index: LengthPropertyIndex, v: Value::fromInt32(i: context->argc()));
92 Q_ASSERT(internalClass->verifyIndex(v4->symbol_iterator()->propertyKey(), SymbolIteratorPropertyIndex));
93 setProperty(e: v4, index: SymbolIteratorPropertyIndex, v: *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
101void ArgumentsObject::fullyCreate()
102{
103 if (d()->fullyCreated)
104 return;
105
106 Scope scope(engine());
107
108 arrayReserve(n: d()->argCount);
109 arrayPut(index: 0, values: context()->args(), n: d()->argCount);
110 // Use a sparse array, so that method_getElement() doesn't shortcut
111 initSparseArray();
112
113 d()->fullyCreated = true;
114}
115
116bool 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, p: desc, attrs);
122
123 uint index = id.asArrayIndex();
124
125 if (!args->isMapped(arg: index))
126 return Object::virtualDefineOwnProperty(m, id, p: desc, attrs);
127
128 Scope scope(args);
129 PropertyAttributes cAttrs = attrs;
130 ScopedProperty cDesc(scope);
131 cDesc->copy(other: 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, p: cDesc, attrs: cAttrs);
139 if (!allowed)
140 return false;
141
142 if (attrs.isAccessor()) {
143 args->removeMapping(arg: index);
144 } else {
145 if (!desc->value.isEmpty())
146 args->context()->setArg(index, v: desc->value);
147 if (attrs.hasWritable() && !attrs.isWritable())
148 args->removeMapping(arg: index);
149 }
150 return true;
151}
152
153ReturnedValue 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(arg: 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
175bool 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, v: value);
183 return true;
184 }
185
186 bool isMapped = (args == receiver && args->isMapped(arg: index));
187 if (isMapped)
188 args->context()->setArg(index, v: value);
189 }
190
191 return Object::virtualPut(m, id, value, receiver);
192}
193
194bool 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(arg: id.asArrayIndex());
201 return result;
202}
203
204PropertyAttributes 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(arg: 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
226qint64 ArgumentsObject::virtualGetLength(const Managed *m)
227{
228 const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m);
229 return a->propertyData(index: Heap::ArgumentsObject::LengthPropertyIndex)->toLength();
230}
231
232OwnPropertyKeyIterator *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

source code of qtdeclarative/src/qml/jsruntime/qv4argumentsobject.cpp