Encapsulate and protect all accesses to the vtable of Heap objects
[platform/upstream/qtdeclarative.git] / src / qml / jsruntime / qv4argumentsobject.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33 #include <qv4argumentsobject_p.h>
34 #include <qv4alloca_p.h>
35 #include <qv4scopedvalue_p.h>
36 #include "qv4string_p.h"
37
38 using namespace QV4;
39
40 DEFINE_OBJECT_VTABLE(ArgumentsObject);
41
42 Heap::ArgumentsObject::ArgumentsObject(QV4::CallContext *context)
43     : Heap::Object(context->d()->strictMode ? context->d()->engine->strictArgumentsObjectClass : context->d()->engine->argumentsObjectClass,
44                    context->d()->engine->objectPrototype())
45     , context(context->d())
46     , fullyCreated(false)
47 {
48     Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
49
50     ExecutionEngine *v4 = context->d()->engine;
51     Scope scope(v4);
52     Scoped<QV4::ArgumentsObject> args(scope, this);
53
54     args->setArrayType(Heap::ArrayData::Complex);
55
56     if (context->d()->strictMode) {
57         Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee()));
58         Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller()));
59         args->propertyAt(CalleePropertyIndex)->value = v4->thrower();
60         args->propertyAt(CalleePropertyIndex)->set = v4->thrower();
61         args->propertyAt(CallerPropertyIndex)->value = v4->thrower();
62         args->propertyAt(CallerPropertyIndex)->set = v4->thrower();
63
64         args->arrayReserve(context->argc());
65         args->arrayPut(0, context->args(), context->argc());
66         args->d()->fullyCreated = true;
67     } else {
68         Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee()));
69         args->memberData()->data[CalleePropertyIndex] = context->d()->function->asReturnedValue();
70     }
71     Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length()));
72     args->memberData()->data[LengthPropertyIndex] = Primitive::fromInt32(context->d()->callData->argc);
73 }
74
75 void ArgumentsObject::fullyCreate()
76 {
77     if (fullyCreated())
78         return;
79
80     uint numAccessors = qMin((int)context()->function->formalParameterCount(), context()->callData->argc);
81     uint argCount = context()->callData->argc;
82     ArrayData::realloc(this, Heap::ArrayData::Sparse, argCount, true);
83     context()->engine->requireArgumentsAccessors(numAccessors);
84
85     Scope scope(engine());
86     Scoped<MemberData> md(scope, d()->mappedArguments);
87     if (!md || md->size() < numAccessors)
88         d()->mappedArguments = md->reallocate(engine(), d()->mappedArguments, numAccessors);
89     for (uint i = 0; i < (uint)numAccessors; ++i) {
90         mappedArguments()->data[i] = context()->callData->args[i];
91         arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
92     }
93     arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors);
94     for (uint i = numAccessors; i < argCount; ++i)
95         setArrayAttributes(i, Attr_Data);
96
97     d()->fullyCreated = true;
98 }
99
100 bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs)
101 {
102     fullyCreate();
103
104     Scope scope(engine);
105     Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
106     ScopedProperty map(scope);
107     PropertyAttributes mapAttrs;
108     bool isMapped = false;
109     uint numAccessors = qMin((int)context()->function->formalParameterCount(), context()->callData->argc);
110     if (pd && index < (uint)numAccessors)
111         isMapped = arrayData()->attributes(index).isAccessor() &&
112                 pd->getter() == context()->engine->argumentsAccessors[index].getter();
113
114     if (isMapped) {
115         Q_ASSERT(arrayData());
116         mapAttrs = arrayData()->attributes(index);
117         map->copy(pd, mapAttrs);
118         setArrayAttributes(index, Attr_Data);
119         pd = arrayData()->getProperty(index);
120         pd->value = mappedArguments()->data[index];
121     }
122
123     bool strict = engine->currentContext()->strictMode;
124     engine->currentContext()->strictMode = false;
125     bool result = Object::defineOwnProperty2(scope.engine, index, desc, attrs);
126     engine->currentContext()->strictMode = strict;
127
128     if (isMapped && attrs.isData()) {
129         Q_ASSERT(arrayData());
130         ScopedFunctionObject setter(scope, map->setter());
131         ScopedCallData callData(scope, 1);
132         callData->thisObject = this->asReturnedValue();
133         callData->args[0] = desc->value;
134         setter->call(callData);
135
136         if (attrs.isWritable()) {
137             setArrayAttributes(index, mapAttrs);
138             pd = arrayData()->getProperty(index);
139             pd->copy(map, mapAttrs);
140         }
141     }
142
143     if (engine->currentContext()->strictMode && !result)
144         return engine->throwTypeError();
145     return result;
146 }
147
148 ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *hasProperty)
149 {
150     const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
151     if (args->fullyCreated())
152         return Object::getIndexed(m, index, hasProperty);
153
154     if (index < static_cast<uint>(args->context()->callData->argc)) {
155         if (hasProperty)
156             *hasProperty = true;
157         return args->context()->callData->args[index].asReturnedValue();
158     }
159     if (hasProperty)
160         *hasProperty = false;
161     return Encode::undefined();
162 }
163
164 void ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
165 {
166     ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
167     if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->callData->argc))
168         args->fullyCreate();
169
170     if (args->fullyCreated()) {
171         Object::putIndexed(m, index, value);
172         return;
173     }
174
175     args->context()->callData->args[index] = value;
176 }
177
178 bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
179 {
180     ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
181     if (!args->fullyCreated())
182         args->fullyCreate();
183     return Object::deleteIndexedProperty(m, index);
184 }
185
186 PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index)
187 {
188     const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
189     if (args->fullyCreated())
190         return Object::queryIndexed(m, index);
191
192     uint numAccessors = qMin((int)args->context()->function->formalParameterCount(), args->context()->callData->argc);
193     uint argCount = args->context()->callData->argc;
194     if (index >= argCount)
195         return PropertyAttributes();
196     if (index >= numAccessors)
197         return Attr_Data;
198     return Attr_Accessor;
199 }
200
201 DEFINE_OBJECT_VTABLE(ArgumentsGetterFunction);
202
203 ReturnedValue ArgumentsGetterFunction::call(const Managed *getter, CallData *callData)
204 {
205     ExecutionEngine *v4 = static_cast<const ArgumentsGetterFunction *>(getter)->engine();
206     Scope scope(v4);
207     Scoped<ArgumentsGetterFunction> g(scope, static_cast<const ArgumentsGetterFunction *>(getter));
208     Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
209     if (!o)
210         return v4->throwTypeError();
211
212     Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->callData->argc));
213     return o->context()->callData->args[g->index()].asReturnedValue();
214 }
215
216 DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction);
217
218 ReturnedValue ArgumentsSetterFunction::call(const Managed *setter, CallData *callData)
219 {
220     ExecutionEngine *v4 = static_cast<const ArgumentsSetterFunction *>(setter)->engine();
221     Scope scope(v4);
222     Scoped<ArgumentsSetterFunction> s(scope, static_cast<const ArgumentsSetterFunction *>(setter));
223     Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
224     if (!o)
225         return v4->throwTypeError();
226
227     Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->callData->argc));
228     o->context()->callData->args[s->index()] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined();
229     return Encode::undefined();
230 }
231
232 void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e)
233 {
234     ArgumentsObject::Data *o = static_cast<ArgumentsObject::Data *>(that);
235     if (o->context)
236         o->context->mark(e);
237     if (o->mappedArguments)
238         o->mappedArguments->mark(e);
239
240     Object::markObjects(that, e);
241 }