Revision control
Copy as Markdown
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant
#include "qv4argumentsobject_p.h"
#include <private/qv4alloca_p.h>
#include <private/qv4arrayobject_p.h>
#include <private/qv4function_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4scopedvalue_p.h>
#include <private/qv4stackframe_p.h>
#include <private/qv4string_p.h>
#include <private/qv4symbol_p.h>
using namespace QV4;
DEFINE_OBJECT_VTABLE(ArgumentsObject);
DEFINE_OBJECT_VTABLE(StrictArgumentsObject);
void Heap::StrictArgumentsObject::init(QV4::JSTypesStackFrame *frame)
{
Q_ASSERT(vtable() == QV4::StrictArgumentsObject::staticVTable());
ExecutionEngine *v4 = internalClass->engine;
Object::init();
Q_ASSERT(internalClass->verifyIndex(v4->id_callee()->propertyKey(), CalleePropertyIndex));
Q_ASSERT(internalClass->findValueOrSetter(v4->id_callee()->propertyKey()).index == CalleeSetterPropertyIndex);
Q_ASSERT(internalClass->verifyIndex(v4->symbol_iterator()->propertyKey(), SymbolIteratorPropertyIndex));
setProperty(v4, SymbolIteratorPropertyIndex, *v4->arrayProtoValues());
setProperty(v4, CalleePropertyIndex, *v4->thrower());
setProperty(v4, CalleeSetterPropertyIndex, *v4->thrower());
Scope scope(v4);
Scoped<QV4::StrictArgumentsObject> args(scope, this);
args->arrayReserve(frame->argc());
args->arrayPut(0, frame->argv(), frame->argc());
Q_ASSERT(args->internalClass()->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex));
setProperty(v4, LengthPropertyIndex, Value::fromInt32(frame->argc()));
}
void Heap::ArgumentsObject::init(QV4::CppStackFrame *frame)
{
ExecutionEngine *v4 = internalClass->engine;
QV4::CallContext *context = static_cast<QV4::CallContext *>(frame->context());
Object::init();
this->context.set(v4, context->d());
Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
Q_ASSERT(internalClass->verifyIndex(v4->id_callee()->propertyKey(), CalleePropertyIndex));
setProperty(v4, CalleePropertyIndex, context->d()->function);
Q_ASSERT(internalClass->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex));
setProperty(v4, LengthPropertyIndex, Value::fromInt32(context->argc()));
Q_ASSERT(internalClass->verifyIndex(v4->symbol_iterator()->propertyKey(), SymbolIteratorPropertyIndex));
setProperty(v4, SymbolIteratorPropertyIndex, *v4->arrayProtoValues());
fullyCreated = false;
argCount = frame->argc();
uint nFormals = frame->v4Function->nFormals;
mapped = nFormals > 63 ? std::numeric_limits<quint64>::max() : (1ull << nFormals) - 1;
}
void ArgumentsObject::fullyCreate()
{
if (d()->fullyCreated)
return;
Scope scope(engine());
arrayReserve(d()->argCount);
arrayPut(0, context()->args(), d()->argCount);
// Use a sparse array, so that method_getElement() doesn't shortcut
initSparseArray();
d()->fullyCreated = true;
}
bool ArgumentsObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *desc, PropertyAttributes attrs)
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
args->fullyCreate();
if (!id.isArrayIndex())
return Object::virtualDefineOwnProperty(m, id, desc, attrs);
uint index = id.asArrayIndex();
if (!args->isMapped(index))
return Object::virtualDefineOwnProperty(m, id, desc, attrs);
Scope scope(args);
PropertyAttributes cAttrs = attrs;
ScopedProperty cDesc(scope);
cDesc->copy(desc, attrs);
if (attrs.isData() && desc->value.isEmpty() && attrs.hasWritable() && !attrs.isWritable()) {
cDesc->value = args->context()->args()[index];
cAttrs.setType(PropertyAttributes::Data);
}
bool allowed = Object::virtualDefineOwnProperty(m, id, cDesc, cAttrs);
if (!allowed)
return false;
if (attrs.isAccessor()) {
args->removeMapping(index);
} else {
if (!desc->value.isEmpty())
args->context()->setArg(index, desc->value);
if (attrs.hasWritable() && !attrs.isWritable())
args->removeMapping(index);
}
return true;
}
ReturnedValue ArgumentsObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
{
if (id.isArrayIndex()) {
const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
uint index = id.asArrayIndex();
if (index < args->d()->argCount && !args->d()->fullyCreated) {
if (hasProperty)
*hasProperty = true;
return args->context()->args()[index].asReturnedValue();
}
if (args->isMapped(index)) {
Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount()));
if (hasProperty)
*hasProperty = true;
return args->context()->args()[index].asReturnedValue();
}
}
return Object::virtualGet(m, id, receiver, hasProperty);
}
bool ArgumentsObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
{
if (id.isArrayIndex()) {
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
uint index = id.asArrayIndex();
if (args == receiver && index < args->d()->argCount && !args->d()->fullyCreated) {
args->context()->setArg(index, value);
return true;
}
bool isMapped = (args == receiver && args->isMapped(index));
if (isMapped)
args->context()->setArg(index, value);
}
return Object::virtualPut(m, id, value, receiver);
}
bool ArgumentsObject::virtualDeleteProperty(Managed *m, PropertyKey id)
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
args->fullyCreate();
bool result = Object::virtualDeleteProperty(m, id);
if (result && id.isArrayIndex())
args->removeMapping(id.asArrayIndex());
return result;
}
PropertyAttributes ArgumentsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
{
if (!id.isArrayIndex())
return Object::virtualGetOwnProperty(m, id, p);
const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
uint index = id.asArrayIndex();
if (index < args->d()->argCount && !args->d()->fullyCreated) {
p->value = args->context()->args()[index];
return Attr_Data;
}
PropertyAttributes attrs = Object::virtualGetOwnProperty(m, id, p);
if (attrs.isEmpty() || !args->isMapped(index))
return attrs;
Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount()));
if (p)
p->value = args->context()->args()[index];
return attrs;
}
qint64 ArgumentsObject::virtualGetLength(const Managed *m)
{
const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m);
return a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->toLength();
}
OwnPropertyKeyIterator *ArgumentsObject::virtualOwnPropertyKeys(const Object *m, Value *target)
{
static_cast<ArgumentsObject *>(const_cast<Object *>(m))->fullyCreate();
return Object::virtualOwnPropertyKeys(m, target);
}