1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qv4argumentsobject_p.h"
5
6#include <private/qv4alloca_p.h>
7#include <private/qv4arrayobject_p.h>
8#include <private/qv4function_p.h>
9#include <private/qv4jscall_p.h>
10#include <private/qv4scopedvalue_p.h>
11#include <private/qv4stackframe_p.h>
12#include <private/qv4string_p.h>
13#include <private/qv4symbol_p.h>
14
15using namespace QV4;
16
17DEFINE_OBJECT_VTABLE(ArgumentsObject);
18DEFINE_OBJECT_VTABLE(StrictArgumentsObject);
19
20void Heap::StrictArgumentsObject::init(QV4::JSTypesStackFrame *frame)
21
22{
23 Q_ASSERT(vtable() == QV4::StrictArgumentsObject::staticVTable());
24 ExecutionEngine *v4 = internalClass->engine;
25
26 Object::init();
27
28 Q_ASSERT(internalClass->verifyIndex(v4->id_callee()->propertyKey(), CalleePropertyIndex));
29 Q_ASSERT(internalClass->findValueOrSetter(v4->id_callee()->propertyKey()).index == CalleeSetterPropertyIndex);
30 Q_ASSERT(internalClass->verifyIndex(v4->symbol_iterator()->propertyKey(), SymbolIteratorPropertyIndex));
31 setProperty(e: v4, index: SymbolIteratorPropertyIndex, v: *v4->arrayProtoValues());
32 setProperty(e: v4, index: CalleePropertyIndex, v: *v4->thrower());
33 setProperty(e: v4, index: CalleeSetterPropertyIndex, v: *v4->thrower());
34
35 Scope scope(v4);
36 Scoped<QV4::StrictArgumentsObject> args(scope, this);
37 args->arrayReserve(n: frame->argc());
38 args->arrayPut(index: 0, values: frame->argv(), n: frame->argc());
39
40 Q_ASSERT(args->internalClass()->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex));
41 setProperty(e: v4, index: LengthPropertyIndex, v: Value::fromInt32(i: frame->argc()));
42}
43
44void Heap::ArgumentsObject::init(QV4::CppStackFrame *frame)
45{
46 ExecutionEngine *v4 = internalClass->engine;
47
48 QV4::CallContext *context = static_cast<QV4::CallContext *>(frame->context());
49
50 Object::init();
51 this->context.set(e: v4, newVal: context->d());
52 Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
53
54 Q_ASSERT(internalClass->verifyIndex(v4->id_callee()->propertyKey(), CalleePropertyIndex));
55 setProperty(e: v4, index: CalleePropertyIndex, b: context->d()->function);
56 Q_ASSERT(internalClass->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex));
57 setProperty(e: v4, index: LengthPropertyIndex, v: Value::fromInt32(i: context->argc()));
58 Q_ASSERT(internalClass->verifyIndex(v4->symbol_iterator()->propertyKey(), SymbolIteratorPropertyIndex));
59 setProperty(e: v4, index: SymbolIteratorPropertyIndex, v: *v4->arrayProtoValues());
60
61 fullyCreated = false;
62 argCount = frame->argc();
63 uint nFormals = frame->v4Function->nFormals;
64 mapped = nFormals > 63 ? std::numeric_limits<quint64>::max() : (1ull << nFormals) - 1;
65}
66
67void ArgumentsObject::fullyCreate()
68{
69 if (d()->fullyCreated)
70 return;
71
72 Scope scope(engine());
73
74 arrayReserve(n: d()->argCount);
75 arrayPut(index: 0, values: context()->args(), n: d()->argCount);
76 // Use a sparse array, so that method_getElement() doesn't shortcut
77 initSparseArray();
78
79 d()->fullyCreated = true;
80}
81
82bool ArgumentsObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *desc, PropertyAttributes attrs)
83{
84 ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
85 args->fullyCreate();
86 if (!id.isArrayIndex())
87 return Object::virtualDefineOwnProperty(m, id, p: desc, attrs);
88
89 uint index = id.asArrayIndex();
90
91 if (!args->isMapped(arg: index))
92 return Object::virtualDefineOwnProperty(m, id, p: desc, attrs);
93
94 Scope scope(args);
95 PropertyAttributes cAttrs = attrs;
96 ScopedProperty cDesc(scope);
97 cDesc->copy(other: desc, attrs);
98
99 if (attrs.isData() && desc->value.isEmpty() && attrs.hasWritable() && !attrs.isWritable()) {
100 cDesc->value = args->context()->args()[index];
101 cAttrs.setType(PropertyAttributes::Data);
102 }
103
104 bool allowed = Object::virtualDefineOwnProperty(m, id, p: cDesc, attrs: cAttrs);
105 if (!allowed)
106 return false;
107
108 if (attrs.isAccessor()) {
109 args->removeMapping(arg: index);
110 } else {
111 if (!desc->value.isEmpty())
112 args->context()->setArg(index, v: desc->value);
113 if (attrs.hasWritable() && !attrs.isWritable())
114 args->removeMapping(arg: index);
115 }
116 return true;
117}
118
119ReturnedValue ArgumentsObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
120{
121 if (id.isArrayIndex()) {
122 const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
123 uint index = id.asArrayIndex();
124 if (index < args->d()->argCount && !args->d()->fullyCreated) {
125 if (hasProperty)
126 *hasProperty = true;
127 return args->context()->args()[index].asReturnedValue();
128 }
129
130 if (args->isMapped(arg: index)) {
131 Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount()));
132 if (hasProperty)
133 *hasProperty = true;
134 return args->context()->args()[index].asReturnedValue();
135 }
136 }
137
138 return Object::virtualGet(m, id, receiver, hasProperty);
139}
140
141bool ArgumentsObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
142{
143 if (id.isArrayIndex()) {
144 ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
145 uint index = id.asArrayIndex();
146
147 if (args == receiver && index < args->d()->argCount && !args->d()->fullyCreated) {
148 args->context()->setArg(index, v: value);
149 return true;
150 }
151
152 bool isMapped = (args == receiver && args->isMapped(arg: index));
153 if (isMapped)
154 args->context()->setArg(index, v: value);
155 }
156
157 return Object::virtualPut(m, id, value, receiver);
158}
159
160bool ArgumentsObject::virtualDeleteProperty(Managed *m, PropertyKey id)
161{
162 ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
163 args->fullyCreate();
164 bool result = Object::virtualDeleteProperty(m, id);
165 if (result && id.isArrayIndex())
166 args->removeMapping(arg: id.asArrayIndex());
167 return result;
168}
169
170PropertyAttributes ArgumentsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
171{
172 if (!id.isArrayIndex())
173 return Object::virtualGetOwnProperty(m, id, p);
174
175 const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
176 uint index = id.asArrayIndex();
177 if (index < args->d()->argCount && !args->d()->fullyCreated) {
178 p->value = args->context()->args()[index];
179 return Attr_Data;
180 }
181
182 PropertyAttributes attrs = Object::virtualGetOwnProperty(m, id, p);
183 if (attrs.isEmpty() || !args->isMapped(arg: index))
184 return attrs;
185
186 Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount()));
187 if (p)
188 p->value = args->context()->args()[index];
189 return attrs;
190}
191
192qint64 ArgumentsObject::virtualGetLength(const Managed *m)
193{
194 const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m);
195 return a->propertyData(index: Heap::ArgumentsObject::LengthPropertyIndex)->toLength();
196}
197
198OwnPropertyKeyIterator *ArgumentsObject::virtualOwnPropertyKeys(const Object *m, Value *target)
199{
200 static_cast<ArgumentsObject *>(const_cast<Object *>(m))->fullyCreate();
201 return Object::virtualOwnPropertyKeys(m, target);
202}
203

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