1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the QtQml module of the Qt Toolkit.
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.
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.
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.
32 ****************************************************************************/
33 #include <qv4argumentsobject_p.h>
34 #include <qv4alloca_p.h>
35 #include <qv4scopedvalue_p.h>
36 #include "qv4string_p.h"
40 DEFINE_OBJECT_VTABLE(ArgumentsObject);
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())
48 Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
50 ExecutionEngine *v4 = context->d()->engine;
52 Scoped<QV4::ArgumentsObject> args(scope, this);
54 args->setArrayType(Heap::ArrayData::Complex);
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();
64 args->arrayReserve(context->argc());
65 args->arrayPut(0, context->args(), context->argc());
66 args->d()->fullyCreated = true;
68 Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee()));
69 args->memberData()->data[CalleePropertyIndex] = context->d()->function->asReturnedValue();
71 Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length()));
72 args->memberData()->data[LengthPropertyIndex] = Primitive::fromInt32(context->d()->callData->argc);
75 void ArgumentsObject::fullyCreate()
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);
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);
93 arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors);
94 for (uint i = numAccessors; i < argCount; ++i)
95 setArrayAttributes(i, Attr_Data);
97 d()->fullyCreated = true;
100 bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs)
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();
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];
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;
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);
136 if (attrs.isWritable()) {
137 setArrayAttributes(index, mapAttrs);
138 pd = arrayData()->getProperty(index);
139 pd->copy(map, mapAttrs);
143 if (engine->currentContext()->strictMode && !result)
144 return engine->throwTypeError();
148 ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *hasProperty)
150 const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
151 if (args->fullyCreated())
152 return Object::getIndexed(m, index, hasProperty);
154 if (index < static_cast<uint>(args->context()->callData->argc)) {
157 return args->context()->callData->args[index].asReturnedValue();
160 *hasProperty = false;
161 return Encode::undefined();
164 void ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
166 ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
167 if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->callData->argc))
170 if (args->fullyCreated()) {
171 Object::putIndexed(m, index, value);
175 args->context()->callData->args[index] = value;
178 bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
180 ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
181 if (!args->fullyCreated())
183 return Object::deleteIndexedProperty(m, index);
186 PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index)
188 const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
189 if (args->fullyCreated())
190 return Object::queryIndexed(m, index);
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)
198 return Attr_Accessor;
201 DEFINE_OBJECT_VTABLE(ArgumentsGetterFunction);
203 ReturnedValue ArgumentsGetterFunction::call(const Managed *getter, CallData *callData)
205 ExecutionEngine *v4 = static_cast<const ArgumentsGetterFunction *>(getter)->engine();
207 Scoped<ArgumentsGetterFunction> g(scope, static_cast<const ArgumentsGetterFunction *>(getter));
208 Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
210 return v4->throwTypeError();
212 Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->callData->argc));
213 return o->context()->callData->args[g->index()].asReturnedValue();
216 DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction);
218 ReturnedValue ArgumentsSetterFunction::call(const Managed *setter, CallData *callData)
220 ExecutionEngine *v4 = static_cast<const ArgumentsSetterFunction *>(setter)->engine();
222 Scoped<ArgumentsSetterFunction> s(scope, static_cast<const ArgumentsSetterFunction *>(setter));
223 Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
225 return v4->throwTypeError();
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();
232 void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e)
234 ArgumentsObject::Data *o = static_cast<ArgumentsObject::Data *>(that);
237 if (o->mappedArguments)
238 o->mappedArguments->mark(e);
240 Object::markObjects(that, e);