diff options
Diffstat (limited to 'src/qml/jsruntime/qv4argumentsobject.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4argumentsobject.cpp | 262 |
1 files changed, 120 insertions, 142 deletions
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 0905c2828a..4a21f62cf2 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -37,209 +37,187 @@ ** ****************************************************************************/ #include <qv4argumentsobject_p.h> +#include <qv4arrayobject_p.h> #include <qv4alloca_p.h> #include <qv4scopedvalue_p.h> #include <qv4string_p.h> #include <qv4function_p.h> +#include <qv4jscall_p.h> +#include <qv4symbol_p.h> using namespace QV4; DEFINE_OBJECT_VTABLE(ArgumentsObject); +DEFINE_OBJECT_VTABLE(StrictArgumentsObject); + +void Heap::StrictArgumentsObject::init(QV4::CppStackFrame *frame) -void Heap::ArgumentsObject::init(QV4::CallContext *context) { + Q_ASSERT(vtable() == QV4::StrictArgumentsObject::staticVTable()); ExecutionEngine *v4 = internalClass->engine; Object::init(); - fullyCreated = false; + + 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->originalArgumentsCount); + args->arrayPut(0, frame->originalArguments, frame->originalArgumentsCount); + + Q_ASSERT(args->internalClass()->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex)); + setProperty(v4, LengthPropertyIndex, Value::fromInt32(frame->originalArgumentsCount)); +} + +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()); - Scope scope(v4); - Scoped<QV4::ArgumentsObject> args(scope, this); - - if (context->d()->strictMode) { - Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee())); - Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(v4->id_caller())); - args->setProperty(CalleePropertyIndex + QV4::Object::GetterOffset, *v4->thrower()); - args->setProperty(CalleePropertyIndex + QV4::Object::SetterOffset, *v4->thrower()); - args->setProperty(CallerPropertyIndex + QV4::Object::GetterOffset, *v4->thrower()); - args->setProperty(CallerPropertyIndex + QV4::Object::SetterOffset, *v4->thrower()); - - args->arrayReserve(context->argc()); - args->arrayPut(0, context->args(), context->argc()); - args->d()->fullyCreated = true; - } else { - Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee())); - args->setProperty(CalleePropertyIndex, context->d()->function); - } - Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(v4->id_length())); - args->setProperty(LengthPropertyIndex, Primitive::fromInt32(context->d()->callData->argc)); + 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->originalArgumentsCount; + uint nFormals = frame->v4Function->nFormals; + mapped = nFormals > 63 ? std::numeric_limits<quint64>::max() : (1ull << nFormals) - 1; } void ArgumentsObject::fullyCreate() { - if (fullyCreated()) + if (d()->fullyCreated) return; Scope scope(engine()); - uint argCount = context()->callData->argc; - uint numAccessors = qMin(context()->formalParameterCount(), argCount); - ArrayData::realloc(this, Heap::ArrayData::Sparse, argCount, true); - scope.engine->requireArgumentsAccessors(numAccessors); - - Scoped<MemberData> md(scope, d()->mappedArguments); - if (numAccessors) { - d()->mappedArguments.set(scope.engine, md->allocate(scope.engine, numAccessors)); - for (uint i = 0; i < numAccessors; ++i) { - d()->mappedArguments->values.set(scope.engine, i, context()->callData->args[i]); - arraySet(i, scope.engine->argumentsAccessors + i, Attr_Accessor); - } - } - arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors); - for (uint i = numAccessors; i < argCount; ++i) - setArrayAttributes(i, Attr_Data); + 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::defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs) +bool ArgumentsObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *desc, PropertyAttributes attrs) { - fullyCreate(); - - Scope scope(engine); - ScopedProperty map(scope); - PropertyAttributes mapAttrs; - uint numAccessors = qMin(context()->formalParameterCount(), static_cast<uint>(context()->callData->argc)); - bool isMapped = false; - if (arrayData() && index < numAccessors && - arrayData()->attributes(index).isAccessor() && - arrayData()->get(index) == scope.engine->argumentsAccessors[index].getter()->asReturnedValue()) - isMapped = true; - - if (isMapped) { - Q_ASSERT(arrayData()); - mapAttrs = arrayData()->attributes(index); - arrayData()->getProperty(index, map, &mapAttrs); - setArrayAttributes(index, Attr_Data); - ArrayData::Index arrayIndex{ arrayData(), arrayData()->mappedIndex(index) }; - arrayIndex.set(scope.engine, d()->mappedArguments->values[index]); - } + ArgumentsObject *args = static_cast<ArgumentsObject *>(m); + args->fullyCreate(); + 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); - bool strict = engine->current->strictMode; - engine->current->strictMode = false; - bool result = Object::defineOwnProperty2(scope.engine, index, desc, attrs); - engine->current->strictMode = strict; - - if (isMapped && attrs.isData()) { - Q_ASSERT(arrayData()); - ScopedFunctionObject setter(scope, map->setter()); - ScopedCallData callData(scope, 1); - callData->thisObject = this->asReturnedValue(); - callData->args[0] = desc->value; - setter->call(scope, callData); - - if (attrs.isWritable()) { - setArrayAttributes(index, mapAttrs); - arrayData()->setProperty(engine, index, map); - } + if (attrs.isData() && desc->value.isEmpty() && attrs.hasWritable() && !attrs.isWritable()) { + cDesc->value = args->context()->args()[index]; + cAttrs.setType(PropertyAttributes::Data); } - if (engine->current->strictMode && !result) - return engine->throwTypeError(); - return result; + 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::getIndexed(const Managed *m, uint index, bool *hasProperty) +ReturnedValue ArgumentsObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) { const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); - if (args->fullyCreated()) - return Object::getIndexed(m, index, hasProperty); - - if (index < static_cast<uint>(args->context()->callData->argc)) { + uint index = id.asArrayIndex(); + if (index < args->d()->argCount && !args->d()->fullyCreated) { if (hasProperty) *hasProperty = true; - return args->context()->callData->args[index].asReturnedValue(); + return args->context()->args()[index].asReturnedValue(); } + + if (!args->isMapped(index)) + return Object::virtualGet(m, id, receiver, hasProperty); + Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount())); if (hasProperty) - *hasProperty = false; - return Encode::undefined(); + *hasProperty = true; + return args->context()->args()[index].asReturnedValue(); } -bool ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value) +bool ArgumentsObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver) { ArgumentsObject *args = static_cast<ArgumentsObject *>(m); - if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->callData->argc)) - args->fullyCreate(); + uint index = id.asArrayIndex(); - if (args->fullyCreated()) - return Object::putIndexed(m, index, value); + if (args == receiver && index < args->d()->argCount && !args->d()->fullyCreated) { + args->context()->setArg(index, value); + return true; + } - args->context()->callData->args[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::deleteIndexedProperty(Managed *m, uint index) +bool ArgumentsObject::virtualDeleteProperty(Managed *m, PropertyKey id) { ArgumentsObject *args = static_cast<ArgumentsObject *>(m); - if (!args->fullyCreated()) - args->fullyCreate(); - return Object::deleteIndexedProperty(m, index); + args->fullyCreate(); + bool result = Object::virtualDeleteProperty(m, id); + if (result) + args->removeMapping(id.asArrayIndex()); + return result; } -PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index) +PropertyAttributes ArgumentsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p) { const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); - if (args->fullyCreated()) - return Object::queryIndexed(m, index); - - uint numAccessors = qMin((int)args->context()->formalParameterCount(), args->context()->callData->argc); - uint argCount = args->context()->callData->argc; - if (index >= argCount) - return PropertyAttributes(); - if (index >= numAccessors) + uint index = id.asArrayIndex(); + if (index < args->d()->argCount && !args->d()->fullyCreated) { + p->value = args->context()->args()[index]; return Attr_Data; - return Attr_Accessor; -} - -DEFINE_OBJECT_VTABLE(ArgumentsGetterFunction); - -void ArgumentsGetterFunction::call(const Managed *getter, Scope &scope, CallData *callData) -{ - ExecutionEngine *v4 = static_cast<const ArgumentsGetterFunction *>(getter)->engine(); - Scoped<ArgumentsGetterFunction> g(scope, static_cast<const ArgumentsGetterFunction *>(getter)); - Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); - if (!o) { - scope.result = v4->throwTypeError(); - return; } - Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->callData->argc)); - scope.result = o->context()->callData->args[g->index()]; -} + PropertyAttributes attrs = Object::virtualGetOwnProperty(m, id, p); + if (attrs.isEmpty() || !args->isMapped(index)) + return attrs; -DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction); + Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount())); + if (p) + p->value = args->context()->args()[index]; + return attrs; +} -void ArgumentsSetterFunction::call(const Managed *setter, Scope &scope, CallData *callData) +qint64 ArgumentsObject::virtualGetLength(const Managed *m) { - ExecutionEngine *v4 = static_cast<const ArgumentsSetterFunction *>(setter)->engine(); - Scoped<ArgumentsSetterFunction> s(scope, static_cast<const ArgumentsSetterFunction *>(setter)); - Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); - if (!o) { - scope.result = v4->throwTypeError(); - return; - } - - Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->callData->argc)); - o->context()->callData->args[s->index()] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined(); - scope.result = Encode::undefined(); + const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m); + return a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->toLength(); } -uint ArgumentsObject::getLength(const Managed *m) +OwnPropertyKeyIterator *ArgumentsObject::virtualOwnPropertyKeys(const Object *m, Value *target) { - const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m); - if (a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->isInteger()) - return a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->integerValue(); - return Primitive::toUInt32(a->propertyData(Heap::ArgumentsObject::LengthPropertyIndex)->doubleValue()); + static_cast<ArgumentsObject *>(const_cast<Object *>(m))->fullyCreate(); + return Object::virtualOwnPropertyKeys(m, target); } |