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