diff options
Diffstat (limited to 'src/qml')
90 files changed, 2229 insertions, 963 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index a7b5326861..c66202262b 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2861,7 +2861,7 @@ void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QStr if (hasError) return; hasError = true; - context->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn); + context->engine()->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn); } void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const QString &detail) @@ -2869,7 +2869,7 @@ void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const Q if (hasError) return; hasError = true; - context->throwReferenceError(detail, _module->fileName, loc.startLine, loc.startColumn); + context->engine()->throwReferenceError(detail, _module->fileName, loc.startLine, loc.startColumn); } #endif // V4_BOOTSTRAP diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index d242fb7b3a..fbef8b8566 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -65,9 +65,9 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) Q_ASSERT(!runtimeStrings); Q_ASSERT(data); - runtimeStrings = (QV4::StringValue *)malloc(data->stringTableSize * sizeof(QV4::StringValue)); + runtimeStrings = (QV4::String **)malloc(data->stringTableSize * sizeof(QV4::String*)); // memset the strings to 0 in case a GC run happens while we're within the loop below - memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::StringValue)); + memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::String*)); for (uint i = 0; i < data->stringTableSize; ++i) runtimeStrings[i] = engine->newIdentifier(data->stringAt(i)); @@ -109,7 +109,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) l->classList[j] = 0; l->level = -1; l->index = UINT_MAX; - l->name = runtimeStrings[compiledLookups[i].nameIndex].asString(); + l->name = runtimeStrings[compiledLookups[i].nameIndex]; if (type == CompiledData::Lookup::Type_IndexedGetter || type == CompiledData::Lookup::Type_IndexedSetter) l->engine = engine; } @@ -123,7 +123,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount); QV4::InternalClass *klass = engine->objectClass; for (int j = 0; j < memberCount; ++j, ++member) - klass = klass->addMember(runtimeStrings[member->nameOffset].asString(), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data); + klass = klass->addMember(runtimeStrings[member->nameOffset], member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data); runtimeClasses[i] = klass; } @@ -166,14 +166,16 @@ void CompilationUnit::unlink() void CompilationUnit::markObjects(QV4::ExecutionEngine *e) { for (uint i = 0; i < data->stringTableSize; ++i) - runtimeStrings[i].mark(e); + if (runtimeStrings[i]) + runtimeStrings[i]->mark(e); if (runtimeRegularExpressions) { for (uint i = 0; i < data->regexpTableSize; ++i) runtimeRegularExpressions[i].mark(e); } if (runtimeLookups) { for (uint i = 0; i < data->lookupTableSize; ++i) - runtimeLookups[i].name->mark(e); + if (runtimeLookups[i].name) + runtimeLookups[i].name->mark(e); } } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 6791970461..6ab7191358 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -588,7 +588,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount ExecutionEngine *engine; QString fileName() const { return data->stringAt(data->sourceFileIndex); } - QV4::StringValue *runtimeStrings; // Array + QV4::String **runtimeStrings; // Array QV4::Lookup *runtimeLookups; QV4::Value *runtimeRegularExpressions; QV4::InternalClass **runtimeClasses; diff --git a/src/qml/debugger/qqmlprofilerdefinitions_p.h b/src/qml/debugger/qqmlprofilerdefinitions_p.h index e8ee98433d..713134f394 100644 --- a/src/qml/debugger/qqmlprofilerdefinitions_p.h +++ b/src/qml/debugger/qqmlprofilerdefinitions_p.h @@ -107,18 +107,20 @@ struct QQmlProfilerDefinitions { }; enum SceneGraphFrameType { - SceneGraphRendererFrame, - SceneGraphAdaptationLayerFrame, - SceneGraphContextFrame, - SceneGraphRenderLoopFrame, - SceneGraphTexturePrepare, - SceneGraphTextureDeletion, - SceneGraphPolishAndSync, - SceneGraphWindowsRenderShow, - SceneGraphWindowsAnimations, - SceneGraphPolishFrame, - - MaximumSceneGraphFrameType + SceneGraphRendererFrame, // Render Thread + SceneGraphAdaptationLayerFrame, // Render Thread + SceneGraphContextFrame, // Render Thread + SceneGraphRenderLoopFrame, // Render Thread + SceneGraphTexturePrepare, // Render Thread + SceneGraphTextureDeletion, // Render Thread + SceneGraphPolishAndSync, // GUI Thread + SceneGraphWindowsRenderShow, // Unused + SceneGraphWindowsAnimations, // GUI Thread + SceneGraphPolishFrame, // GUI Thread + + MaximumSceneGraphFrameType, + NumRenderThreadFrameTypes = SceneGraphPolishAndSync, + NumGUIThreadFrameTypes = MaximumSceneGraphFrameType - NumRenderThreadFrameTypes }; typedef QV4::Profiling::MemoryType MemoryType; diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index ed342740ac..300f4b0fb2 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -214,7 +214,7 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, compilationUnit)), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg); const int id = _isel->registerString(string); - return Pointer(reg, id * sizeof(QV4::StringValue)); + return Pointer(reg, id * sizeof(QV4::String*)); } void Assembler::loadStringRef(RegisterID reg, const QString &string) @@ -222,7 +222,7 @@ void Assembler::loadStringRef(RegisterID reg, const QString &string) loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, compilationUnit)), reg); loadPtr(Address(reg, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg); const int id = _isel->registerString(string); - loadPtr(Address(reg, id * sizeof(QV4::StringValue)), reg); + loadPtr(Address(reg, id * sizeof(QV4::String*)), reg); } void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination) diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp index f7976e7cfc..cc6953cbf7 100644 --- a/src/qml/jsapi/qjsvalueiterator.cpp +++ b/src/qml/jsapi/qjsvalueiterator.cpp @@ -36,6 +36,7 @@ #include "qjsvalue_p.h" #include "private/qv4string_p.h" #include "private/qv4object_p.h" +#include "private/qv4context_p.h" QT_BEGIN_NAMESPACE @@ -51,7 +52,7 @@ QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v) QV4::Scope scope(e); QV4::ScopedObject o(scope, jsp->value); - iterator = e->newForEachIteratorObject(e->currentContext(), o)->asReturnedValue(); + iterator = e->newForEachIteratorObject(o)->asReturnedValue(); currentName = (QV4::String *)0; nextName = (QV4::String *)0; @@ -223,7 +224,7 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) QJSValuePrivate *jsp = QJSValuePrivate::get(object); QV4::Scope scope(v4); QV4::ScopedObject o(scope, jsp->value); - d_ptr->iterator = v4->newForEachIteratorObject(v4->currentContext(), o)->asReturnedValue(); + d_ptr->iterator = v4->newForEachIteratorObject(o)->asReturnedValue(); QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); it->d()->it.flags = QV4::ObjectIterator::NoFlags; QV4::String *nm = 0; diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index c27aaa90d8..ef44ca6f4d 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -42,7 +42,10 @@ SOURCES += \ $$PWD/qv4qobjectwrapper.cpp \ $$PWD/qv4qmlextensions.cpp \ $$PWD/qv4vme_moth.cpp \ - $$PWD/qv4profiling.cpp + $$PWD/qv4profiling.cpp \ + $$PWD/qv4arraybuffer.cpp \ + $$PWD/qv4typedarray.cpp \ + $$PWD/qv4dataview.cpp HEADERS += \ $$PWD/qv4global_p.h \ @@ -89,7 +92,10 @@ HEADERS += \ $$PWD/qv4qobjectwrapper_p.h \ $$PWD/qv4qmlextensions_p.h \ $$PWD/qv4vme_moth_p.h \ - $$PWD/qv4profiling_p.h + $$PWD/qv4profiling_p.h \ + $$PWD/qv4arraybuffer_p.h \ + $$PWD/qv4typedarray_p.h \ + $$PWD/qv4dataview_p.h } diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 4af8927a2e..e8cb788b74 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -134,7 +134,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const } if (ctx->d()->strictMode && !result) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return result; } @@ -200,7 +200,7 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) Scoped<ArgumentsGetterFunction> g(scope, static_cast<ArgumentsGetterFunction *>(getter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) - return v4->currentContext()->throwTypeError(); + return v4->throwTypeError(); Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->d()->callData->argc)); return o->context()->argument(g->index()); @@ -215,19 +215,19 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData) Scoped<ArgumentsSetterFunction> s(scope, static_cast<ArgumentsSetterFunction *>(setter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) - return v4->currentContext()->throwTypeError(); + return v4->throwTypeError(); Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->d()->callData->argc)); o->context()->d()->callData->args[s->index()] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined(); return Encode::undefined(); } -void ArgumentsObject::markObjects(Managed *that, ExecutionEngine *e) +void ArgumentsObject::markObjects(HeapObject *that, ExecutionEngine *e) { - ArgumentsObject *o = static_cast<ArgumentsObject *>(that); - if (o->context()) - o->context()->mark(e); - o->mappedArguments().mark(e); + ArgumentsObject::Data *o = static_cast<ArgumentsObject::Data *>(that); + if (o->context) + o->context->mark(e); + o->mappedArguments.mark(e); Object::markObjects(that, e); } diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 786cb36d0a..73c6bb26f3 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -106,7 +106,7 @@ struct ArgumentsObject: Object { static void putIndexed(Managed *m, uint index, const ValueRef value); static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); void fullyCreate(); }; diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp new file mode 100644 index 0000000000..82ab2a2a87 --- /dev/null +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qv4arraybuffer_p.h" +#include "qv4typedarray_p.h" +#include "qv4dataview_p.h" + +using namespace QV4; + +DEFINE_OBJECT_VTABLE(ArrayBufferCtor); +DEFINE_OBJECT_VTABLE(ArrayBuffer); + +ArrayBufferCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("ArrayBuffer")) +{ + setVTable(staticVTable()); +} + +ReturnedValue ArrayBufferCtor::construct(Managed *m, CallData *callData) +{ + ExecutionEngine *v4 = m->engine(); + + Scope scope(v4); + ScopedValue l(scope, callData->argument(0)); + double dl = l->toInteger(); + if (v4->hasException) + return Encode::undefined(); + uint len = (uint)qBound(0., dl, (double)UINT_MAX); + if (len != dl) + return v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length")); + + Scoped<ArrayBuffer> a(scope, v4->memoryManager->alloc<ArrayBuffer>(v4, len)); + if (scope.engine->hasException) + return Encode::undefined(); + return a.asReturnedValue(); +} + + +ReturnedValue ArrayBufferCtor::call(Managed *that, CallData *callData) +{ + return construct(that, callData); +} + +ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx) +{ + QV4::Scope scope(ctx); + QV4::Scoped<TypedArray> a(scope, ctx->argument(0)); + if (!!a) + return Encode(true); + QV4::Scoped<DataView> v(scope, ctx->argument(0)); + if (!!v) + return Encode(true); + return Encode(true); +} + + +ArrayBuffer::Data::Data(ExecutionEngine *e, int length) + : Object::Data(e->arrayBufferClass) +{ + data = QTypedArrayData<char>::allocate(length + 1); + if (!data) { + data = 0; + e->throwRangeError(QStringLiteral("ArrayBuffer: out of memory")); + return; + } + data->size = length; + memset(data->data(), 0, length + 1); +} + +QByteArray ArrayBuffer::asByteArray() const +{ + QByteArrayDataPtr ba = { d()->data }; + ba.ptr->ref.ref(); + return QByteArray(ba); +} + +void ArrayBuffer::destroy(Managed *m) +{ + ArrayBuffer *b = static_cast<ArrayBuffer *>(m); + if (!b->d()->data->ref.deref()) + QTypedArrayData<char>::deallocate(b->d()->data); +} + + +void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor) +{ + Scope scope(engine); + ScopedObject o(scope); + ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineDefaultProperty(QStringLiteral("isView"), ArrayBufferCtor::method_isView, 1); + defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); + defineDefaultProperty(QStringLiteral("slice"), method_slice, 2); +} + +ReturnedValue ArrayBufferPrototype::method_get_byteLength(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<ArrayBuffer> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->data->size); +} + +ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<ArrayBuffer> a(scope, ctx->d()->callData->thisObject); + if (!a) + return scope.engine->throwTypeError(); + + double start = ctx->d()->callData->argc > 0 ? ctx->d()->callData->args[0].toInteger() : 0; + double end = (ctx->d()->callData->argc < 2 || ctx->d()->callData->args[1].isUndefined()) ? + a->d()->data->size : ctx->d()->callData->args[1].toInteger(); + if (scope.engine->hasException) + return Encode::undefined(); + + double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size); + double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size); + + Scoped<FunctionObject> constructor(scope, a->get(scope.engine->id_constructor)); + if (!constructor) + return scope.engine->throwTypeError(); + + ScopedCallData callData(scope, 1); + double newLen = qMax(final - first, 0.); + callData->args[0] = QV4::Encode(newLen); + QV4::Scoped<ArrayBuffer> newBuffer(scope, constructor->construct(callData)); + if (!newBuffer || newBuffer->d()->data->size < (int)newLen) + return scope.engine->throwTypeError(); + + memcpy(newBuffer->d()->data->data(), a->d()->data->data() + (uint)first, newLen); + + return newBuffer.asReturnedValue(); +} diff --git a/src/qml/qml/v8/qv8debug_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index 75342aa070..57ee34e570 100644 --- a/src/qml/qml/v8/qv8debug_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -30,5 +30,64 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#ifndef QV4ARRAYBUFFER_H +#define QV4ARRAYBUFFER_H -//#include <private/v8-debug.h> +#include "qv4object_p.h" +#include "qv4functionobject_p.h" + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct ArrayBufferCtor: FunctionObject +{ + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + + V4_OBJECT(FunctionObject) + + static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue call(Managed *that, CallData *callData); + + static ReturnedValue method_isView(CallContext *ctx); + +}; + +struct ArrayBuffer : Object +{ + struct Data : Object::Data { + Data(ExecutionEngine *e, int length); + QTypedArrayData<char> *data; + }; + V4_OBJECT(Object) + + QByteArray asByteArray() const; + uint byteLength() const { return d()->data->size; } + char *data() { + // ### detach if refcount > 1 + return d()->data->data(); + } + const char *constData() { + // ### detach if refcount > 1 + return d()->data->data(); + } + + static void destroy(Managed *m); +}; + +struct ArrayBufferPrototype: Object +{ + void init(ExecutionEngine *engine, Object *ctor); + + static ReturnedValue method_get_byteLength(CallContext *ctx); + static ReturnedValue method_slice(CallContext *ctx); +}; + + +} // namespace QV4 + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 35bd6e5501..5aaed1a98d 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -34,6 +34,7 @@ #include "qv4object_p.h" #include "qv4functionobject_p.h" #include "qv4mm_p.h" +#include "qv4runtime_p.h" using namespace QV4; @@ -212,12 +213,12 @@ void ArrayData::ensureAttributes(Object *o) } -void SimpleArrayData::markObjects(Managed *d, ExecutionEngine *e) +void SimpleArrayData::markObjects(HeapObject *d, ExecutionEngine *e) { - SimpleArrayData *dd = static_cast<SimpleArrayData *>(d); - uint l = dd->len(); + SimpleArrayData::Data *dd = static_cast<SimpleArrayData::Data *>(d); + uint l = dd->len; for (uint i = 0; i < l; ++i) - dd->data(i).mark(e); + dd->arrayData[i].mark(e); } ReturnedValue SimpleArrayData::get(const ArrayData *d, uint index) @@ -362,12 +363,12 @@ void SparseArrayData::destroy(Managed *d) delete dd->sparse(); } -void SparseArrayData::markObjects(Managed *d, ExecutionEngine *e) +void SparseArrayData::markObjects(HeapObject *d, ExecutionEngine *e) { - SparseArrayData *dd = static_cast<SparseArrayData *>(d); - uint l = dd->alloc(); + SparseArrayData::Data *dd = static_cast<SparseArrayData::Data *>(d); + uint l = dd->alloc; for (uint i = 0; i < l; ++i) - dd->arrayData()[i].mark(e); + dd->arrayData[i].mark(e); } ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes) @@ -746,7 +747,7 @@ void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueR return; if (!(comparefn->isUndefined() || comparefn->asObject())) { - context->throwTypeError(); + context->engine()->throwTypeError(); return; } diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index b69d200665..5286be875b 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -172,7 +172,7 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData static ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); - static void markObjects(Managed *d, ExecutionEngine *e); + static void markObjects(HeapObject *d, ExecutionEngine *e); static ReturnedValue get(const ArrayData *d, uint index); static bool put(Object *o, uint index, ValueRef value); @@ -218,7 +218,7 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData } static void destroy(Managed *d); - static void markObjects(Managed *d, ExecutionEngine *e); + static void markObjects(HeapObject *d, ExecutionEngine *e); static ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); static ReturnedValue get(const ArrayData *d, uint index); diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 011279ae07..bbc0867c22 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -35,6 +35,7 @@ #include "qv4sparsearray_p.h" #include "qv4objectproto_p.h" #include "qv4scopedvalue_p.h" +#include "qv4runtime_p.h" using namespace QV4; @@ -57,7 +58,7 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData) len = callData->args[0].asArrayLength(&ok); if (!ok) - return v4->currentContext()->throwRangeError(callData->args[0]); + return v4->throwRangeError(callData->args[0]); if (len < 0x1000) a->arrayReserve(len); @@ -285,7 +286,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx) instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); else { ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); - return ctx->throwRangeError(str); + return ctx->engine()->throwRangeError(str); } return Encode(newLen); } @@ -690,7 +691,7 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, 3); callData->args[2] = instance; @@ -724,7 +725,7 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, 3); callData->thisObject = ctx->argument(1); @@ -758,7 +759,7 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, 3); callData->thisObject = ctx->argument(1); @@ -789,7 +790,7 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject()); a->arrayReserve(len); @@ -826,7 +827,7 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject()); a->arrayReserve(len); @@ -867,7 +868,7 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); uint k = 0; ScopedValue acc(scope); @@ -884,7 +885,7 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) ++k; } if (!kPresent) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } ScopedCallData callData(scope, 4); @@ -917,11 +918,11 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (len == 0) { if (ctx->d()->callData->argc == 1) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return ctx->argument(1); } @@ -939,7 +940,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) --k; } if (!kPresent) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } ScopedCallData callData(scope, 4); diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index b58fcbe709..17f638426a 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -78,7 +78,7 @@ ReturnedValue BooleanPrototype::method_toString(CallContext *ctx) Scope scope(ctx); Scoped<BooleanObject> thisObject(scope, ctx->d()->callData->thisObject); if (!thisObject) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); result = thisObject->value().booleanValue(); } @@ -93,7 +93,7 @@ ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx) Scope scope(ctx); Scoped<BooleanObject> thisObject(scope, ctx->d()->callData->thisObject); if (!thisObject) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return thisObject->value().asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 5ca47a80b1..2dc8e8b608 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -48,7 +48,7 @@ DEFINE_MANAGED_VTABLE(CallContext); DEFINE_MANAGED_VTABLE(WithContext); DEFINE_MANAGED_VTABLE(GlobalContext); -HeapObject *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) +Returned<CallContext> *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) { Q_ASSERT(function->function()); @@ -78,24 +78,25 @@ HeapObject *ExecutionContext::newCallContext(FunctionObject *function, CallData std::fill(c->callData->args + c->callData->argc, c->callData->args + compiledFunction->nFormals, Primitive::undefinedValue()); c->callData->argc = qMax((uint)callData->argc, compiledFunction->nFormals); - return c; + return Returned<CallContext>::create(c); } -WithContext *ExecutionContext::newWithContext(Object *with) +Returned<WithContext> *ExecutionContext::newWithContext(Object *with) { return d()->engine->memoryManager->alloc<WithContext>(d()->engine, with); } -CatchContext *ExecutionContext::newCatchContext(String *exceptionVarName, const ValueRef exceptionValue) +Returned<CatchContext> *ExecutionContext::newCatchContext(String *exceptionVarName, const ValueRef exceptionValue) { return d()->engine->memoryManager->alloc<CatchContext>(d()->engine, exceptionVarName, exceptionValue); } -CallContext *ExecutionContext::newQmlContext(FunctionObject *f, Object *qml) +Returned<CallContext> *ExecutionContext::newQmlContext(FunctionObject *f, Object *qml) { - CallContext *c = reinterpret_cast<CallContext*>(d()->engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0))); + Scope scope(this); + Scoped<CallContext> c(scope, static_cast<CallContext*>(d()->engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0)))); new (c->d()) CallContext::Data(d()->engine, qml, f); - return c; + return c.asReturned(); } @@ -236,7 +237,7 @@ bool ExecutionContext::deleteProperty(String *name) } if (d()->strictMode) - throwSyntaxError(QStringLiteral("Can't delete property %1").arg(name->toQString())); + engine()->throwSyntaxError(QStringLiteral("Can't delete property %1").arg(name->toQString())); return true; } @@ -245,35 +246,35 @@ bool CallContext::needsOwnArguments() const return d()->function->needsActivation() || d()->callData->argc < static_cast<int>(d()->function->formalParameterCount()); } -void ExecutionContext::markObjects(Managed *m, ExecutionEngine *engine) +void ExecutionContext::markObjects(HeapObject *m, ExecutionEngine *engine) { - ExecutionContext *ctx = static_cast<ExecutionContext *>(m); + ExecutionContext::Data *ctx = static_cast<ExecutionContext::Data *>(m); - if (ctx->d()->outer) - ctx->d()->outer->mark(engine); + if (ctx->outer) + ctx->outer->mark(engine); // ### shouldn't need these 3 lines - ctx->d()->callData->thisObject.mark(engine); - for (int arg = 0; arg < ctx->d()->callData->argc; ++arg) - ctx->d()->callData->args[arg].mark(engine); - - if (ctx->d()->type >= Type_CallContext) { - QV4::CallContext *c = static_cast<CallContext *>(ctx); - for (unsigned local = 0, lastLocal = c->d()->function->varCount(); local < lastLocal; ++local) - c->d()->locals[local].mark(engine); - if (c->d()->activation) - c->d()->activation->mark(engine); - c->d()->function->mark(engine); - } else if (ctx->d()->type == Type_WithContext) { - WithContext *w = static_cast<WithContext *>(ctx); - w->d()->withObject->mark(engine); - } else if (ctx->d()->type == Type_CatchContext) { - CatchContext *c = static_cast<CatchContext *>(ctx); - c->d()->exceptionVarName->mark(engine); - c->d()->exceptionValue.mark(engine); - } else if (ctx->d()->type == Type_GlobalContext) { - GlobalContext *g = static_cast<GlobalContext *>(ctx); - g->d()->global->mark(engine); + ctx->callData->thisObject.mark(engine); + for (int arg = 0; arg < ctx->callData->argc; ++arg) + ctx->callData->args[arg].mark(engine); + + if (ctx->type >= Type_CallContext) { + QV4::CallContext::Data *c = static_cast<CallContext::Data *>(ctx); + for (unsigned local = 0, lastLocal = c->function->varCount(); local < lastLocal; ++local) + c->locals[local].mark(engine); + if (c->activation) + c->activation->mark(engine); + c->function->mark(engine); + } else if (ctx->type == Type_WithContext) { + WithContext::Data *w = static_cast<WithContext::Data *>(ctx); + w->withObject->mark(engine); + } else if (ctx->type == Type_CatchContext) { + CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx); + c->exceptionVarName->mark(engine); + c->exceptionValue.mark(engine); + } else if (ctx->type == Type_GlobalContext) { + GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx); + g->global->mark(engine); } } @@ -327,7 +328,7 @@ void ExecutionContext::setProperty(String *name, const ValueRef value) } if (d()->strictMode || name->equals(d()->engine->id_this.getPointer())) { ScopedValue n(scope, name->asReturnedValue()); - throwReferenceError(n); + engine()->throwReferenceError(n); return; } d()->engine->globalObject->put(name, value); @@ -394,7 +395,7 @@ ReturnedValue ExecutionContext::getProperty(String *name) } } ScopedValue n(scope, name); - return throwReferenceError(n); + return engine()->throwReferenceError(n); } ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Object *&base) @@ -463,100 +464,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Object *&base) } } ScopedValue n(scope, name); - return throwReferenceError(n); -} - - -ReturnedValue ExecutionContext::throwError(const ValueRef value) -{ - return d()->engine->throwException(value); -} - -ReturnedValue ExecutionContext::throwError(const QString &message) -{ - Scope scope(this); - ScopedValue v(scope, d()->engine->newString(message)); - v = d()->engine->newErrorObject(v); - return throwError(v); -} - -ReturnedValue ExecutionContext::throwSyntaxError(const QString &message, const QString &fileName, int line, int column) -{ - Scope scope(this); - Scoped<Object> error(scope, d()->engine->newSyntaxErrorObject(message, fileName, line, column)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwSyntaxError(const QString &message) -{ - Scope scope(this); - Scoped<Object> error(scope, d()->engine->newSyntaxErrorObject(message)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwTypeError() -{ - Scope scope(this); - Scoped<Object> error(scope, d()->engine->newTypeErrorObject(QStringLiteral("Type error"))); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwTypeError(const QString &message) -{ - Scope scope(this); - Scoped<Object> error(scope, d()->engine->newTypeErrorObject(message)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwUnimplemented(const QString &message) -{ - Scope scope(this); - ScopedValue v(scope, d()->engine->newString(QStringLiteral("Unimplemented ") + message)); - v = d()->engine->newErrorObject(v); - return throwError(v); + return engine()->throwReferenceError(n); } ReturnedValue ExecutionContext::catchException(StackTrace *trace) { return d()->engine->catchException(this, trace); } - -ReturnedValue ExecutionContext::throwReferenceError(const ValueRef value) -{ - Scope scope(this); - Scoped<String> s(scope, value->toString(this)); - QString msg = s->toQString() + QStringLiteral(" is not defined"); - Scoped<Object> error(scope, d()->engine->newReferenceErrorObject(msg)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwReferenceError(const QString &message, const QString &fileName, int line, int column) -{ - Scope scope(this); - QString msg = message; - Scoped<Object> error(scope, d()->engine->newReferenceErrorObject(msg, fileName, line, column)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwRangeError(const ValueRef value) -{ - Scope scope(this); - ScopedString s(scope, value->toString(this)); - QString msg = s->toQString() + QStringLiteral(" out of range"); - ScopedObject error(scope, d()->engine->newRangeErrorObject(msg)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwRangeError(const QString &message) -{ - Scope scope(this); - ScopedObject error(scope, d()->engine->newRangeErrorObject(message)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwURIError(const ValueRef msg) -{ - Scope scope(this); - ScopedObject error(scope, d()->engine->newURIErrorObject(msg)); - return throwError(error); -} diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 74530e7ae9..a942c12f6c 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -42,20 +42,12 @@ QT_BEGIN_NAMESPACE namespace QV4 { -struct Object; -struct ExecutionEngine; -struct DeclarativeEnvironment; -struct Lookup; -struct Function; -struct ValueRef; - namespace CompiledData { struct CompilationUnit; struct Function; } struct CallContext; -struct CallContext; struct CatchContext; struct WithContext; @@ -127,26 +119,13 @@ struct Q_QML_EXPORT ExecutionContext : public Managed engine->current = this; } - HeapObject *newCallContext(FunctionObject *f, CallData *callData); - WithContext *newWithContext(Object *with); - CatchContext *newCatchContext(String *exceptionVarName, const ValueRef exceptionValue); - CallContext *newQmlContext(FunctionObject *f, Object *qml); + Returned<CallContext> *newCallContext(FunctionObject *f, CallData *callData); + Returned<WithContext> *newWithContext(Object *with); + Returned<CatchContext> *newCatchContext(String *exceptionVarName, const ValueRef exceptionValue); + Returned<CallContext> *newQmlContext(FunctionObject *f, Object *qml); void createMutableBinding(String *name, bool deletable); - ReturnedValue throwError(const QV4::ValueRef value); - ReturnedValue throwError(const QString &message); - ReturnedValue throwSyntaxError(const QString &message); - ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column); - ReturnedValue throwTypeError(); - ReturnedValue throwTypeError(const QString &message); - ReturnedValue throwReferenceError(const ValueRef value); - ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column); - ReturnedValue throwRangeError(const ValueRef value); - ReturnedValue throwRangeError(const QString &message); - ReturnedValue throwURIError(const ValueRef msg); - ReturnedValue throwUnimplemented(const QString &message); - void setProperty(String *name, const ValueRef value); ReturnedValue getProperty(String *name); ReturnedValue getPropertyAndBase(String *name, Object *&base); @@ -158,7 +137,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed inline CallContext *asCallContext(); inline const CallContext *asCallContext() const; - static void markObjects(Managed *m, ExecutionEngine *e); + static void markObjects(HeapObject *m, ExecutionEngine *e); }; struct CallContext : public ExecutionContext diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp new file mode 100644 index 0000000000..11cb04e22f --- /dev/null +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4dataview_p.h" +#include "qv4arraybuffer_p.h" + +#include "qendian.h" + +using namespace QV4; + +DEFINE_OBJECT_VTABLE(DataViewCtor); +DEFINE_OBJECT_VTABLE(DataView); + +DataViewCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("DataView")) +{ + setVTable(staticVTable()); +} + +ReturnedValue DataViewCtor::construct(Managed *m, CallData *callData) +{ + Scope scope(m->engine()); + Scoped<ArrayBuffer> buffer(scope, callData->argument(0)); + if (!buffer) + return scope.engine->throwTypeError(); + + double bo = callData->argc > 1 ? callData->args[1].toNumber() : 0; + uint byteOffset = (uint)bo; + uint bufferLength = buffer->d()->data->size; + double bl = callData->argc < 3 || callData->args[2].isUndefined() ? (bufferLength - bo) : callData->args[2].toNumber(); + uint byteLength = (uint)bl; + if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength) + return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range")); + + Scoped<DataView> a(scope, scope.engine->memoryManager->alloc<DataView>(scope.engine)); + a->d()->buffer = buffer; + a->d()->byteLength = byteLength; + a->d()->byteOffset = byteOffset; + return a.asReturnedValue(); + +} + +ReturnedValue DataViewCtor::call(Managed *that, CallData *callData) +{ + return construct(that, callData); +} + + +DataView::Data::Data(ExecutionEngine *e) + : Object::Data(e->dataViewClass), + buffer(0), + byteLength(0), + byteOffset(0) +{ +} + + +void DataView::markObjects(HeapObject *that, ExecutionEngine *e) +{ + DataView::Data *v = static_cast<DataView::Data *>(that); + v->buffer->mark(e); +} + +void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) +{ + Scope scope(engine); + ScopedObject o(scope); + ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); + defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); + defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); + + defineDefaultProperty(QStringLiteral("getInt8"), method_getChar<signed char>, 0); + defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("getInt16"), method_get<short>, 0); + defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("getInt32"), method_get<int>, 0); + defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("getFloat32"), method_getFloat<float>, 0); + defineDefaultProperty(QStringLiteral("getFloat64"), method_getFloat<double>, 0); + + defineDefaultProperty(QStringLiteral("setInt8"), method_setChar<signed char>, 0); + defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("setInt16"), method_set<short>, 0); + defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("setInt32"), method_set<int>, 0); + defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("setFloat32"), method_setFloat<float>, 0); + defineDefaultProperty(QStringLiteral("setFloat64"), method_setFloat<double>, 0); +} + +ReturnedValue DataViewPrototype::method_get_buffer(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->buffer->asReturnedValue()); +} + +ReturnedValue DataViewPrototype::method_get_byteLength(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->byteLength); +} + +ReturnedValue DataViewPrototype::method_get_byteOffset(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->byteOffset); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_getChar(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + T t = T(v->d()->buffer->d()->data->data()[idx]); + + return Encode((int)t); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_get(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + bool littleEndian = ctx->d()->callData->argc < 2 ? false : ctx->d()->callData->args[1].toBoolean(); + + T t = littleEndian + ? qFromLittleEndian<T>((uchar *)v->d()->buffer->d()->data->data() + idx) + : qFromBigEndian<T>((uchar *)v->d()->buffer->d()->data->data() + idx); + + return Encode(t); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + bool littleEndian = ctx->d()->callData->argc < 2 ? false : ctx->d()->callData->args[1].toBoolean(); + + if (sizeof(T) == 4) { + // float + union { + uint i; + float f; + } u; + u.i = littleEndian + ? qFromLittleEndian<uint>((uchar *)v->d()->buffer->d()->data->data() + idx) + : qFromBigEndian<uint>((uchar *)v->d()->buffer->d()->data->data() + idx); + return Encode(u.f); + } else { + Q_ASSERT(sizeof(T) == 8); + union { + quint64 i; + double d; + } u; + u.i = littleEndian + ? qFromLittleEndian<quint64>((uchar *)v->d()->buffer->d()->data->data() + idx) + : qFromBigEndian<quint64>((uchar *)v->d()->buffer->d()->data->data() + idx); + return Encode(u.d); + } +} + +template <typename T> +ReturnedValue DataViewPrototype::method_setChar(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + int val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toInt32() : 0; + v->d()->buffer->d()->data->data()[idx] = (char)val; + + return Encode::undefined(); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_set(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + int val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toInt32() : 0; + + bool littleEndian = ctx->d()->callData->argc < 3 ? false : ctx->d()->callData->args[2].toBoolean(); + + if (littleEndian) + qToLittleEndian<T>(val, (uchar *)v->d()->buffer->d()->data->data() + idx); + else + qToBigEndian<T>(val, (uchar *)v->d()->buffer->d()->data->data() + idx); + + return Encode::undefined(); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_setFloat(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + double val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toNumber() : qSNaN(); + bool littleEndian = ctx->d()->callData->argc < 3 ? false : ctx->d()->callData->args[2].toBoolean(); + + if (sizeof(T) == 4) { + // float + union { + uint i; + float f; + } u; + u.f = val; + if (littleEndian) + qToLittleEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + else + qToBigEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + } else { + Q_ASSERT(sizeof(T) == 8); + union { + quint64 i; + double d; + } u; + u.d = val; + if (littleEndian) + qToLittleEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + else + qToBigEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + } + return Encode::undefined(); +} diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h new file mode 100644 index 0000000000..b1c2e361f4 --- /dev/null +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4DATAVIEW_H +#define QV4DATAVIEW_H + +#include "qv4object_p.h" +#include "qv4functionobject_p.h" + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct ArrayBuffer; + +struct DataViewCtor: FunctionObject +{ + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + + V4_OBJECT(FunctionObject) + + static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue call(Managed *that, CallData *callData); +}; + +struct DataView : Object +{ + struct Data : Object::Data { + Data(ExecutionEngine *e); + ArrayBuffer *buffer; + uint byteLength; + uint byteOffset; + }; + V4_OBJECT(Object) + + static void markObjects(HeapObject *that, ExecutionEngine *e); +}; + +struct DataViewPrototype: Object +{ + void init(ExecutionEngine *engine, Object *ctor); + + static ReturnedValue method_get_buffer(CallContext *ctx); + static ReturnedValue method_get_byteLength(CallContext *ctx); + static ReturnedValue method_get_byteOffset(CallContext *ctx); + template <typename T> + static ReturnedValue method_getChar(CallContext *ctx); + template <typename T> + static ReturnedValue method_get(CallContext *ctx); + template <typename T> + static ReturnedValue method_getFloat(CallContext *ctx); + template <typename T> + static ReturnedValue method_setChar(CallContext *ctx); + template <typename T> + static ReturnedValue method_set(CallContext *ctx); + template <typename T> + static ReturnedValue method_setFloat(CallContext *ctx); +}; + + +} // namespace QV4 + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index e00a705700..25727166a5 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -35,6 +35,8 @@ #include "qv4dateobject_p.h" #include "qv4objectproto_p.h" #include "qv4scopedvalue_p.h" +#include "qv4runtime_p.h" + #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> #include <QtCore/QDateTime> @@ -762,7 +764,7 @@ double DatePrototype::getThisDate(ExecutionContext *ctx) if (DateObject *thisObject = ctx->d()->callData->thisObject.asDateObject()) return thisObject->date().asDouble(); else { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return 0; } } @@ -998,7 +1000,7 @@ ReturnedValue DatePrototype::method_setTime(CallContext *ctx) Scope scope(ctx); Scoped<DateObject> self(scope, ctx->d()->callData->thisObject); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); self->date().setDouble(TimeClip(t)); @@ -1010,7 +1012,7 @@ ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx) Scope scope(ctx); Scoped<DateObject> self(scope, ctx->d()->callData->thisObject); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double ms = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1022,7 +1024,7 @@ ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double ms = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1034,7 +1036,7 @@ ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double sec = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1048,7 +1050,7 @@ ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double sec = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1062,7 +1064,7 @@ ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double min = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1077,7 +1079,7 @@ ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double min = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1092,7 +1094,7 @@ ReturnedValue DatePrototype::method_setHours(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double hour = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1108,7 +1110,7 @@ ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double hour = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1124,7 +1126,7 @@ ReturnedValue DatePrototype::method_setDate(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double date = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1137,7 +1139,7 @@ ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double date = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1150,7 +1152,7 @@ ReturnedValue DatePrototype::method_setMonth(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double month = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1164,7 +1166,7 @@ ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double month = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1178,7 +1180,7 @@ ReturnedValue DatePrototype::method_setYear(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); if (std::isnan(t)) @@ -1204,7 +1206,7 @@ ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double year = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1219,7 +1221,7 @@ ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); if (std::isnan(t)) @@ -1236,7 +1238,7 @@ ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); return ctx->d()->engine->newString(ToUTCString(t))->asReturnedValue(); @@ -1259,11 +1261,11 @@ ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); if (!std::isfinite(t)) - return ctx->throwRangeError(ctx->d()->callData->thisObject); + return ctx->engine()->throwRangeError(ctx->d()->callData->thisObject); QString result; int year = (int)YearFromTime(t); @@ -1307,7 +1309,7 @@ ReturnedValue DatePrototype::method_toJSON(CallContext *ctx) FunctionObject *toIso = v->asFunctionObject(); if (!toIso) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, 0); callData->thisObject = ctx->d()->callData->thisObject; diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index bcf0d07719..c001b60295 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -38,6 +38,7 @@ #include "qv4instr_moth_p.h" #include "qv4runtime_p.h" #include "qv4script_p.h" +#include "qv4objectiterator_p.h" #include <iostream> #include <algorithm> diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index ea075f9cbd..c47420583c 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -61,6 +61,9 @@ #include "qv4qobjectwrapper_p.h" #include "qv4qmlextensions_p.h" #include "qv4memberdata_p.h" +#include "qv4arraybuffer_p.h" +#include "qv4dataview_p.h" +#include "qv4typedarray_p.h" #include <QtCore/QTextStream> #include <QDateTime> @@ -87,7 +90,7 @@ static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1); static ReturnedValue throwTypeError(CallContext *ctx) { - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } const int MinimumStackSize = 256; // in kbytes @@ -198,7 +201,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) // reserve space for the JS stack // we allow it to grow to 2 times JSStackLimit, as we can overshoot due to garbage collection // and ScopedValues allocated outside of JIT'ed methods. - *jsStack = WTF::PageAllocation::allocate(2*JSStackLimit, WTF::OSAllocator::JSVMStackPages, true); + *jsStack = WTF::PageAllocation::allocate(2 * JSStackLimit, WTF::OSAllocator::JSVMStackPages, + /* writable */ true, /* executable */ false, + /* includesGuardPages */ true); jsStackBase = (Value *)jsStack->base(); jsStackTop = jsStackBase; @@ -252,6 +257,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) id_toString = newIdentifier(QStringLiteral("toString")); id_destroy = newIdentifier(QStringLiteral("destroy")); id_valueOf = newIdentifier(QStringLiteral("valueOf")); + id_byteLength = newIdentifier(QStringLiteral("byteLength")); + id_byteOffset = newIdentifier(QStringLiteral("byteOffset")); + id_buffer = newIdentifier(QStringLiteral("buffer")); memberDataClass = InternalClass::create(this, MemberData::staticVTable(), 0); @@ -361,7 +369,27 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) static_cast<URIErrorPrototype *>(uRIErrorPrototype.getPointer())->init(this, uRIErrorCtor.asObject()); static_cast<VariantPrototype *>(variantPrototype.getPointer())->init(); - static_cast<SequencePrototype *>(sequencePrototype.managed())->init(); + sequencePrototype.cast<SequencePrototype>()->init(); + + + // typed arrays + + arrayBufferCtor = memoryManager->alloc<ArrayBufferCtor>(rootContext); + Scoped<ArrayBufferPrototype> arrayBufferPrototype(scope, memoryManager->alloc<ArrayBufferPrototype>(objectClass)); + arrayBufferPrototype->init(this, arrayBufferCtor.asObject()); + arrayBufferClass = InternalClass::create(this, ArrayBuffer::staticVTable(), arrayBufferPrototype); + + dataViewCtor = memoryManager->alloc<DataViewCtor>(rootContext); + Scoped<DataViewPrototype> dataViewPrototype(scope, memoryManager->alloc<DataViewPrototype>(objectClass)); + dataViewPrototype->init(this, dataViewCtor.asObject()); + dataViewClass = InternalClass::create(this, DataView::staticVTable(), dataViewPrototype); + + for (int i = 0; i < TypedArray::NTypes; ++i) { + typedArrayCtors[i] = memoryManager->alloc<TypedArrayCtor>(rootContext, TypedArray::Type(i)); + Scoped<TypedArrayPrototype> typedArrayPrototype(scope, memoryManager->alloc<TypedArrayPrototype>(this, TypedArray::Type(i))); + typedArrayPrototype->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].asObject())); + typedArrayClasses[i] = InternalClass::create(this, TypedArray::staticVTable(), typedArrayPrototype); + } // // set up the global object @@ -386,6 +414,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), syntaxErrorCtor); globalObject->defineDefaultProperty(QStringLiteral("TypeError"), typeErrorCtor); globalObject->defineDefaultProperty(QStringLiteral("URIError"), uRIErrorCtor); + + globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), arrayBufferCtor); + globalObject->defineDefaultProperty(QStringLiteral("DataView"), dataViewCtor); + ScopedString str(scope); + for (int i = 0; i < TypedArray::NTypes; ++i) + globalObject->defineDefaultProperty((str = typedArrayCtors[i].asFunctionObject()->name())->toQString(), typedArrayCtors[i]); ScopedObject o(scope); globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(QV4::InternalClass::create(this, MathObject::staticVTable(), objectPrototype)))); globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(QV4::InternalClass::create(this, JsonObject::staticVTable(), objectPrototype)))); @@ -410,7 +444,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1); Scoped<String> name(scope, newString(QStringLiteral("thrower"))); - thrower = ScopedFunctionObject(scope, BuiltinFunction::create(rootContext, name.getPointer(), throwTypeError)).getPointer(); + thrower = ScopedFunctionObject(scope, BuiltinFunction::create(rootContext, name.getPointer(), ::throwTypeError)).getPointer(); } ExecutionEngine::~ExecutionEngine() @@ -474,11 +508,12 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other) ExecutionContext *ExecutionEngine::pushGlobalContext() { - GlobalContext *g = memoryManager->alloc<GlobalContext>(this); + Scope scope(this); + Scoped<GlobalContext> g(scope, memoryManager->alloc<GlobalContext>(this)); g->d()->callData = rootContext->d()->callData; - Q_ASSERT(currentContext() == g); - return g; + Q_ASSERT(currentContext() == g.getPointer()); + return g.getPointer(); } @@ -665,10 +700,10 @@ Returned<Object> *ExecutionEngine::newVariantObject(const QVariant &v) return o->asReturned<Object>(); } -Returned<Object> *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ctx, Object *o) +Returned<Object> *ExecutionEngine::newForEachIteratorObject(Object *o) { Scope scope(this); - ScopedObject obj(scope, memoryManager->alloc<ForEachIteratorObject>(ctx, o)); + ScopedObject obj(scope, memoryManager->alloc<ForEachIteratorObject>(this, o)); return obj->asReturned<Object>(); } @@ -850,7 +885,7 @@ void ExecutionEngine::markObjects() Q_ASSERT(c->inUse()); if (!c->markBit()) { c->d()->markBit = 1; - c->markObjects(c, this); + c->markObjects(c->d(), this); } c = c->d()->parent; } @@ -887,6 +922,9 @@ void ExecutionEngine::markObjects() id_toString->mark(this); id_destroy->mark(this); id_valueOf->mark(this); + id_byteLength->mark(this); + id_byteOffset->mark(this); + id_buffer->mark(this); objectCtor.mark(this); stringCtor.mark(this); @@ -903,6 +941,10 @@ void ExecutionEngine::markObjects() syntaxErrorCtor.mark(this); typeErrorCtor.mark(this); uRIErrorCtor.mark(this); + arrayBufferCtor.mark(this); + dataViewCtor.mark(this); + for (int i = 0; i < TypedArray::NTypes; ++i) + typedArrayCtors[i].mark(this); sequencePrototype.mark(this); exceptionValue.mark(this); @@ -926,7 +968,7 @@ QmlExtensions *ExecutionEngine::qmlExtensions() return m_qmlExtensions; } -ReturnedValue ExecutionEngine::throwException(const ValueRef value) +ReturnedValue ExecutionEngine::throwError(const ValueRef value) { // we can get in here with an exception already set, as the runtime // doesn't check after every operation that can throw. @@ -964,6 +1006,92 @@ ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext, return res; } +ReturnedValue ExecutionEngine::throwError(const QString &message) +{ + Scope scope(this); + ScopedValue v(scope, newString(message)); + v = newErrorObject(v); + return throwError(v); +} + +ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message, const QString &fileName, int line, int column) +{ + Scope scope(this); + Scoped<Object> error(scope, newSyntaxErrorObject(message, fileName, line, column)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message) +{ + Scope scope(this); + Scoped<Object> error(scope, newSyntaxErrorObject(message)); + return throwError(error); +} + + +ReturnedValue ExecutionEngine::throwTypeError() +{ + Scope scope(this); + Scoped<Object> error(scope, newTypeErrorObject(QStringLiteral("Type error"))); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwTypeError(const QString &message) +{ + Scope scope(this); + Scoped<Object> error(scope, newTypeErrorObject(message)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwReferenceError(const ValueRef value) +{ + Scope scope(this); + Scoped<String> s(scope, value->toString(this)); + QString msg = s->toQString() + QStringLiteral(" is not defined"); + Scoped<Object> error(scope, newReferenceErrorObject(msg)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwReferenceError(const QString &message, const QString &fileName, int line, int column) +{ + Scope scope(this); + QString msg = message; + Scoped<Object> error(scope, newReferenceErrorObject(msg, fileName, line, column)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwRangeError(const QString &message) +{ + Scope scope(this); + ScopedObject error(scope, newRangeErrorObject(message)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwRangeError(const ValueRef value) +{ + Scope scope(this); + ScopedString s(scope, value->toString(this)); + QString msg = s->toQString() + QStringLiteral(" out of range"); + ScopedObject error(scope, newRangeErrorObject(msg)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwURIError(const ValueRef msg) +{ + Scope scope(this); + ScopedObject error(scope, newURIErrorObject(msg)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwUnimplemented(const QString &message) +{ + Scope scope(this); + ScopedValue v(scope, newString(QStringLiteral("Unimplemented ") + message)); + v = newErrorObject(v); + return throwError(v); +} + + QQmlError ExecutionEngine::catchExceptionAsQmlError(ExecutionContext *context) { QV4::StackTrace trace; diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index a4a40c2f41..1da54b1129 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -35,8 +35,7 @@ #include "qv4global_p.h" #include "private/qv4isel_p.h" -#include "qv4util_p.h" -#include "qv4property_p.h" +#include "qv4managed_p.h" #include <private/qintrusivelist_p.h> namespace WTF { @@ -113,7 +112,7 @@ struct ExecutionContextSaver; #define CHECK_STACK_LIMITS(v4) \ if ((v4->jsStackTop <= v4->jsStackLimit) && (reinterpret_cast<quintptr>(&v4) >= v4->cStackLimit || v4->recheckCStackLimits())) {} \ else \ - return v4->currentContext()->throwRangeError(QStringLiteral("Maximum call stack size exceeded.")) + return v4->throwRangeError(QStringLiteral("Maximum call stack size exceeded.")) struct Q_QML_EXPORT ExecutionEngine @@ -153,13 +152,13 @@ public: jsStackTop -= nValues; } - void pushForGC(Managed *m) { - *jsStackTop = Value::fromManaged(m); + void pushForGC(HeapObject *m) { + *jsStackTop = Value::fromHeapObject(m); ++jsStackTop; } - Managed *popForGC() { + HeapObject *popForGC() { --jsStackTop; - return jsStackTop->managed(); + return jsStackTop->heapObject(); } IdentifierTable *identifierTable; @@ -189,6 +188,10 @@ public: Value typeErrorCtor; Value uRIErrorCtor; Value sequencePrototype; + Value arrayBufferCtor; + Value dataViewCtor; + enum { NTypedArrayTypes = 9 }; // avoid header dependency + Value typedArrayCtors[NTypedArrayTypes]; InternalClassPool *classPool; InternalClass *emptyClass; @@ -224,6 +227,10 @@ public: InternalClass *variantClass; InternalClass *memberDataClass; + InternalClass *arrayBufferClass; + InternalClass *dataViewClass; + InternalClass *typedArrayClasses[NTypedArrayTypes]; // TypedArray::NValues, avoid including the header here + EvalFunction *evalFunction; FunctionObject *thrower; @@ -262,6 +269,9 @@ public: StringValue id_toString; StringValue id_destroy; StringValue id_valueOf; + StringValue id_byteLength; + StringValue id_byteOffset; + StringValue id_buffer; QSet<CompiledData::CompilationUnit*> compilationUnits; @@ -330,7 +340,7 @@ public: Returned<Object> *newVariantObject(const QVariant &v); - Returned<Object> *newForEachIteratorObject(ExecutionContext *ctx, Object *o); + Returned<Object> *newForEachIteratorObject(Object *o); Returned<Object> *qmlContextObject() const; @@ -354,9 +364,21 @@ public: Value exceptionValue; StackTrace exceptionStackTrace; - ReturnedValue throwException(const ValueRef value); + ReturnedValue throwError(const ValueRef value); ReturnedValue catchException(ExecutionContext *catchingContext, StackTrace *trace); + ReturnedValue throwError(const QString &message); + ReturnedValue throwSyntaxError(const QString &message); + ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column); + ReturnedValue throwTypeError(); + ReturnedValue throwTypeError(const QString &message); + ReturnedValue throwReferenceError(const ValueRef value); + ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column); + ReturnedValue throwRangeError(const ValueRef value); + ReturnedValue throwRangeError(const QString &message); + ReturnedValue throwURIError(const ValueRef msg); + ReturnedValue throwUnimplemented(const QString &message); + // Use only inside catch(...) -- will re-throw if no JS exception static QQmlError catchExceptionAsQmlError(QV4::ExecutionContext *context); @@ -364,6 +386,7 @@ private: QmlExtensions *m_qmlExtensions; }; +// ### Remove me inline void Managed::mark(QV4::ExecutionEngine *engine) { @@ -371,6 +394,17 @@ void Managed::mark(QV4::ExecutionEngine *engine) if (markBit()) return; d()->markBit = 1; + engine->pushForGC(d()); +} + + +inline +void HeapObject::mark(QV4::ExecutionEngine *engine) +{ + Q_ASSERT(inUse); + if (markBit) + return; + markBit = 1; engine->pushForGC(this); } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index d87083275d..ef664f2830 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -150,7 +150,7 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) Scope scope(ctx); Scoped<ErrorObject> This(scope, ctx->d()->callData->thisObject); if (!This) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (!This->d()->stack) { QString trace; for (int i = 0; i < This->d()->stackTrace.count(); ++i) { @@ -170,11 +170,11 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) return This->d()->stack->asReturnedValue(); } -void ErrorObject::markObjects(Managed *that, ExecutionEngine *e) +void ErrorObject::markObjects(HeapObject *that, ExecutionEngine *e) { - ErrorObject *This = that->asErrorObject(); - if (This->d()->stack) - This->d()->stack->mark(e); + ErrorObject::Data *This = static_cast<ErrorObject::Data *>(that); + if (This->stack) + This->stack->mark(e); Object::markObjects(that, e); } @@ -365,7 +365,7 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx) Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedValue name(scope, o->get(ctx->d()->engine->id_name)); QString qname; diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 47442ad985..ffbdafcc43 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -70,7 +70,7 @@ struct ErrorObject: Object { SyntaxErrorObject *asSyntaxError(); static ReturnedValue method_get_stack(CallContext *ctx); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); static void destroy(Managed *that) { static_cast<ErrorObject *>(that)->d()->~Data(); } }; diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index c7fe2128ce..6bc48157c0 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -58,7 +58,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, Scope scope(engine); ScopedString s(scope); for (int i = static_cast<int>(compiledFunction->nFormals - 1); i >= 0; --i) { - String *arg = compilationUnit->runtimeStrings[formalsIndices[i]].asString(); + String *arg = compilationUnit->runtimeStrings[formalsIndices[i]]; while (1) { InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable); if (newClass != internalClass) { @@ -72,7 +72,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const quint32 *localsIndices = compiledFunction->localsTable(); for (quint32 i = 0; i < compiledFunction->nLocals; ++i) { - String *local = compilationUnit->runtimeStrings[localsIndices[i]].asString(); + String *local = compilationUnit->runtimeStrings[localsIndices[i]]; internalClass = internalClass->addMember(local, Attr_NotConfigurable); } } diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 465489b83f..63bbb01e74 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -34,44 +34,12 @@ #define QV4FUNCTION_H #include "qv4global_p.h" - -#include <QtCore/QVector> -#include <QtCore/QByteArray> -#include <QtCore/qurl.h> - -#include "qv4value_p.h" #include <private/qv4compileddata_p.h> -#include <private/qv4engine_p.h> QT_BEGIN_NAMESPACE namespace QV4 { -struct String; -struct Function; -struct Object; -struct FunctionObject; -struct ExecutionContext; -struct ExecutionEngine; -class MemoryManager; - -struct ObjectPrototype; -struct StringPrototype; -struct NumberPrototype; -struct BooleanPrototype; -struct ArrayPrototype; -struct FunctionPrototype; -struct DatePrototype; -struct ErrorPrototype; -struct EvalErrorPrototype; -struct RangeErrorPrototype; -struct ReferenceErrorPrototype; -struct SyntaxErrorPrototype; -struct TypeErrorPrototype; -struct URIErrorPrototype; -struct InternalClass; -struct Lookup; - struct Q_QML_EXPORT Function { const CompiledData::Function *compiledFunction; CompiledData::CompilationUnit *compilationUnit; @@ -87,7 +55,7 @@ struct Q_QML_EXPORT Function { ~Function(); inline String *name() { - return compilationUnit->runtimeStrings[compiledFunction->nameIndex].getPointer(); + return compilationUnit->runtimeStrings[compiledFunction->nameIndex]; } inline QString sourceFile() const { return compilationUnit->fileName(); } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index f3ad8ef892..deb9e62591 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -48,15 +48,11 @@ #include <private/qqmljsast_p.h> #include <private/qqmlcontextwrapper_p.h> #include <private/qqmlengine_p.h> -#include <qv4jsir_p.h> #include <qv4codegen_p.h> #include "private/qlocale_tools_p.h" #include <QtCore/qmath.h> #include <QtCore/QDebug> -#include <cassert> -#include <typeinfo> -#include <iostream> #include <algorithm> #include "qv4alloca_p.h" #include "qv4profiling_p.h" @@ -147,7 +143,7 @@ ReturnedValue FunctionObject::newInstance() ReturnedValue FunctionObject::construct(Managed *that, CallData *) { - that->internalClass()->engine->currentContext()->throwTypeError(); + that->internalClass()->engine->throwTypeError(); return Encode::undefined(); } @@ -156,23 +152,23 @@ ReturnedValue FunctionObject::call(Managed *, CallData *) return Encode::undefined(); } -void FunctionObject::markObjects(Managed *that, ExecutionEngine *e) +void FunctionObject::markObjects(HeapObject *that, ExecutionEngine *e) { - FunctionObject *o = static_cast<FunctionObject *>(that); - if (o->scope()) - o->scope()->mark(e); + FunctionObject::Data *o = static_cast<FunctionObject::Data *>(that); + if (o->scope) + o->scope->mark(e); Object::markObjects(that, e); } -FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function, bool createProto) +Returned<FunctionObject> *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function, bool createProto) { if (function->needsActivation() || function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith || function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount || function->isNamedExpression()) - return scope->d()->engine->memoryManager->alloc<ScriptFunction>(scope, function); - return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto); + return scope->d()->engine->memoryManager->alloc<ScriptFunction>(scope, function)->as<FunctionObject>(); + return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto)->as<FunctionObject>(); } DEFINE_OBJECT_VTABLE(FunctionCtor); @@ -212,12 +208,12 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) const bool parsed = parser.parseExpression(); if (!parsed) - return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error")); + return v4->throwSyntaxError(QLatin1String("Parse error")); using namespace QQmlJS::AST; FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode()); if (!fe) - return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error")); + return v4->throwSyntaxError(QLatin1String("Parse error")); IR::Module module(v4->debugger != 0); @@ -266,7 +262,7 @@ ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) { FunctionObject *fun = ctx->d()->callData->thisObject.asFunctionObject(); if (!fun) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return ctx->d()->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue(); } @@ -276,7 +272,7 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) Scope scope(ctx); FunctionObject *o = ctx->d()->callData->thisObject.asFunctionObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedValue arg(scope, ctx->argument(1)); @@ -286,7 +282,7 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) if (!arr) { len = 0; if (!arg->isNullOrUndefined()) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } else { len = arr->getLength(); } @@ -318,7 +314,7 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) FunctionObject *o = ctx->d()->callData->thisObject.asFunctionObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, ctx->d()->callData->argc ? ctx->d()->callData->argc - 1 : 0); if (ctx->d()->callData->argc) { @@ -334,7 +330,7 @@ ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) Scope scope(ctx); Scoped<FunctionObject> target(scope, ctx->d()->callData->thisObject); if (!target) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedValue boundThis(scope, ctx->argument(0)); Members boundArgs; @@ -372,7 +368,7 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) ExecutionContext *context = v4->currentContext(); callData->thisObject = obj.asReturnedValue(); - ExecutionContext *ctx = reinterpret_cast<ExecutionContext *>(context->newCallContext(f.getPointer(), callData)); + Scoped<CallContext> ctx(scope, context->newCallContext(f.getPointer(), callData)); ExecutionContextSaver ctxSaver(context); ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function())); @@ -399,7 +395,7 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) ExecutionContext *context = v4->currentContext(); Scope scope(context); - CallContext *ctx = reinterpret_cast<CallContext *>(context->newCallContext(f, callData)); + Scoped<CallContext> ctx(scope, context->newCallContext(f, callData)); ExecutionContextSaver ctxSaver(context); ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function())); @@ -543,7 +539,7 @@ BuiltinFunction::Data::Data(ExecutionContext *scope, String *name, ReturnedValue ReturnedValue BuiltinFunction::construct(Managed *f, CallData *) { - return f->internalClass()->engine->currentContext()->throwTypeError(); + return f->internalClass()->engine->throwTypeError(); } ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) @@ -641,11 +637,11 @@ ReturnedValue BoundFunction::construct(Managed *that, CallData *dd) return f->target()->construct(callData); } -void BoundFunction::markObjects(Managed *that, ExecutionEngine *e) +void BoundFunction::markObjects(HeapObject *that, ExecutionEngine *e) { - BoundFunction *o = static_cast<BoundFunction *>(that); - o->target()->mark(e); - o->boundThis().mark(e); - o->boundArgs().mark(e); + BoundFunction::Data *o = static_cast<BoundFunction::Data *>(that); + o->target->mark(e); + o->boundThis.mark(e); + o->boundArgs.mark(e); FunctionObject::markObjects(that, e); } diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index c8edb765de..1ff8124e6a 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -33,59 +33,15 @@ #ifndef QV4FUNCTIONOBJECT_H #define QV4FUNCTIONOBJECT_H -#include "qv4global_p.h" -#include "qv4runtime_p.h" -#include "qv4engine_p.h" -#include "qv4context_p.h" #include "qv4object_p.h" -#include "qv4string_p.h" -#include "qv4managed_p.h" -#include "qv4property_p.h" #include "qv4function_p.h" -#include "qv4objectiterator_p.h" +#include "qv4context_p.h" #include "qv4mm_p.h" -#include <QtCore/QString> -#include <QtCore/QHash> -#include <QtCore/QScopedPointer> -#include <cstdio> -#include <cassert> - QT_BEGIN_NAMESPACE namespace QV4 { -struct Function; -struct Object; -struct BooleanObject; -struct NumberObject; -struct StringObject; -struct ArrayObject; -struct DateObject; -struct FunctionObject; -struct ErrorObject; -struct ArgumentsObject; -struct ExecutionContext; -struct ExecutionEngine; -class MemoryManager; - -struct ObjectPrototype; -struct StringPrototype; -struct NumberPrototype; -struct BooleanPrototype; -struct ArrayPrototype; -struct FunctionPrototype; -struct DatePrototype; -struct ErrorPrototype; -struct EvalErrorPrototype; -struct RangeErrorPrototype; -struct ReferenceErrorPrototype; -struct SyntaxErrorPrototype; -struct TypeErrorPrototype; -struct URIErrorPrototype; -struct InternalClass; -struct Lookup; - struct Q_QML_EXPORT FunctionObject: Object { struct Q_QML_PRIVATE_EXPORT Data : Object::Data { Data(ExecutionContext *scope, String *name, bool createProto = false); @@ -138,7 +94,7 @@ struct Q_QML_EXPORT FunctionObject: Object { return v.asFunctionObject(); } - static FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); + static Returned<FunctionObject> *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); ReturnedValue protoProperty() { return memberData()[Index_Prototype].asReturnedValue(); } @@ -146,7 +102,7 @@ struct Q_QML_EXPORT FunctionObject: Object { bool strictMode() const { return d()->strictMode; } bool bindingKeyFlag() const { return d()->bindingKeyFlag; } - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; template<> @@ -188,7 +144,7 @@ struct Q_QML_EXPORT BuiltinFunction: FunctionObject { }; V4_OBJECT(FunctionObject) - static BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) + static Returned<BuiltinFunction> *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) { return scope->engine()->memoryManager->alloc<BuiltinFunction>(scope, name, code); } @@ -214,7 +170,7 @@ struct IndexedBuiltinFunction: FunctionObject static ReturnedValue construct(Managed *m, CallData *) { - return m->engine()->currentContext()->throwTypeError(); + return m->engine()->throwTypeError(); } static ReturnedValue call(Managed *that, CallData *callData); @@ -253,7 +209,7 @@ struct BoundFunction: FunctionObject { }; V4_OBJECT(FunctionObject) - static BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const QV4::Members &boundArgs) + static Returned<BoundFunction> *create(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const QV4::Members &boundArgs) { return scope->engine()->memoryManager->alloc<BoundFunction>(scope, target, boundThis, boundArgs); } @@ -265,7 +221,7 @@ struct BoundFunction: FunctionObject { static ReturnedValue construct(Managed *, CallData *d); static ReturnedValue call(Managed *that, CallData *dd); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; } diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 81f1240d89..71f217395b 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -126,6 +126,10 @@ struct ScriptFunction; struct InternalClass; struct Property; struct Value; +struct Lookup; +struct HeapObject; +struct ArrayData; +struct ManagedVTable; struct BooleanObject; struct NumberObject; @@ -146,6 +150,7 @@ struct QObjectWrapper; // It will be returned in rax on x64, [eax,edx] on x86 and [r0,r1] on arm typedef quint64 ReturnedValue; struct CallData; +struct Scope; struct ScopedValue; struct ValueRef; template<typename T> struct Scoped; diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 49032e5bcf..e194460bfd 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -584,7 +584,7 @@ ReturnedValue GlobalFunctions::method_decodeURI(CallContext *context) if (!ok) { Scope scope(context); ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->throwURIError(s); + return context->engine()->throwURIError(s); } return context->d()->engine->newString(out)->asReturnedValue(); @@ -602,7 +602,7 @@ ReturnedValue GlobalFunctions::method_decodeURIComponent(CallContext *context) if (!ok) { Scope scope(context); ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->throwURIError(s); + return context->engine()->throwURIError(s); } return context->d()->engine->newString(out)->asReturnedValue(); @@ -620,7 +620,7 @@ ReturnedValue GlobalFunctions::method_encodeURI(CallContext *context) if (!ok) { Scope scope(context); ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->throwURIError(s); + return context->engine()->throwURIError(s); } return context->d()->engine->newString(out)->asReturnedValue(); @@ -638,7 +638,7 @@ ReturnedValue GlobalFunctions::method_encodeURIComponent(CallContext *context) if (!ok) { Scope scope(context); ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->throwURIError(s); + return context->engine()->throwURIError(s); } return context->d()->engine->newString(out)->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index d7ed7a8db0..5554b68db3 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -121,7 +121,8 @@ String *IdentifierTable::insertString(const QString &s) idx %= alloc; } - String *str = engine->newString(s)->getPointer(); + Returned<String> *_s = engine->newString(s); + String *str = _s->getPointer(); addEntry(str); return str; } diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h index 6ae2ec06d6..cc792fa3b4 100644 --- a/src/qml/jsruntime/qv4identifiertable_p.h +++ b/src/qml/jsruntime/qv4identifiertable_p.h @@ -78,7 +78,7 @@ public: continue; entry->d()->markBit = 1; Q_ASSERT(entry->internalClass()->vtable->markObjects); - entry->internalClass()->vtable->markObjects(entry, e); + entry->internalClass()->vtable->markObjects(entry->d(), e); } } }; diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 06feea1d5a..972c341992 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -33,9 +33,9 @@ #ifndef QV4INTERNALCLASS_H #define QV4INTERNALCLASS_H -#include <QHash> -#include <QVector> #include "qv4global_p.h" + +#include <QHash> #include <private/qqmljsmemorypool_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 268559dec8..74cf26c381 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -37,6 +37,8 @@ #include <qv4booleanobject_p.h> #include <qv4objectiterator_p.h> #include <qv4scopedvalue_p.h> +#include <qv4runtime_p.h> + #include <qjsondocument.h> #include <qstack.h> #include <qstringlist.h> @@ -775,7 +777,7 @@ QString Stringify::makeMember(const QString &key, ValueRef v) QString Stringify::JO(Object *o) { if (stack.contains(o)) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return QString(); } @@ -832,7 +834,7 @@ QString Stringify::JO(Object *o) QString Stringify::JA(ArrayObject *a) { if (stack.contains(a)) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return QString(); } @@ -898,7 +900,7 @@ ReturnedValue JsonObject::method_parse(CallContext *ctx) ScopedValue result(scope, parser.parse(&error)); if (error.error != QJsonParseError::NoError) { DEBUG << "parse error" << error.errorString(); - return ctx->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")); + return ctx->engine()->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")); } return result.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 254666eca2..f7ebb62b8d 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -130,7 +130,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const ValueRef object, co if (object->isNullOrUndefined()) { QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index->toQStringNoThrow()).arg(object->toQStringNoThrow()); - return ctx->throwTypeError(message); + return ctx->engine()->throwTypeError(message); } o = RuntimeHelpers::convertToObject(ctx, object); @@ -240,7 +240,7 @@ ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object) switch (object->type()) { case Value::Undefined_Type: case Value::Null_Type: - return engine->currentContext()->throwTypeError(); + return engine->throwTypeError(); case Value::Boolean_Type: proto = engine->booleanClass->prototype; break; @@ -598,7 +598,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionContext *ctx) } Scope scope(ctx); Scoped<String> n(scope, l->name); - return ctx->throwReferenceError(n); + return ctx->engine()->throwReferenceError(n); } ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionContext *ctx) diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index c7327addfd..93286b3945 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -157,7 +157,7 @@ void Managed::setVTable(const ManagedVTable *vt) d()->internalClass = internalClass()->changeVTable(vt); } -void Managed::Data::setVTable(const ManagedVTable *vt) +void HeapObject::setVTable(const ManagedVTable *vt) { Q_ASSERT(internalClass); internalClass = internalClass->changeVTable(vt); diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index e679017b7e..91dc0fb034 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -33,9 +33,6 @@ #ifndef QMLJS_MANAGED_H #define QMLJS_MANAGED_H -#include <QtCore/QString> -#include <QtCore/QVector> -#include <QtCore/QDebug> #include "qv4global_p.h" #include "qv4value_p.h" #include "qv4internalclass_p.h" @@ -45,7 +42,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { #define Q_MANAGED_CHECK \ - template <typename T> inline void qt_check_for_QMANAGED_macro(const T *_q_argument) const \ + template <typename _T> inline void qt_check_for_QMANAGED_macro(const _T *_q_argument) const \ { int i = qYouForgotTheQ_MANAGED_Macro(this, _q_argument); i = i + 1; } template <typename T> @@ -66,8 +63,8 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} typedef superClass SuperClass; \ static const QV4::ManagedVTable static_vtbl; \ static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl; } \ - template <typename T> \ - QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \ + template <typename _T> \ + QV4::Returned<_T> *asReturned() { return QV4::Returned<_T>::create(this); } \ V4_MANAGED_SIZE_TEST \ const Data *d() const { return &static_cast<const Data &>(Managed::data); } \ Data *d() { return &static_cast<Data &>(Managed::data); } @@ -78,8 +75,8 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} typedef superClass SuperClass; \ static const QV4::ObjectVTable static_vtbl; \ static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ - template <typename T> \ - QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \ + template <typename _T> \ + QV4::Returned<_T> *asReturned() { return QV4::Returned<_T>::create(this); } \ V4_MANAGED_SIZE_TEST \ const Data *d() const { return &static_cast<const Data &>(Managed::data); } \ Data *d() { return &static_cast<Data &>(Managed::data); } @@ -113,7 +110,7 @@ struct ManagedVTable uint type : 8; const char *className; void (*destroy)(Managed *); - void (*markObjects)(Managed *, ExecutionEngine *e); + void (*markObjects)(HeapObject *, ExecutionEngine *e); bool (*isEqualTo)(Managed *m, Managed *other); }; @@ -180,39 +177,10 @@ const QV4::ObjectVTable classname::static_vtbl = \ struct Q_QML_PRIVATE_EXPORT Managed { struct Q_QML_PRIVATE_EXPORT Data : HeapObject { - Data() {} + Data() : HeapObject(0) {} Data(InternalClass *internal) - : internalClass(internal) - , markBit(0) - , inUse(1) - , extensible(1) - { - // #### -// Q_ASSERT(internal && internal->vtable); - } - InternalClass *internalClass; - struct { - uchar markBit : 1; - uchar inUse : 1; - uchar extensible : 1; // used by Object - uchar _unused : 1; - uchar needsActivation : 1; // used by FunctionObject - uchar strictMode : 1; // used by FunctionObject - uchar bindingKeyFlag : 1; - uchar hasAccessorProperty : 1; - uchar _type; - mutable uchar subtype; - uchar _flags; - }; - - void setVTable(const ManagedVTable *vt); - ReturnedValue asReturnedValue() const { - return reinterpret_cast<Managed *>(const_cast<Data *>(this))->asReturnedValue(); - } - - void *operator new(size_t, Managed *m) { return m; } - void *operator new(size_t, Managed::Data *m) { return m; } - void operator delete(void *, Managed::Data *) {} + : HeapObject(internal) + {} }; Data data; V4_MANAGED(Managed) @@ -326,8 +294,8 @@ public: void setVTable(const ManagedVTable *vt); - bool isEqualTo(Managed *other) - { return internalClass()->vtable->isEqualTo(this, other); } + bool isEqualTo(const Managed *other) const + { return internalClass()->vtable->isEqualTo(const_cast<Managed *>(this), const_cast<Managed *>(other)); } static bool isEqualTo(Managed *m, Managed *other); @@ -377,6 +345,20 @@ inline FunctionObject *managed_cast(Managed *m) return m ? m->asFunctionObject() : 0; } +inline Value Value::fromManaged(Managed *m) +{ + if (!m) + return QV4::Primitive::undefinedValue(); + Value v; +#if QT_POINTER_SIZE == 8 + v.m = &m->data; +#else + v.tag = Managed_Type; + v.m = &m->data; +#endif + return v; +} + } diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 405594ca9b..de226305f1 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -38,11 +38,11 @@ using namespace QV4; DEFINE_MANAGED_VTABLE(MemberData); -void MemberData::markObjects(Managed *that, ExecutionEngine *e) +void MemberData::markObjects(HeapObject *that, ExecutionEngine *e) { - MemberData *m = static_cast<MemberData *>(that); - for (uint i = 0; i < m->d()->size; ++i) - m->d()->data[i].mark(e); + MemberData::Data *m = static_cast<MemberData::Data *>(that); + for (uint i = 0; i < m->size; ++i) + m->data[i].mark(e); } void Members::ensureIndex(QV4::ExecutionEngine *e, uint idx) @@ -57,6 +57,6 @@ void Members::ensureIndex(QV4::ExecutionEngine *e, uint idx) else new (newMemberData) MemberData(e->memberDataClass); newMemberData->d()->size = newAlloc; - m = newMemberData; + m = &newMemberData->data; } } diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 83732113a9..cc7b10ff81 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -54,7 +54,7 @@ struct MemberData : Managed MemberData(QV4::InternalClass *ic) : Managed(ic) {} Value &operator[] (uint idx) { return d()->data[idx]; } - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; struct Members : Value diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp index b9a4a55b4a..df439e1c5e 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/jsruntime/qv4mm.cpp @@ -264,9 +264,9 @@ Managed *MemoryManager::allocData(std::size_t size) static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) { while (engine->jsStackTop > markBase) { - Managed *m = engine->popForGC(); - Q_ASSERT (m->internalClass()->vtable->markObjects); - m->internalClass()->vtable->markObjects(m, engine); + HeapObject *h = engine->popForGC(); + Q_ASSERT (h->internalClass->vtable->markObjects); + h->internalClass->vtable->markObjects(h, engine); } } @@ -492,9 +492,9 @@ size_t MemoryManager::getUsedMem() const char *chunkStart = reinterpret_cast<char *>(i->memory.base()); char *chunkEnd = chunkStart + i->memory.size() - i->chunkSize; for (char *chunk = chunkStart; chunk <= chunkEnd; chunk += i->chunkSize) { - Managed *m = reinterpret_cast<Managed *>(chunk); + Managed::Data *m = reinterpret_cast<Managed::Data *>(chunk); Q_ASSERT((qintptr) chunk % 16 == 0); - if (m->inUse()) + if (m->inUse) usedMem += i->chunkSize; } } @@ -535,6 +535,11 @@ MemoryManager::~MemoryManager() #endif } +ExecutionEngine *MemoryManager::engine() const +{ + return m_d->engine; +} + void MemoryManager::setExecutionEngine(ExecutionEngine *engine) { m_d->engine = engine; diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h index d5e28f7f84..f2267e5852 100644 --- a/src/qml/jsruntime/qv4mm_p.h +++ b/src/qml/jsruntime/qv4mm_p.h @@ -35,10 +35,8 @@ #define QV4GC_H #include "qv4global_p.h" -#include "qv4context_p.h" #include "qv4value_inl_p.h" - -#include <QScopedPointer> +#include "qv4scopedvalue_p.h" //#define DETAILED_MM_STATS @@ -96,57 +94,64 @@ public: } template <typename ManagedType> - ManagedType *alloc() + Returned<ManagedType> *alloc() { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(); - return t; + return t.asReturned(); } template <typename ManagedType, typename Arg1> - ManagedType *alloc(Arg1 arg1) + Returned<ManagedType> *alloc(Arg1 arg1) { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(arg1); - return t; + return t.asReturned(); } template <typename ManagedType, typename Arg1, typename Arg2> - ManagedType *alloc(Arg1 arg1, Arg2 arg2) + Returned<ManagedType> *alloc(Arg1 arg1, Arg2 arg2) { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2); - return t; + return t.asReturned(); } template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3> - ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3) + Returned<ManagedType> *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3) { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3); - return t; + return t.asReturned(); } template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4> - ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) + Returned<ManagedType> *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4); - return t; + return t.asReturned(); } template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> - ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) + Returned<ManagedType> *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4, arg5); - return t; + return t.asReturned(); } bool isGCBlocked() const; void setGCBlocked(bool blockGC); void runGC(); + ExecutionEngine *engine() const; void setExecutionEngine(ExecutionEngine *engine); void dumpStats() const; diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 227ff14104..44826c94c8 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -32,6 +32,8 @@ ****************************************************************************/ #include "qv4numberobject_p.h" +#include "qv4runtime_p.h" + #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> #include <QtCore/QDebug> @@ -99,7 +101,7 @@ inline ReturnedValue thisNumberValue(ExecutionContext *ctx) return ctx->d()->callData->thisObject.asReturnedValue(); NumberObject *n = ctx->d()->callData->thisObject.asNumberObject(); if (!n) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return n->value().asReturnedValue(); } @@ -109,7 +111,7 @@ inline double thisNumber(ExecutionContext *ctx) return ctx->d()->callData->thisObject.asDouble(); NumberObject *n = ctx->d()->callData->thisObject.asNumberObject(); if (!n) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return n->value().asDouble(); } @@ -122,7 +124,7 @@ ReturnedValue NumberPrototype::method_toString(CallContext *ctx) if (ctx->d()->callData->argc && !ctx->d()->callData->args[0].isUndefined()) { int radix = ctx->d()->callData->args[0].toInt32(); if (radix < 2 || radix > 36) - return ctx->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix") + return ctx->engine()->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix") .arg(radix)); if (std::isnan(num)) { @@ -195,7 +197,7 @@ ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx) fdigits = 0; if (fdigits < 0 || fdigits > 20) - return ctx->throwRangeError(ctx->d()->callData->thisObject); + return ctx->engine()->throwRangeError(ctx->d()->callData->thisObject); QString str; if (std::isnan(v)) @@ -222,7 +224,7 @@ ReturnedValue NumberPrototype::method_toExponential(CallContext *ctx) fdigits = ctx->d()->callData->args[0].toInt32(); if (fdigits < 0 || fdigits > 20) { ScopedString error(scope, ctx->d()->engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range"))); - return ctx->throwRangeError(error); + return ctx->engine()->throwRangeError(error); } } @@ -247,7 +249,7 @@ ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx) double precision = ctx->d()->callData->args[0].toInt32(); if (precision < 1 || precision > 21) { ScopedString error(scope, ctx->d()->engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range"))); - return ctx->throwRangeError(error); + return ctx->engine()->throwRangeError(error); } char str[100]; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 0c61d666ab..576537dcef 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -41,22 +41,9 @@ #include "qv4lookup_p.h" #include "qv4scopedvalue_p.h" #include "qv4memberdata_p.h" +#include "qv4objectiterator_p.h" -#include <private/qqmljsengine_p.h> -#include <private/qqmljslexer_p.h> -#include <private/qqmljsparser_p.h> -#include <private/qqmljsast_p.h> -#include <qv4jsir_p.h> -#include <qv4codegen_p.h> -#include "private/qlocale_tools_p.h" - -#include <QtCore/qmath.h> -#include <QtCore/QDebug> -#include <cassert> -#include <typeinfo> -#include <iostream> #include <stdint.h> -#include "qv4alloca_p.h" using namespace QV4; @@ -130,7 +117,7 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef val reject: if (engine()->currentContext()->d()->strictMode) - engine()->currentContext()->throwTypeError(); + engine()->throwTypeError(); } void Object::defineDefaultProperty(const QString &name, ValueRef value) @@ -191,13 +178,13 @@ void Object::defineReadonlyProperty(String *name, ValueRef value) insertMember(name, value, Attr_ReadOnly); } -void Object::markObjects(Managed *that, ExecutionEngine *e) +void Object::markObjects(HeapObject *that, ExecutionEngine *e) { - Object *o = static_cast<Object *>(that); + Object::Data *o = static_cast<Object::Data *>(that); - o->memberData().mark(e); - if (o->arrayData()) - o->arrayData()->mark(e); + o->memberData.mark(e); + if (o->arrayData) + o->arrayData->mark(e); } void Object::ensureMemberIndex(uint idx) @@ -369,12 +356,12 @@ bool Object::hasOwnProperty(uint index) const ReturnedValue Object::construct(Managed *m, CallData *) { - return m->engine()->currentContext()->throwTypeError(); + return m->engine()->throwTypeError(); } ReturnedValue Object::call(Managed *m, CallData *) { - return m->engine()->currentContext()->throwTypeError(); + return m->engine()->throwTypeError(); } ReturnedValue Object::get(Managed *m, String *name, bool *hasProperty) @@ -678,7 +665,7 @@ void Object::internalPut(String *name, const ValueRef value) bool ok; uint l = value->asArrayLength(&ok); if (!ok) { - engine()->currentContext()->throwRangeError(value); + engine()->throwRangeError(value); return; } ok = setArrayLength(l); @@ -727,7 +714,7 @@ void Object::internalPut(String *name, const ValueRef value) QString message = QStringLiteral("Cannot assign to read-only property \""); message += name->toQString(); message += QLatin1Char('\"'); - engine()->currentContext()->throwTypeError(message); + engine()->throwTypeError(message); } } @@ -796,7 +783,7 @@ void Object::internalPutIndexed(uint index, const ValueRef value) reject: if (engine()->currentContext()->d()->strictMode) - engine()->currentContext()->throwTypeError(); + engine()->throwTypeError(); } // Section 8.12.7 @@ -818,7 +805,7 @@ bool Object::internalDeleteProperty(String *name) return true; } if (engine()->currentContext()->d()->strictMode) - engine()->currentContext()->throwTypeError(); + engine()->throwTypeError(); return false; } @@ -834,7 +821,7 @@ bool Object::internalDeleteIndexedProperty(uint index) return true; if (engine()->currentContext()->d()->strictMode) - engine()->currentContext()->throwTypeError(); + engine()->throwTypeError(); return false; } @@ -866,7 +853,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr uint l = p.value.asArrayLength(&ok); if (!ok) { ScopedValue v(scope, p.value); - ctx->throwRangeError(v); + ctx->engine()->throwRangeError(v); return false; } succeeded = setArrayLength(l); @@ -900,7 +887,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr return __defineOwnProperty__(ctx, memberIndex, name, p, attrs); reject: if (ctx->d()->strictMode) - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return false; } @@ -916,7 +903,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Prop return defineOwnProperty2(ctx, index, p, attrs); reject: if (ctx->d()->strictMode) - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return false; } @@ -952,7 +939,7 @@ bool Object::defineOwnProperty2(ExecutionContext *ctx, uint index, const Propert return __defineOwnProperty__(ctx, index, 0, p, attrs); reject: if (ctx->d()->strictMode) - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return false; } @@ -1045,7 +1032,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, String *me return true; reject: if (ctx->d()->strictMode) - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return false; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 4e9d1527c2..f11220f55c 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -30,70 +30,17 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef QMLJS_OBJECTS_H -#define QMLJS_OBJECTS_H - -#include "qv4global_p.h" -#include "qv4runtime_p.h" -#include "qv4engine_p.h" -#include "qv4context_p.h" -#include "qv4string_p.h" +#ifndef QV4_OBJECT_H +#define QV4_OBJECT_H + #include "qv4managed_p.h" -#include "qv4property_p.h" -#include "qv4internalclass_p.h" -#include "qv4arraydata_p.h" #include "qv4memberdata_p.h" - -#include <QtCore/QString> -#include <QtCore/QHash> -#include <QtCore/QScopedPointer> -#include <cstdio> -#include <cassert> - -#ifdef _WIN32_WCE -#undef assert -#define assert(x) -#endif // _WIN32_WCE +#include "qv4arraydata_p.h" QT_BEGIN_NAMESPACE namespace QV4 { -struct Function; -struct Lookup; -struct Object; -struct ObjectIterator; -struct BooleanObject; -struct NumberObject; -struct StringObject; -struct ArrayObject; -struct DateObject; -struct FunctionObject; -struct RegExpObject; -struct ErrorObject; -struct ArgumentsObject; -struct ExecutionContext; -struct CallContext; -struct ExecutionEngine; -class MemoryManager; - -struct ObjectPrototype; -struct StringPrototype; -struct NumberPrototype; -struct BooleanPrototype; -struct ArrayPrototype; -struct FunctionPrototype; -struct DatePrototype; -struct RegExpPrototype; -struct ErrorPrototype; -struct EvalErrorPrototype; -struct RangeErrorPrototype; -struct ReferenceErrorPrototype; -struct SyntaxErrorPrototype; -struct TypeErrorPrototype; -struct URIErrorPrototype; - - struct Q_QML_EXPORT Object: Managed { struct Data : Managed::Data { Data(ExecutionEngine *engine) @@ -277,7 +224,7 @@ public: inline ReturnedValue call(CallData *d) { return vtable()->call(this, d); } protected: - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); static ReturnedValue construct(Managed *m, CallData *); static ReturnedValue call(Managed *m, CallData *); static ReturnedValue get(Managed *m, String *name, bool *hasProperty); diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index f9038472df..e0f7087437 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -68,15 +68,15 @@ ObjectIterator::ObjectIterator(Value *scratch1, Value *scratch2, uint flags) , memberIndex(0) , flags(flags) { - object->o = (Object*)0; - current->o = (Object*)0; + object->m = 0; + current->m = 0; // Caller needs to call init! } void ObjectIterator::init(Object *o) { - object->o = o; - current->o = o; + object->m = o ? &o->data : 0; + current->m = o ? &o->data : 0; #if QT_POINTER_SIZE == 4 object->tag = QV4::Value::Managed_Type; @@ -125,10 +125,11 @@ void ObjectIterator::next(String *&name, uint *index, Property *pd, PropertyAttr return; } - if (flags & WithProtoChain) - current->o = current->objectValue()->prototype(); - else - current->o = (Object *)0; + if (flags & WithProtoChain) { + Object *proto = current->objectValue()->prototype(); + current->m = proto ? &proto->data : 0; + } else + current->m = (HeapObject *)0; arrayIndex = 0; memberIndex = 0; @@ -209,10 +210,10 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString() DEFINE_OBJECT_VTABLE(ForEachIteratorObject); -void ForEachIteratorObject::markObjects(Managed *that, ExecutionEngine *e) +void ForEachIteratorObject::markObjects(HeapObject *that, ExecutionEngine *e) { - ForEachIteratorObject *o = static_cast<ForEachIteratorObject *>(that); - o->d()->workArea[0].mark(e); - o->d()->workArea[1].mark(e); + ForEachIteratorObject::Data *o = static_cast<ForEachIteratorObject::Data *>(that); + o->workArea[0].mark(e); + o->workArea[1].mark(e); Object::markObjects(that, e); } diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index 3ed73b5c08..10f75a1e0d 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -34,24 +34,12 @@ #define QV4OBJECTITERATOR_H #include "qv4global_p.h" -#include "qv4property_p.h" -#include "qv4scopedvalue_p.h" #include "qv4object_p.h" QT_BEGIN_NAMESPACE namespace QV4 { -struct SparseArrayNode; -struct Object; -struct ArrayObject; -struct PropertyAttributes; -struct ExecutionContext; -struct Property; -struct String; -struct InternalClass; -struct ForEachIteratorObject; - struct Q_QML_EXPORT ObjectIterator { enum Flags { @@ -81,8 +69,8 @@ private: struct ForEachIteratorObject: Object { struct Data : Object::Data { - Data(ExecutionContext *ctx, Object *o) - : Object::Data(ctx->engine()) + Data(ExecutionEngine *engine, Object *o) + : Object::Data(engine) , it(workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) { setVTable(staticVTable()); } @@ -95,7 +83,7 @@ struct ForEachIteratorObject: Object { ReturnedValue nextPropertyName() { return d()->it.nextPropertyNameAsString(); } protected: - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 9cbf4b204e..5a4fe253e2 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -36,30 +36,13 @@ #include "qv4argumentsobject_p.h" #include "qv4mm_p.h" #include "qv4scopedvalue_p.h" +#include "qv4runtime_p.h" +#include "qv4objectiterator_p.h" + #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> #include <QtCore/QDateTime> #include <QtCore/QStringList> -#include <QtCore/QDebug> -#include <cassert> - -#include <private/qqmljsengine_p.h> -#include <private/qqmljslexer_p.h> -#include <private/qqmljsparser_p.h> -#include <private/qqmljsast_p.h> -#include <qv4jsir_p.h> -#include <qv4codegen_p.h> - -#ifndef Q_OS_WIN -# include <time.h> -# ifndef Q_OS_VXWORKS -# include <sys/time.h> -# else -# include "qplatformdefs.h" -# endif -#else -# include <windows.h> -#endif using namespace QV4; @@ -135,7 +118,7 @@ ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<Object> p(scope, o->prototype()); return !!p ? p->asReturnedValue() : Encode::null(); @@ -146,7 +129,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) Scope scope(ctx); Scoped<Object> O(scope, ctx->argument(0)); if (!O) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (ArgumentsObject::isNonStrictArgumentsObject(O.getPointer())) Scoped<ArgumentsObject>(scope, O)->fullyCreate(); @@ -165,7 +148,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context) Scope scope(context); ScopedObject O(scope, context->argument(0)); if (!O) - return context->throwTypeError(); + return context->engine()->throwTypeError(); ScopedArrayObject array(scope, getOwnPropertyNames(context->d()->engine, context->d()->callData->args[0])); return array.asReturnedValue(); @@ -176,7 +159,7 @@ ReturnedValue ObjectPrototype::method_create(CallContext *ctx) Scope scope(ctx); ScopedValue O(scope, ctx->argument(0)); if (!O->isObject() && !O->isNull()) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<Object> newObject(scope, ctx->d()->engine->newObject()); newObject->setPrototype(O->asObject()); @@ -194,7 +177,7 @@ ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx) Scope scope(ctx); Scoped<Object> O(scope, ctx->argument(0)); if (!O) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<String> name(scope, ctx->argument(1), Scoped<String>::Convert); if (scope.engine->hasException) @@ -208,7 +191,7 @@ ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx) return Encode::undefined(); if (!O->__defineOwnProperty__(ctx, name.getPointer(), pd, attrs)) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return O.asReturnedValue(); } @@ -218,7 +201,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) Scope scope(ctx); Scoped<Object> O(scope, ctx->argument(0)); if (!O) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<Object> o(scope, ctx->argument(1), Scoped<Object>::Convert); if (scope.engine->hasException) @@ -248,7 +231,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) else ok = O->__defineOwnProperty__(ctx, index, n, nattrs); if (!ok) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } return O.asReturnedValue(); @@ -259,7 +242,7 @@ ReturnedValue ObjectPrototype::method_seal(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); o->setExtensible(false); @@ -281,7 +264,7 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (ArgumentsObject::isNonStrictArgumentsObject(o.getPointer())) Scoped<ArgumentsObject>(scope, o)->fullyCreate(); @@ -307,7 +290,7 @@ ReturnedValue ObjectPrototype::method_preventExtensions(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); o->setExtensible(false); return o.asReturnedValue(); @@ -318,7 +301,7 @@ ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (o->isExtensible()) return Encode(false); @@ -347,7 +330,7 @@ ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (o->isExtensible()) return Encode(false); @@ -376,7 +359,7 @@ ReturnedValue ObjectPrototype::method_isExtensible(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return Encode((bool)o->isExtensible()); } @@ -386,7 +369,7 @@ ReturnedValue ObjectPrototype::method_keys(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject()); @@ -424,7 +407,7 @@ ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx) return Encode::undefined(); Scoped<FunctionObject> f(scope, o->get(ctx->d()->engine->id_toString)); if (!f) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, 0); callData->thisObject = o; return f->call(callData); @@ -491,12 +474,12 @@ ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx) ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) { if (ctx->d()->callData->argc < 2) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scope scope(ctx); Scoped<FunctionObject> f(scope, ctx->argument(1)); if (!f) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<String> prop(scope, ctx->argument(0), Scoped<String>::Convert); if (scope.engine->hasException) @@ -519,12 +502,12 @@ ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) { if (ctx->d()->callData->argc < 2) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scope scope(ctx); Scoped<FunctionObject> f(scope, ctx->argument(1)); if (!f) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<String> prop(scope, ctx->argument(0), Scoped<String>::Convert); if (scope.engine->hasException) @@ -549,7 +532,7 @@ ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx) Scope scope(ctx); ScopedObject o(scope, ctx->d()->callData->thisObject.asObject()); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return o->prototype()->asReturnedValue(); } @@ -559,7 +542,7 @@ ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->d()->callData->thisObject); if (!o || !ctx->d()->callData->argc) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (ctx->d()->callData->args[0].isNull()) { o->setPrototype(0); @@ -576,7 +559,7 @@ ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx) } } if (!ok) - return ctx->throwTypeError(QStringLiteral("Cyclic __proto__ value")); + return ctx->engine()->throwTypeError(QStringLiteral("Cyclic __proto__ value")); return Encode::undefined(); } @@ -585,7 +568,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef Scope scope(ctx); ScopedObject o(scope, v); if (!o) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return; } @@ -606,7 +589,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef if (f || get->isUndefined()) { desc->value = get; } else { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return; } attrs->setType(PropertyAttributes::Accessor); @@ -618,7 +601,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef if (f || set->isUndefined()) { desc->set = set; } else { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return; } attrs->setType(PropertyAttributes::Accessor); @@ -626,7 +609,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef if (o->hasProperty(ctx->d()->engine->id_writable)) { if (attrs->isAccessor()) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return; } attrs->setWritable((tmp = o->get(ctx->d()->engine->id_writable))->toBoolean()); @@ -636,7 +619,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef if (o->hasProperty(ctx->d()->engine->id_value)) { if (attrs->isAccessor()) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return; } desc->value = o->get(ctx->d()->engine->id_value); diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h index f9b3159033..601e3446f4 100644 --- a/src/qml/jsruntime/qv4property_p.h +++ b/src/qml/jsruntime/qv4property_p.h @@ -34,7 +34,7 @@ #define QV4PROPERTYDESCRIPTOR_H #include "qv4global_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4internalclass_p.h" QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index f2c30e618f..cf59fe027c 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -443,7 +443,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro if (!property->isWritable() && !property->isQList()) { QString error = QLatin1String("Cannot assign to read-only property \"") + property->name(object) + QLatin1Char('\"'); - ctx->throwTypeError(error); + ctx->engine()->throwTypeError(error); return; } @@ -459,7 +459,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(property->propType)); - ctx->throwError(error); + ctx->engine()->throwError(error); return; } } else { @@ -511,7 +511,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(property->propType)); - ctx->throwError(error); + ctx->engine()->throwError(error); return; } else if (value->asFunctionObject()) { // this is handled by the binding creation above @@ -560,7 +560,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro QLatin1String(valueType) + QLatin1String(" to ") + QLatin1String(targetTypeName); - ctx->throwError(error); + ctx->engine()->throwError(error); return; } } @@ -693,7 +693,7 @@ void QObjectWrapper::put(Managed *m, String *name, const ValueRef value) if (ddata && ddata->context) { QString error = QLatin1String("Cannot assign to non-existent property \"") + name->toQString() + QLatin1Char('\"'); - v4->currentContext()->throwError(error); + v4->throwError(error); } else { QV4::Object::put(m, name, value); } @@ -985,11 +985,11 @@ static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine * } } -void QObjectWrapper::markObjects(Managed *that, QV4::ExecutionEngine *e) +void QObjectWrapper::markObjects(HeapObject *that, QV4::ExecutionEngine *e) { - QObjectWrapper *This = static_cast<QObjectWrapper*>(that); + QObjectWrapper::Data *This = static_cast<QObjectWrapper::Data *>(that); - if (QObject *o = This->d()->object.data()) { + if (QObject *o = This->object.data()) { QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o); if (vme) vme->mark(e); @@ -1374,7 +1374,7 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d if (returnType == QMetaType::UnknownType) { QString typeName = QString::fromLatin1(unknownTypeError); QString error = QString::fromLatin1("Unknown method return type: %1").arg(typeName); - return QV8Engine::getV4(engine)->currentContext()->throwError(error); + return QV8Engine::getV4(engine)->throwError(error); } if (data.hasArguments()) { @@ -1388,12 +1388,12 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d if (!args) { QString typeName = QString::fromLatin1(unknownTypeError); QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName); - return QV8Engine::getV4(engine)->currentContext()->throwError(error); + return QV8Engine::getV4(engine)->throwError(error); } if (args[0] > callArgs->argc) { QString error = QLatin1String("Insufficient arguments"); - return QV8Engine::getV4(engine)->currentContext()->throwError(error); + return QV8Engine::getV4(engine)->throwError(error); } return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs); @@ -1492,7 +1492,7 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData candidate = RelatedMethod(object, candidate, dummy); } - return QV8Engine::getV4(engine)->currentContext()->throwError(error); + return QV8Engine::getV4(engine)->throwError(error); } } @@ -1793,7 +1793,7 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con if (!d()->object) return Encode::undefined(); if (QQmlData::keepAliveDuringGarbageCollection(d()->object)) - return ctx->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object")); + return ctx->engine()->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object")); int delay = 0; if (argc > 0) diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 1a31b5af4b..6458f03037 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -108,7 +108,7 @@ private: static void put(Managed *m, String *name, const ValueRef value); static PropertyAttributes query(const Managed *, String *name); static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes); - static void markObjects(Managed *that, QV4::ExecutionEngine *e); + static void markObjects(HeapObject *that, QV4::ExecutionEngine *e); static void destroy(Managed *that); static ReturnedValue method_connect(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index e84c96f417..659221b0d9 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -63,17 +63,18 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets) return JSC::Yarr::interpret(byteCode().get(), s.characters16(), string.length(), start, matchOffsets); } -RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline) +Returned<RegExp> *RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline) { RegExpCacheKey key(pattern, ignoreCase, multiline); RegExpCache *cache = engine->regExpCache; if (cache) { if (RegExp *result = cache->value(key)) - return result; + return Returned<RegExp>::create(result); } - RegExp *result = engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline); + Scope scope(engine); + Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline)); if (!cache) cache = engine->regExpCache = new RegExpCache; @@ -81,7 +82,7 @@ RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ign result->d()->cache = cache; cache->insert(key, result); - return result; + return result.asReturned(); } RegExp::Data::Data(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline) @@ -118,7 +119,7 @@ void RegExp::destroy(Managed *that) static_cast<RegExp*>(that)->d()->~Data(); } -void RegExp::markObjects(Managed *that, ExecutionEngine *e) +void RegExp::markObjects(HeapObject *that, ExecutionEngine *e) { Q_UNUSED(that); Q_UNUSED(e); diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index e2f43bf7d7..7aad1a32f2 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -85,7 +85,7 @@ struct RegExp : public Managed bool ignoreCase() const { return d()->ignoreCase; } bool multiLine() const { return d()->multiLine; } - static RegExp* create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false); + static Returned<RegExp> *create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false); bool isValid() const { return d()->byteCode.get(); } @@ -94,7 +94,7 @@ struct RegExp : public Managed int captureCount() const { return subPatternCount() + 1; } static void destroy(Managed *that); - static void markObjects(Managed *that, QV4::ExecutionEngine *e); + static void markObjects(HeapObject *that, QV4::ExecutionEngine *e); friend class RegExpCache; }; diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index c48175247e..23b46c8492 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -71,7 +71,7 @@ RegExpObject::Data::Data(InternalClass *ic) Scope scope(ic->engine); Scoped<RegExpObject> o(scope, this); - o->d()->value = reinterpret_cast<RegExp *>(RegExp::create(ic->engine, QString(), false, false)); + o->d()->value = RegExp::create(ic->engine, QString(), false, false)->getPointer(); o->d()->global = false; o->init(ic->engine); } @@ -139,7 +139,7 @@ RegExpObject::Data::Data(ExecutionEngine *engine, const QRegExp &re) Scope scope(engine); Scoped<RegExpObject> o(scope, this); - o->d()->value = reinterpret_cast<RegExp *>(RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false)); + o->d()->value = RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false)->getPointer(); o->init(engine); } @@ -170,11 +170,11 @@ void RegExpObject::init(ExecutionEngine *engine) } -void RegExpObject::markObjects(Managed *that, ExecutionEngine *e) +void RegExpObject::markObjects(HeapObject *that, ExecutionEngine *e) { - RegExpObject *re = static_cast<RegExpObject*>(that); - if (re->value()) - re->value()->mark(e); + RegExpObject::Data *re = static_cast<RegExpObject::Data *>(that); + if (re->value) + re->value->mark(e); Object::markObjects(that, e); } @@ -254,7 +254,7 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) Scoped<RegExpObject> re(scope, r); if (re) { if (!f->isUndefined()) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return Encode(ctx->d()->engine->newRegExpObject(re->value(), re->global())); } @@ -281,14 +281,14 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) } else if (str.at(i) == QLatin1Char('m') && !multiLine) { multiLine = true; } else { - return ctx->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor")); + return ctx->engine()->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor")); } } } - RegExp *regexp = reinterpret_cast<RegExp *>(RegExp::create(ctx->d()->engine, pattern, ignoreCase, multiLine)); + Scoped<RegExp> regexp(scope, RegExp::create(ctx->d()->engine, pattern, ignoreCase, multiLine)); if (!regexp->isValid()) - return ctx->throwSyntaxError(QStringLiteral("Invalid regular expression")); + return ctx->engine()->throwSyntaxError(QStringLiteral("Invalid regular expression")); return Encode(ctx->d()->engine->newRegExpObject(regexp, global)); } @@ -303,11 +303,11 @@ ReturnedValue RegExpCtor::call(Managed *that, CallData *callData) return construct(that, callData); } -void RegExpCtor::markObjects(Managed *that, ExecutionEngine *e) +void RegExpCtor::markObjects(HeapObject *that, ExecutionEngine *e) { - RegExpCtor *This = static_cast<RegExpCtor*>(that); - This->lastMatch().mark(e); - This->lastInput().mark(e); + RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that); + This->lastMatch.mark(e); + This->lastInput.mark(e); FunctionObject::markObjects(that, e); } @@ -353,7 +353,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) Scope scope(ctx); Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedValue arg(scope, ctx->argument(0)); arg = RuntimeHelpers::toString(ctx, arg); @@ -417,7 +417,7 @@ ReturnedValue RegExpPrototype::method_toString(CallContext *ctx) Scope scope(ctx); Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return ctx->d()->engine->newString(r->toString())->asReturnedValue(); } @@ -427,7 +427,7 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx) Scope scope(ctx); Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, ctx->d()->callData->argc); memcpy(callData->args, ctx->d()->callData->args, ctx->d()->callData->argc*sizeof(Value)); diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index e2f8049157..cf59ca12c0 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -91,7 +91,7 @@ struct RegExpObject: Object { uint flags() const; protected: - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; struct RegExpCtor: FunctionObject @@ -113,7 +113,7 @@ struct RegExpCtor: FunctionObject static ReturnedValue construct(Managed *m, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; struct RegExpPrototype: RegExpObject diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index f72f25bd58..b817bc594b 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -35,11 +35,11 @@ #include "qv4runtime_p.h" #ifndef V4_BOOTSTRAP #include "qv4object_p.h" -#include "qv4jsir_p.h" #include "qv4objectproto_p.h" #include "qv4globalobject_p.h" #include "qv4stringobject_p.h" #include "qv4argumentsobject_p.h" +#include "qv4objectiterator_p.h" #include "qv4lookup_p.h" #include "qv4function_p.h" #include "private/qlocale_tools_p.h" @@ -300,7 +300,7 @@ QV4::ReturnedValue Runtime::instanceof(ExecutionContext *ctx, const ValueRef lef FunctionObject *f = right->asFunctionObject(); if (!f) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (f->subtype() == FunctionObject::BoundFunction) f = static_cast<BoundFunction *>(f)->target(); @@ -311,7 +311,7 @@ QV4::ReturnedValue Runtime::instanceof(ExecutionContext *ctx, const ValueRef lef Object *o = QV4::Value::fromReturnedValue(f->protoProperty()).asObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); while (v) { v = v->prototype(); @@ -328,7 +328,7 @@ QV4::ReturnedValue Runtime::instanceof(ExecutionContext *ctx, const ValueRef lef QV4::ReturnedValue Runtime::in(ExecutionContext *ctx, const ValueRef left, const ValueRef right) { if (!right->isObject()) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scope scope(ctx); ScopedString s(scope, left->toString(ctx)); if (scope.hasException()) @@ -406,7 +406,7 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) return r->asReturnedValue(); } - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } @@ -417,7 +417,7 @@ Returned<Object> *RuntimeHelpers::convertToObject(ExecutionContext *ctx, const V switch (value->type()) { case Value::Undefined_Type: case Value::Null_Type: - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return 0; case Value::Boolean_Type: return ctx->engine()->newBooleanObject(value); @@ -571,7 +571,7 @@ ReturnedValue Runtime::getElement(ExecutionContext *ctx, const ValueRef object, if (object->isNullOrUndefined()) { QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index->toQStringNoThrow()).arg(object->toQStringNoThrow()); - return ctx->throwTypeError(message); + return ctx->engine()->throwTypeError(message); } o = RuntimeHelpers::convertToObject(ctx, object); @@ -625,8 +625,7 @@ ReturnedValue Runtime::foreachIterator(ExecutionContext *ctx, const ValueRef in) Scoped<Object> o(scope, (Object *)0); if (!in->isNullOrUndefined()) o = in->toObject(ctx); - Scoped<Object> it(scope, ctx->engine()->newForEachIteratorObject(ctx, o)); - return it.asReturnedValue(); + return ctx->engine()->newForEachIteratorObject(o)->asReturnedValue(); } ReturnedValue Runtime::foreachNextPropertyName(const ValueRef foreach_iterator) @@ -655,7 +654,7 @@ ReturnedValue Runtime::getProperty(ExecutionContext *ctx, const ValueRef object, if (object->isNullOrUndefined()) { QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString()).arg(object->toQStringNoThrow()); - return ctx->throwTypeError(message); + return ctx->engine()->throwTypeError(message); } o = RuntimeHelpers::convertToObject(ctx, object); @@ -721,7 +720,7 @@ Bool RuntimeHelpers::strictEqual(const ValueRef x, const ValueRef y) if (x->isNumber()) return y->isNumber() && x->asDouble() == y->asDouble(); if (x->isManaged()) - return y->isManaged() && x->managed()->isEqualTo(y->managed()); + return y->isManaged() && x->cast<Managed>()->isEqualTo(y->cast<Managed>()); return false; } @@ -858,6 +857,25 @@ QV4::Bool Runtime::compareLessEqual(const QV4::ValueRef l, const QV4::ValueRef r } #ifndef V4_BOOTSTRAP +Bool Runtime::compareInstanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right) +{ + TRACE2(left, right); + + Scope scope(ctx); + ScopedValue v(scope, Runtime::instanceof(ctx, left, right)); + return v->booleanValue(); +} + +uint Runtime::compareIn(ExecutionContext *ctx, const ValueRef left, const ValueRef right) +{ + TRACE2(left, right); + + Scope scope(ctx); + ScopedValue v(scope, Runtime::in(ctx, left, right)); + return v->booleanValue(); +} + + ReturnedValue Runtime::callGlobalLookup(ExecutionContext *context, uint index, CallData *callData) { Scope scope(context); @@ -866,7 +884,7 @@ ReturnedValue Runtime::callGlobalLookup(ExecutionContext *context, uint index, C Lookup *l = context->d()->lookups + index; Scoped<FunctionObject> o(scope, l->globalGetter(l, context)); if (!o) - return context->throwTypeError(); + return context->engine()->throwTypeError(); if (o.getPointer() == scope.engine->evalFunction && l->name->equals(scope.engine->id_eval)) return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true); @@ -881,7 +899,9 @@ ReturnedValue Runtime::callActivationProperty(ExecutionContext *context, String Scope scope(context); ScopedObject base(scope); - ScopedValue func(scope, context->getPropertyAndBase(name, base.ptr->o)); + Object *baseObj = 0; + ScopedValue func(scope, context->getPropertyAndBase(name, baseObj)); + base.ptr->m = baseObj ? &baseObj->data : 0; if (scope.engine->hasException) return Encode::undefined(); @@ -894,7 +914,7 @@ ReturnedValue Runtime::callActivationProperty(ExecutionContext *context, String if (base) objectAsString = ScopedValue(scope, base.asReturnedValue())->toQStringNoThrow(); QString msg = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString()).arg(objectAsString); - return context->throwTypeError(msg); + return context->engine()->throwTypeError(msg); } if (o == scope.engine->evalFunction && name->equals(scope.engine->id_eval)) { @@ -912,7 +932,7 @@ ReturnedValue Runtime::callProperty(ExecutionContext *context, String *name, Cal Q_ASSERT(!callData->thisObject.isEmpty()); if (callData->thisObject.isNullOrUndefined()) { QString message = QStringLiteral("Cannot call method '%1' of %2").arg(name->toQString()).arg(callData->thisObject.toQStringNoThrow()); - return context->throwTypeError(message); + return context->engine()->throwTypeError(message); } baseObject = RuntimeHelpers::convertToObject(context, ValueRef(&callData->thisObject)); @@ -924,7 +944,7 @@ ReturnedValue Runtime::callProperty(ExecutionContext *context, String *name, Cal Scoped<FunctionObject> o(scope, baseObject->get(name)); if (!o) { QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString(), callData->thisObject.toQStringNoThrow()); - return context->throwTypeError(error); + return context->engine()->throwTypeError(error); } return o->call(callData); @@ -936,7 +956,7 @@ ReturnedValue Runtime::callPropertyLookup(ExecutionContext *context, uint index, Value v; v = l->getter(l, callData->thisObject); if (!v.isObject()) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return v.objectValue()->call(callData); } @@ -953,7 +973,7 @@ ReturnedValue Runtime::callElement(ExecutionContext *context, const ValueRef ind ScopedObject o(scope, baseObject->get(s.getPointer())); if (!o) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return o->call(callData); } @@ -961,7 +981,7 @@ ReturnedValue Runtime::callElement(ExecutionContext *context, const ValueRef ind ReturnedValue Runtime::callValue(ExecutionContext *context, const ValueRef func, CallData *callData) { if (!func->isObject()) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return func->objectValue()->call(callData); } @@ -975,7 +995,7 @@ ReturnedValue Runtime::constructGlobalLookup(ExecutionContext *context, uint ind Lookup *l = context->d()->lookups + index; Scoped<Object> f(scope, l->globalGetter(l, context)); if (!f) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return f->construct(callData); } @@ -990,7 +1010,7 @@ ReturnedValue Runtime::constructActivationProperty(ExecutionContext *context, St Object *f = func->asObject(); if (!f) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return f->construct(callData); } @@ -999,7 +1019,7 @@ ReturnedValue Runtime::constructValue(ExecutionContext *context, const ValueRef { Object *f = func->asObject(); if (!f) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return f->construct(callData); } @@ -1013,7 +1033,7 @@ ReturnedValue Runtime::constructProperty(ExecutionContext *context, String *name Scoped<Object> f(scope, thisObject->get(name)); if (!f) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return f->construct(callData); } @@ -1024,7 +1044,7 @@ ReturnedValue Runtime::constructPropertyLookup(ExecutionContext *context, uint i Value v; v = l->getter(l, callData->thisObject); if (!v.isObject()) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return v.objectValue()->construct(callData); } @@ -1033,7 +1053,7 @@ ReturnedValue Runtime::constructPropertyLookup(ExecutionContext *context, uint i void Runtime::throwException(ExecutionContext *context, const ValueRef value) { if (!value->isEmpty()) - context->throwError(value); + context->engine()->throwError(value); } ReturnedValue Runtime::typeofValue(ExecutionContext *ctx, const ValueRef value) @@ -1099,7 +1119,7 @@ ExecutionContext *Runtime::pushWithScope(const ValueRef o, ExecutionContext *ctx { Scope scope(ctx); ScopedObject obj(scope, o->toObject(ctx)); - return reinterpret_cast<ExecutionContext *>(ctx->newWithContext(obj)); + return ctx->newWithContext(obj)->getPointer(); } ReturnedValue Runtime::unwindException(ExecutionContext *ctx) @@ -1113,7 +1133,7 @@ ExecutionContext *Runtime::pushCatchScope(ExecutionContext *ctx, String *excepti { Scope scope(ctx); ScopedValue v(scope, ctx->engine()->catchException(ctx, 0)); - return reinterpret_cast<ExecutionContext *>(ctx->newCatchContext(exceptionVarName, v)); + return ctx->newCatchContext(exceptionVarName, v)->getPointer(); } ExecutionContext *Runtime::popScope(ExecutionContext *ctx) @@ -1300,7 +1320,7 @@ ReturnedValue Runtime::getQmlQObjectProperty(ExecutionContext *ctx, const ValueR Scope scope(ctx); QV4::Scoped<QObjectWrapper> wrapper(scope, object); if (!wrapper) { - ctx->throwTypeError(QStringLiteral("Cannot read property of null")); + ctx->engine()->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } return QV4::QObjectWrapper::getProperty(wrapper->object(), ctx, propertyIndex, captureRequired); @@ -1323,7 +1343,7 @@ ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionContext *ctx, con Scope scope(ctx); QV4::Scoped<QmlTypeWrapper> wrapper(scope, object); if (!wrapper) { - ctx->throwTypeError(QStringLiteral("Cannot read property of null")); + scope.engine->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } return QV4::QObjectWrapper::getProperty(wrapper->singletonObject(), ctx, propertyIndex, captureRequired); @@ -1334,7 +1354,7 @@ void Runtime::setQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object Scope scope(ctx); QV4::Scoped<QObjectWrapper> wrapper(scope, object); if (!wrapper) { - ctx->throwTypeError(QStringLiteral("Cannot write property of null")); + ctx->engine()->throwTypeError(QStringLiteral("Cannot write property of null")); return; } wrapper->setProperty(ctx, propertyIndex, value); diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 6042420291..f69ea1620c 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -35,20 +35,11 @@ #include "qv4global_p.h" #include "qv4value_inl_p.h" -#include "qv4math_p.h" -#include "qv4scopedvalue_p.h" #include "qv4context_p.h" +#include "qv4math_p.h" -#include <QtCore/QString> #include <QtCore/qnumeric.h> -#include <QtCore/QDebug> -#include <QtCore/qurl.h> -#include <cmath> -#include <cassert> -#include <limits> - -//#include <wtf/MathExtras.h> QT_BEGIN_NAMESPACE @@ -470,7 +461,7 @@ inline Bool Runtime::compareEqual(const ValueRef left, const ValueRef right) if (!left->isManaged()) return false; if (left->isString() == right->isString()) - return left->managed()->isEqualTo(right->managed()); + return left->cast<Managed>()->isEqualTo(right->cast<Managed>()); } return RuntimeHelpers::equalHelper(left, right); @@ -529,27 +520,6 @@ inline Bool Runtime::compareStrictNotEqual(const ValueRef left, const ValueRef r return ! RuntimeHelpers::strictEqual(left, right); } -#ifndef V4_BOOTSTRAP -inline Bool Runtime::compareInstanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right) -{ - TRACE2(left, right); - - Scope scope(ctx); - ScopedValue v(scope, Runtime::instanceof(ctx, left, right)); - return v->booleanValue(); -} - -inline uint Runtime::compareIn(ExecutionContext *ctx, const ValueRef left, const ValueRef right) -{ - TRACE2(left, right); - - Scope scope(ctx); - ScopedValue v(scope, Runtime::in(ctx, left, right)); - return v->booleanValue(); -} - -#endif // V4_BOOTSTRAP - inline Bool Runtime::toBoolean(const ValueRef value) { return value->toBoolean(); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index b1b4d5da8d..90a3bf1602 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -36,6 +36,7 @@ #include "qv4engine_p.h" #include "qv4value_p.h" #include "qv4persistent_p.h" +#include "qv4property_p.h" QT_BEGIN_NAMESPACE @@ -112,7 +113,7 @@ struct ScopedValue ScopedValue(const Scope &scope, HeapObject *o) { ptr = scope.engine->jsStackTop++; - ptr->m = reinterpret_cast<Managed *>(o); + ptr->m = o; #if QT_POINTER_SIZE == 4 ptr->tag = QV4::Value::Managed_Type; #endif @@ -155,7 +156,7 @@ struct ScopedValue } ScopedValue &operator=(HeapObject *o) { - ptr->m = reinterpret_cast<Managed *>(o); + ptr->m = o; #if QT_POINTER_SIZE == 4 ptr->tag = QV4::Value::Managed_Type; #endif @@ -204,7 +205,7 @@ struct Scoped inline void setPointer(Managed *p) { #if QT_POINTER_SIZE == 8 - ptr->val = (quint64)p; + ptr->val = (quint64)(p ? &p->data : 0); #else *ptr = p ? QV4::Value::fromManaged(p) : QV4::Primitive::undefinedValue(); #endif @@ -230,7 +231,7 @@ struct Scoped Scoped(const Scope &scope, HeapObject *o) { Value v; - v.m = reinterpret_cast<Managed *>(o); + v.m = o; #if QT_POINTER_SIZE == 4 v.tag = QV4::Value::Managed_Type; #endif @@ -317,7 +318,7 @@ struct Scoped Scoped<T> &operator=(HeapObject *o) { Value v; - v.m = reinterpret_cast<Managed *>(o); + v.m = o; #if QT_POINTER_SIZE == 4 v.tag = QV4::Value::Managed_Type; #endif @@ -357,14 +358,14 @@ struct Scoped } T *operator->() { - return static_cast<T *>(ptr->managed()); + return ptr->cast<T>(); } bool operator!() const { - return !ptr->managed(); + return !ptr->m; } operator void *() const { - return ptr->managed(); + return ptr->m; } T *getPointer() { @@ -379,6 +380,8 @@ struct Scoped #endif } + Returned<T> *asReturned() const { return Returned<T>::create(static_cast<typename T::Data*>(ptr->heapObject())); } + Value *ptr; }; @@ -478,7 +481,7 @@ inline Returned<T> *Value::as() template<typename T> inline TypedValue<T> &TypedValue<T>::operator =(T *t) { - m = t; + m = t ? &t->data : 0; #if QT_POINTER_SIZE == 4 tag = Managed_Type; #endif @@ -488,7 +491,7 @@ inline TypedValue<T> &TypedValue<T>::operator =(T *t) template<typename T> inline TypedValue<T> &TypedValue<T>::operator =(const Scoped<T> &v) { - m = v.ptr->managed(); + m = v.ptr->m; #if QT_POINTER_SIZE == 4 tag = Managed_Type; #endif @@ -519,7 +522,7 @@ inline TypedValue<T> &TypedValue<T>::operator=(const TypedValue<T> &t) template<typename T> inline Returned<T> * TypedValue<T>::ret() const { - return Returned<T>::create(static_cast<T *>(managed())); + return Returned<T>::create(static_cast<typename T::Data *>(heapObject())); } inline Primitive::operator ValueRef() diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index fa4b4b1894..5c0c3f32ff 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -70,7 +70,7 @@ QmlBindingWrapper::Data::Data(ExecutionContext *scope, Function *f, Object *qml) o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); - o->d()->qmlContext = reinterpret_cast<CallContext *>(s.engine->currentContext()->newQmlContext(o, qml)); + o->d()->qmlContext = s.engine->currentContext()->newQmlContext(o, qml)->getPointer(); s.engine->popContext(); } @@ -88,7 +88,7 @@ QmlBindingWrapper::Data::Data(ExecutionContext *scope, Object *qml) o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); - o->d()->qmlContext = reinterpret_cast<CallContext *>(s.engine->currentContext()->newQmlContext(o, qml)); + o->d()->qmlContext = s.engine->currentContext()->newQmlContext(o, qml)->getPointer(); s.engine->popContext(); } @@ -111,14 +111,14 @@ ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *) return result.asReturnedValue(); } -void QmlBindingWrapper::markObjects(Managed *m, ExecutionEngine *e) +void QmlBindingWrapper::markObjects(HeapObject *m, ExecutionEngine *e) { - QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m); - if (wrapper->d()->qml) - wrapper->d()->qml->mark(e); + QmlBindingWrapper::Data *wrapper = static_cast<QmlBindingWrapper::Data *>(m); + if (wrapper->qml) + wrapper->qml->mark(e); FunctionObject::markObjects(m, e); - if (wrapper->d()->qmlContext) - wrapper->d()->qmlContext->mark(e); + if (wrapper->qmlContext) + wrapper->qmlContext->mark(e); } static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex) @@ -224,7 +224,7 @@ void Script::parse() foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) { if (m.isError()) { - scope->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn); + scope->engine()->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn); return; } else { qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn @@ -268,7 +268,7 @@ void Script::parse() if (!vmFunction) { // ### FIX file/line number Scoped<Object> error(valueScope, v4->newSyntaxErrorObject(QStringLiteral("Syntax error"))); - v4->currentContext()->throwError(error); + v4->throwError(error); } } diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index ed93ce49ae..f12d5ad6fc 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -82,7 +82,7 @@ struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { V4_OBJECT(FunctionObject) static ReturnedValue call(Managed *that, CallData *); - static void markObjects(Managed *m, ExecutionEngine *e); + static void markObjects(HeapObject *m, ExecutionEngine *e); CallContext *context() const { return d()->qmlContext; } diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 83bfb65658..c63e634025 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -39,7 +39,8 @@ #include <private/qv4arrayobject_p.h> #include <private/qqmlengine_p.h> #include <private/qv4scopedvalue_p.h> -#include <private/qv4internalclass_p.h> +#include "qv4runtime_p.h" +#include "qv4objectiterator_p.h" #include <algorithm> @@ -401,7 +402,7 @@ public: QV4::Scope scope(ctx); QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->d()->callData->thisObject.as<QQmlSequence<Container> >()); if (!This) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (This->d()->isReference) { if (!This->d()->object) @@ -416,7 +417,7 @@ public: QV4::Scope scope(ctx); QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->d()->callData->thisObject.as<QQmlSequence<Container> >()); if (!This) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); quint32 newLength = ctx->d()->callData->args[0].toUInt32(); /* Qt containers have int (rather than uint) allowable indexes. */ @@ -544,7 +545,7 @@ QV4::ReturnedValue SequencePrototype::method_sort(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::ScopedObject o(scope, ctx->d()->callData->thisObject); if (!o || !o->isListType()) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (ctx->d()->callData->argc >= 2) return o.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index be348e524c..c0848ec0ba 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -50,6 +50,7 @@ #include "qv4value_inl_p.h" #include "qv4object_p.h" +#include "qv4context_p.h" QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index bd8a5ffccb..4ae10f6506 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -122,12 +122,12 @@ void String::destroy(Managed *that) static_cast<String*>(that)->d()->~Data(); } -void String::markObjects(Managed *that, ExecutionEngine *e) +void String::markObjects(HeapObject *that, ExecutionEngine *e) { - String *s = static_cast<String *>(that); - if (s->d()->largestSubLength) { - s->d()->left->mark(e); - s->d()->right->mark(e); + String::Data *s = static_cast<String::Data *>(that); + if (s->largestSubLength) { + s->left->mark(e); + s->right->mark(e); } } diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index ce0e1f9d73..1e53132fe3 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -154,7 +154,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { protected: static void destroy(Managed *); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); static ReturnedValue get(Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); static void put(Managed *m, String *name, const ValueRef value); @@ -171,20 +171,6 @@ public: static uint toArrayIndex(const QString &str); }; -#ifndef V4_BOOTSTRAP -template<> -inline String *value_cast(const Value &v) { - return v.asString(); -} - -template<> -inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) -{ - return v.toString(e)->asReturnedValue(); -} - -#endif - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 397a6efdf8..19ef7892ad 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -109,13 +109,13 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index) Scope scope(v4); Scoped<StringObject> o(scope, m->asStringObject()); if (!o) { - v4->currentContext()->throwTypeError(); + v4->throwTypeError(); return false; } if (index < static_cast<uint>(o->d()->value.stringValue()->toQString().length())) { if (v4->currentContext()->d()->strictMode) - v4->currentContext()->throwTypeError(); + v4->throwTypeError(); return false; } return true; @@ -149,11 +149,11 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, String *&name return Object::advanceIterator(m, it, name, index, p, attrs); } -void StringObject::markObjects(Managed *that, ExecutionEngine *e) +void StringObject::markObjects(HeapObject *that, ExecutionEngine *e) { - StringObject *o = static_cast<StringObject *>(that); - o->d()->value.stringValue()->mark(e); - o->d()->tmpProperty.value.mark(e); + StringObject::Data *o = static_cast<StringObject::Data *>(that); + o->value.stringValue()->mark(e); + o->tmpProperty.value.mark(e); Object::markObjects(that, e); } @@ -230,7 +230,7 @@ static QString getThisString(ExecutionContext *ctx) if (StringObject *thisString = t->asStringObject()) return thisString->d()->value.stringValue()->toQString(); if (t->isUndefined() || t->isNull()) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return QString(); } return t->toQString(); @@ -243,7 +243,7 @@ ReturnedValue StringPrototype::method_toString(CallContext *context) StringObject *o = context->d()->callData->thisObject.asStringObject(); if (!o) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return o->d()->value.asReturnedValue(); } @@ -365,7 +365,7 @@ ReturnedValue StringPrototype::method_localeCompare(CallContext *context) ReturnedValue StringPrototype::method_match(CallContext *context) { if (context->d()->callData->thisObject.isUndefined() || context->d()->callData->thisObject.isNull()) - return context->throwTypeError(); + return context->engine()->throwTypeError(); Scope scope(context); ScopedString s(scope, context->d()->callData->thisObject.toString(context)); @@ -380,7 +380,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context) if (!rx) // ### CHECK - return context->throwTypeError(); + return context->engine()->throwTypeError(); bool global = rx->global(); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 5d3c0c9ccb..28e944c791 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -59,7 +59,7 @@ struct StringObject: Object { protected: static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; struct StringCtor: FunctionObject diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp new file mode 100644 index 0000000000..72823efa12 --- /dev/null +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -0,0 +1,572 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qv4typedarray_p.h" +#include "qv4arraybuffer_p.h" + +using namespace QV4; + +DEFINE_OBJECT_VTABLE(TypedArrayCtor); +DEFINE_OBJECT_VTABLE(TypedArrayPrototype); +DEFINE_OBJECT_VTABLE(TypedArray); + +Q_STATIC_ASSERT((int)ExecutionEngine::NTypedArrayTypes == (int)TypedArray::NTypes); + +ReturnedValue Int8ArrayRead(const char *data, int index) +{ + return Encode((int)(signed char)data[index]); +} + +void Int8ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + signed char v = (signed char)value->toUInt32(); + if (e->hasException) + return; + data[index] = v; +} + +ReturnedValue UInt8ArrayRead(const char *data, int index) +{ + return Encode((int)(unsigned char)data[index]); +} + +void UInt8ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + unsigned char v = (unsigned char)value->toUInt32(); + if (e->hasException) + return; + data[index] = v; +} + +void UInt8ClampedArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + if (value->isInteger()) { + data[index] = (char)(unsigned char)qBound(0, value->integerValue(), 255); + return; + } + double d = value->toNumber(); + if (e->hasException) + return; + // ### is there a way to optimise this? + if (d <= 0 || std::isnan(d)) { + data[index] = 0; + return; + } + if (d >= 255) { + data[index] = 255; + return; + } + double f = floor(d); + if (f + 0.5 < d) { + data[index] = (unsigned char)(f + 1); + return; + } + if (d < f + 0.5) { + data[index] = (unsigned char)(f); + return; + } + if (int(f) % 2) { + // odd number + data[index] = (unsigned char)(f + 1); + return; + } + data[index] = (unsigned char)(f); +} + +ReturnedValue Int16ArrayRead(const char *data, int index) +{ + return Encode((int)*(short *)(data + index)); +} + +void Int16ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + short v = (short)value->toInt32(); + if (e->hasException) + return; + *(short *)(data + index) = v; +} + +ReturnedValue UInt16ArrayRead(const char *data, int index) +{ + return Encode((int)*(unsigned short *)(data + index)); +} + +void UInt16ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + unsigned short v = (unsigned short)value->toInt32(); + if (e->hasException) + return; + *(unsigned short *)(data + index) = v; +} + +ReturnedValue Int32ArrayRead(const char *data, int index) +{ + return Encode(*(int *)(data + index)); +} + +void Int32ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + int v = (int)value->toInt32(); + if (e->hasException) + return; + *(int *)(data + index) = v; +} + +ReturnedValue UInt32ArrayRead(const char *data, int index) +{ + return Encode(*(unsigned int *)(data + index)); +} + +void UInt32ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + unsigned int v = (unsigned int)value->toUInt32(); + if (e->hasException) + return; + *(unsigned int *)(data + index) = v; +} + +ReturnedValue Float32ArrayRead(const char *data, int index) +{ + return Encode(*(float *)(data + index)); +} + +void Float32ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + float v = value->toNumber(); + if (e->hasException) + return; + *(float *)(data + index) = v; +} + +ReturnedValue Float64ArrayRead(const char *data, int index) +{ + return Encode(*(double *)(data + index)); +} + +void Float64ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + double v = value->toNumber(); + if (e->hasException) + return; + *(double *)(data + index) = v; +} + +const TypedArrayOperations operations[TypedArray::NTypes] = { + { 1, "Int8Array", Int8ArrayRead, Int8ArrayWrite }, + { 1, "Uint8Array", UInt8ArrayRead, UInt8ArrayWrite }, + { 1, "Uint8ClampedArray", UInt8ArrayRead, UInt8ClampedArrayWrite }, + { 2, "Int16Array", Int16ArrayRead, Int16ArrayWrite }, + { 2, "Uint16Array", UInt16ArrayRead, UInt16ArrayWrite }, + { 4, "Int32Array", Int32ArrayRead, Int32ArrayWrite }, + { 4, "Uint32Array", UInt32ArrayRead, UInt32ArrayWrite }, + { 4, "Float32Array", Float32ArrayRead, Float32ArrayWrite }, + { 8, "Float64Array", Float64ArrayRead, Float64ArrayWrite }, +}; + + +TypedArrayCtor::Data::Data(ExecutionContext *scope, TypedArray::Type t) + : FunctionObject::Data(scope, QLatin1String(operations[t].name)) + , type(t) +{ + setVTable(staticVTable()); +} + +ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) +{ + Scope scope(m->engine()); + Scoped<TypedArrayCtor> that(scope, static_cast<TypedArrayCtor *>(m)); + + if (!callData->argc || !callData->args[0].isObject()) { + // ECMA 6 22.2.1.1 + double l = callData->argc ? callData->args[0].toNumber() : 0; + if (scope.engine->hasException) + return Encode::undefined(); + uint len = (uint)l; + if (l != len) + scope.engine->throwRangeError(QStringLiteral("Non integer length for typed array.")); + uint byteLength = len * operations[that->d()->type].bytesPerElement; + Scoped<ArrayBuffer> buffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, byteLength)); + if (scope.engine->hasException) + return Encode::undefined(); + + Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + array->d()->buffer = buffer; + array->d()->byteLength = byteLength; + array->d()->byteOffset = 0; + + return array.asReturnedValue(); + } + Scoped<TypedArray> typedArray(scope, callData->argument(0)); + if (!!typedArray) { + // ECMA 6 22.2.1.2 + Scoped<ArrayBuffer> buffer(scope, typedArray->d()->buffer); + uint srcElementSize = typedArray->d()->type->bytesPerElement; + uint destElementSize = operations[that->d()->type].bytesPerElement; + uint byteLength = typedArray->d()->byteLength; + uint destByteLength = byteLength*destElementSize/srcElementSize; + + Scoped<ArrayBuffer> newBuffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, destByteLength)); + if (scope.engine->hasException) + return Encode::undefined(); + + Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + array->d()->buffer = newBuffer; + array->d()->byteLength = destByteLength; + array->d()->byteOffset = 0; + + const char *src = buffer->d()->data->data() + typedArray->d()->byteOffset; + char *dest = newBuffer->d()->data->data(); + + // check if src and new type have the same size. In that case we can simply memcpy the data + if (srcElementSize == destElementSize) { + memcpy(dest, src, byteLength); + } else { + // not same size, we need to loop + uint l = typedArray->length(); + TypedArrayRead read = typedArray->d()->type->read; + TypedArrayWrite write =array->d()->type->write; + for (uint i = 0; i < l; ++i) { + Primitive val; + val.val = read(src, i*srcElementSize); + write(scope.engine, dest, i*destElementSize, val); + } + } + + return array.asReturnedValue(); + } + Scoped<ArrayBuffer> buffer(scope, callData->argument(0)); + if (!!buffer) { + // ECMA 6 22.2.1.4 + + double dbyteOffset = callData->argc > 1 ? callData->args[1].toInteger() : 0; + uint byteOffset = (uint)dbyteOffset; + uint elementSize = operations[that->d()->type].bytesPerElement; + if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->byteLength()) + return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset")); + + uint byteLength; + if (callData->argc < 3 || callData->args[2].isUndefined()) { + byteLength = buffer->byteLength() - byteOffset; + if (buffer->byteLength() < byteOffset || byteLength % elementSize) + return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length")); + } else { + double l = qBound(0., callData->args[2].toInteger(), (double)UINT_MAX); + if (scope.engine->hasException) + return Encode::undefined(); + l *= elementSize; + if (buffer->byteLength() - byteOffset < l) + return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length")); + byteLength = (uint)l; + } + + Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + array->d()->buffer = buffer; + array->d()->byteLength = byteLength; + array->d()->byteOffset = byteOffset; + return array.asReturnedValue(); + } + + // ECMA 6 22.2.1.3 + + ScopedObject o(scope, callData->argument(0)); + uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length))->toInteger(), (double)UINT_MAX); + if (scope.engine->hasException) + return scope.engine->throwTypeError(); + + uint elementSize = operations[that->d()->type].bytesPerElement; + Scoped<ArrayBuffer> newBuffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, l * elementSize)); + if (scope.engine->hasException) + return Encode::undefined(); + + Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + array->d()->buffer = newBuffer; + array->d()->byteLength = l * elementSize; + array->d()->byteOffset = 0; + + uint idx = 0; + char *b = newBuffer->d()->data->data(); + ScopedValue val(scope); + while (idx < l) { + val = o->getIndexed(idx); + array->d()->type->write(scope.engine, b, 0, val); + if (scope.engine->hasException) + return Encode::undefined(); + ++idx; + b += elementSize; + } + + + return array.asReturnedValue(); +} + +ReturnedValue TypedArrayCtor::call(Managed *that, CallData *callData) +{ + return construct(that, callData); +} + +TypedArray::Data::Data(ExecutionEngine *e, Type t) + : Object::Data(e->typedArrayClasses[t]), + type(operations + t) +{ +} + +void TypedArray::markObjects(HeapObject *that, ExecutionEngine *e) +{ + static_cast<TypedArray::Data *>(that)->buffer->mark(e); + Object::markObjects(that, e); +} + +ReturnedValue TypedArray::getIndexed(Managed *m, uint index, bool *hasProperty) +{ + Scope scope(m->engine()); + Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m)); + + uint bytesPerElement = a->d()->type->bytesPerElement; + uint byteOffset = a->d()->byteOffset + index * bytesPerElement; + if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength()) { + if (hasProperty) + *hasProperty = false; + return Encode::undefined(); + } + if (hasProperty) + *hasProperty = true; + return a->d()->type->read(a->d()->buffer->d()->data->data(), byteOffset); +} + +void TypedArray::putIndexed(Managed *m, uint index, const ValueRef value) +{ + if (m->engine()->hasException) + return; + + Scope scope(m->engine()); + Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m)); + + uint bytesPerElement = a->d()->type->bytesPerElement; + uint byteOffset = a->d()->byteOffset + index * bytesPerElement; + if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength()) + goto reject; + + a->d()->type->write(scope.engine, a->d()->buffer->d()->data->data(), byteOffset, value); + return; + +reject: + if (scope.engine->currentContext()->d()->strictMode) + scope.engine->throwTypeError(); +} + +void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) +{ + Scope scope(engine); + ScopedObject o(scope); + ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); + defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); + defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); + defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); + defineAccessorProperty(QStringLiteral("length"), method_get_length, 0); + defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); + + defineDefaultProperty(QStringLiteral("set"), method_set, 1); + defineDefaultProperty(QStringLiteral("subarray"), method_subarray, 0); +} + +ReturnedValue TypedArrayPrototype::method_get_buffer(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->buffer->asReturnedValue()); +} + +ReturnedValue TypedArrayPrototype::method_get_byteLength(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->byteLength); +} + +ReturnedValue TypedArrayPrototype::method_get_byteOffset(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->byteOffset); +} + +ReturnedValue TypedArrayPrototype::method_get_length(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->byteLength/v->d()->type->bytesPerElement); +} + +ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> a(scope, ctx->d()->callData->thisObject); + if (!a) + return scope.engine->throwTypeError(); + Scoped<ArrayBuffer> buffer(scope, a->d()->buffer); + if (!buffer) + scope.engine->throwTypeError(); + + double doffset = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toInteger() : 0; + if (scope.engine->hasException) + return Encode::undefined(); + + if (doffset < 0 || doffset >= UINT_MAX) + return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")); + uint offset = (uint)doffset; + uint elementSize = a->d()->type->bytesPerElement; + + Scoped<TypedArray> srcTypedArray(scope, ctx->d()->callData->args[0]); + if (!srcTypedArray) { + // src is a regular object + ScopedObject o(scope, ctx->d()->callData->args[0].toObject(ctx)); + if (scope.engine->hasException || !o) + return scope.engine->throwTypeError(); + + double len = ScopedValue(scope, o->get(scope.engine->id_length))->toNumber(); + uint l = (uint)len; + if (scope.engine->hasException || l != len) + return scope.engine->throwTypeError(); + + if (offset + l > a->length()) + return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")); + + uint idx = 0; + char *b = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize; + ScopedValue val(scope); + while (idx < l) { + val = o->getIndexed(idx); + a->d()->type->write(scope.engine, b, 0, val); + if (scope.engine->hasException) + return Encode::undefined(); + ++idx; + b += elementSize; + } + return Encode::undefined(); + } + + // src is a typed array + Scoped<ArrayBuffer> srcBuffer(scope, srcTypedArray->d()->buffer); + if (!srcBuffer) + return scope.engine->throwTypeError(); + + uint l = srcTypedArray->length(); + if (offset + l > a->length()) + return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")); + + char *dest = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize; + const char *src = srcBuffer->d()->data->data() + srcTypedArray->d()->byteOffset; + if (srcTypedArray->d()->type == a->d()->type) { + // same type of typed arrays, use memmove (as srcbuffer and buffer could be the same) + memmove(dest, src, srcTypedArray->d()->byteLength); + return Encode::undefined(); + } + + char *srcCopy = 0; + if (buffer->d() == srcBuffer->d()) { + // same buffer, need to take a temporary copy, to not run into problems + srcCopy = new char[srcTypedArray->d()->byteLength]; + memcpy(srcCopy, src, srcTypedArray->d()->byteLength); + src = srcCopy; + } + + // typed arrays of different kind, need to manually loop + uint srcElementSize = srcTypedArray->d()->type->bytesPerElement; + TypedArrayRead read = srcTypedArray->d()->type->read; + TypedArrayWrite write = a->d()->type->write; + for (uint i = 0; i < l; ++i) { + Primitive val; + val.val = read(src, i*srcElementSize); + write(scope.engine, dest, i*elementSize, val); + } + + if (srcCopy) + delete [] srcCopy; + + return Encode::undefined(); +} + +ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> a(scope, ctx->d()->callData->thisObject); + + if (!a) + return scope.engine->throwTypeError(); + + Scoped<ArrayBuffer> buffer(scope, a->d()->buffer); + if (!buffer) + return scope.engine->throwTypeError(); + + int len = a->length(); + double b = ctx->d()->callData->argc > 0 ? ctx->d()->callData->args[0].toInteger() : 0; + if (b < 0) + b = len + b; + uint begin = (uint)qBound(0., b, (double)len); + + double e = ctx->d()->callData->argc < 2 || ctx->d()->callData->args[1].isUndefined() ? len : ctx->d()->callData->args[1].toInteger(); + if (e < 0) + e = len + e; + uint end = (uint)qBound(0., e, (double)len); + if (end < begin) + end = begin; + + if (scope.engine->hasException) + return Encode::undefined(); + + int newLen = end - begin; + + Scoped<FunctionObject> constructor(scope, a->get(scope.engine->id_constructor)); + if (!constructor) + return scope.engine->throwTypeError(); + + ScopedCallData callData(scope, 3); + callData->args[0] = buffer; + callData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement); + callData->args[2] = Encode(newLen); + return constructor->construct(callData); +} diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h new file mode 100644 index 0000000000..28847e0c85 --- /dev/null +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4TYPEDARRAY_H +#define QV4TYPEDARRAY_H + +#include "qv4object_p.h" +#include "qv4functionobject_p.h" + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct ArrayBuffer; + +typedef ReturnedValue (*TypedArrayRead)(const char *data, int index); +typedef void (*TypedArrayWrite)(ExecutionEngine *engine, char *data, int index, ValueRef value); + +struct TypedArrayOperations { + int bytesPerElement; + const char *name; + TypedArrayRead read; + TypedArrayWrite write; +}; + +struct TypedArray : Object +{ + enum Type { + Int8Array, + UInt8Array, + UInt8ClampedArray, + Int16Array, + UInt16Array, + Int32Array, + UInt32Array, + Float32Array, + Float64Array, + NTypes + }; + + struct Data : Object::Data { + Data(ExecutionEngine *e, Type t); + + const TypedArrayOperations *type; + ArrayBuffer *buffer; + uint byteLength; + uint byteOffset; + }; + V4_OBJECT(Object) + + uint length() const { + return d()->byteLength/d()->type->bytesPerElement; + } + + + static void markObjects(HeapObject *that, ExecutionEngine *e); + static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static void putIndexed(Managed *m, uint index, const ValueRef value); +}; + +struct TypedArrayCtor: FunctionObject +{ + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope, TypedArray::Type t); + + TypedArray::Type type; + }; + + V4_OBJECT(FunctionObject) + + static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue call(Managed *that, CallData *callData); +}; + + +struct TypedArrayPrototype : Object +{ + struct Data : Object::Data { + Data(ExecutionEngine *e, TypedArray::Type t) + : Object::Data(e) + , type(t) + { + setVTable(staticVTable()); + } + TypedArray::Type type; + }; + V4_OBJECT(Object) + + void init(ExecutionEngine *engine, TypedArrayCtor *ctor); + + static ReturnedValue method_get_buffer(CallContext *ctx); + static ReturnedValue method_get_byteLength(CallContext *ctx); + static ReturnedValue method_get_byteOffset(CallContext *ctx); + static ReturnedValue method_get_length(CallContext *ctx); + + static ReturnedValue method_set(CallContext *ctx); + static ReturnedValue method_subarray(CallContext *ctx); +}; + +} // namespace QV4 + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 0293054457..a80cc40add 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -31,6 +31,7 @@ ** ****************************************************************************/ #include <qv4engine_p.h> +#include <qv4runtime_p.h> #ifndef V4_BOOTSTRAP #include <qv4object_p.h> #include <qv4objectproto_p.h> diff --git a/src/qml/jsruntime/qv4value_inl_p.h b/src/qml/jsruntime/qv4value_inl_p.h index 045eaccfaf..2600148417 100644 --- a/src/qml/jsruntime/qv4value_inl_p.h +++ b/src/qml/jsruntime/qv4value_inl_p.h @@ -35,18 +35,11 @@ #include <cmath> // this HAS to come -#include <QtCore/QString> -#include <QtCore/qnumeric.h> -#include "qv4global_p.h" +#include "qv4value_p.h" + #include "qv4string_p.h" -#include <QtCore/QDebug> #include "qv4managed_p.h" #include "qv4engine_p.h" -#include <private/qtqmlglobal_p.h> - -//#include <wtf/MathExtras.h> - -#include "qv4value_p.h" QT_BEGIN_NAMESPACE @@ -56,13 +49,13 @@ inline bool Value::isString() const { if (!isManaged()) return false; - return managed() && managed()->internalClass()->vtable->isString; + return m && static_cast<Managed::Data *>(m)->internalClass->vtable->isString; } inline bool Value::isObject() const { if (!isManaged()) return false; - return managed() && managed()->internalClass()->vtable->isObject; + return m && static_cast<Managed::Data *>(m)->internalClass->vtable->isObject; } inline bool Value::isPrimitive() const @@ -70,6 +63,13 @@ inline bool Value::isPrimitive() const return !isObject(); } +inline String *Value::asString() const +{ + if (isString()) + return stringValue(); + return 0; +} + inline ExecutionEngine *Value::engine() const { Managed *m = asManaged(); @@ -275,6 +275,21 @@ inline ErrorObject *Value::asErrorObject() const template<typename T> inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m ? m->as<T>() : 0; } +#ifndef V4_BOOTSTRAP + +template<> +inline String *value_cast(const Value &v) { + return v.asString(); +} + +template<> +inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) +{ + return v.toString(e)->asReturnedValue(); +} + +#endif + #endif } // namespace QV4 diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 59a4543538..fa2d544fcf 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -44,19 +44,54 @@ namespace QV4 { typedef uint Bool; +struct Q_QML_EXPORT HeapObject { + HeapObject(InternalClass *internal) + : internalClass(internal) + , markBit(0) + , inUse(1) + , extensible(1) + { + // #### + // Q_ASSERT(internal && internal->vtable); + } + InternalClass *internalClass; + struct { + uchar markBit : 1; + uchar inUse : 1; + uchar extensible : 1; // used by Object + uchar _unused : 1; + uchar needsActivation : 1; // used by FunctionObject + uchar strictMode : 1; // used by FunctionObject + uchar bindingKeyFlag : 1; + uchar hasAccessorProperty : 1; + uchar _type; + mutable uchar subtype; + uchar _flags; + + }; + + void setVTable(const ManagedVTable *vt); + inline ReturnedValue asReturnedValue() const; + inline void mark(QV4::ExecutionEngine *engine); + + void *operator new(size_t, Managed *m) { return m; } + void *operator new(size_t, HeapObject *m) { return m; } + void operator delete(void *, HeapObject *) {} +}; + template <typename T> -struct Returned : private T +struct Returned : private HeapObject { - static Returned<T> *create(T *t) { return static_cast<Returned<T> *>(t); } - T *getPointer() { return this; } + static Returned<T> *create(T *t) { Q_ASSERT((void *)&t->data == (void *)t); return static_cast<Returned<T> *>(static_cast<HeapObject*>(t ? &t->data : 0)); } + static Returned<T> *create(typename T::Data *t) { return static_cast<Returned<T> *>(static_cast<HeapObject*>(t)); } + T *getPointer() { return reinterpret_cast<T *>(this); } template<typename X> static T *getPointer(Returned<X> *x) { return x->getPointer(); } template<typename X> Returned<X> *as() { return Returned<X>::create(Returned<X>::getPointer(this)); } - using T::asReturnedValue; -}; -struct HeapObject {}; + inline ReturnedValue asReturnedValue(); +}; struct Q_QML_PRIVATE_EXPORT Value { @@ -86,9 +121,7 @@ struct Q_QML_PRIVATE_EXPORT Value union { quint64 val; #if QT_POINTER_SIZE == 8 - Managed *m; - Object *o; - String *s; + HeapObject *m; #else double dbl; #endif @@ -100,9 +133,7 @@ struct Q_QML_PRIVATE_EXPORT Value uint uint_32; int int_32; #if QT_POINTER_SIZE == 4 - Managed *m; - Object *o; - String *s; + HeapObject *m; #endif }; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN @@ -270,12 +301,15 @@ struct Q_QML_PRIVATE_EXPORT Value } String *stringValue() const { - return s; + return m ? reinterpret_cast<String*>(m) : 0; } Object *objectValue() const { - return o; + return m ? reinterpret_cast<Object*>(m) : 0; } Managed *managed() const { + return m ? reinterpret_cast<Managed*>(m) : 0; + } + HeapObject *heapObject() const { return m; } @@ -283,7 +317,17 @@ struct Q_QML_PRIVATE_EXPORT Value return val; } - static inline Value fromManaged(Managed *o); + static inline Value fromHeapObject(HeapObject *m) + { + Value v; + v.m = m; +#if QT_POINTER_SIZE == 4 + v.tag = Managed_Type; +#endif + return v; + } + + static inline Value fromManaged(Managed *m); int toUInt16() const; inline int toInt32() const; @@ -318,6 +362,12 @@ struct Q_QML_PRIVATE_EXPORT Value inline ErrorObject *asErrorObject() const; template<typename T> inline T *as() const; + template<typename T> inline T *cast() { + return static_cast<T *>(managed()); + } + template<typename T> inline const T *cast() const { + return static_cast<const T *>(managed()); + } inline uint asArrayIndex() const; inline uint asArrayLength(bool *ok) const; @@ -342,7 +392,7 @@ struct Q_QML_PRIVATE_EXPORT Value return *this; } Value &operator=(HeapObject *o) { - m = reinterpret_cast<Managed *>(o); + m = o; return *this; } @@ -364,13 +414,6 @@ inline Managed *Value::asManaged() const return 0; } -inline String *Value::asString() const -{ - if (isString()) - return stringValue(); - return 0; -} - struct Q_QML_PRIVATE_EXPORT Primitive : public Value { inline static Primitive emptyValue(); @@ -409,20 +452,6 @@ inline Primitive Primitive::emptyValue() return v; } -inline Value Value::fromManaged(Managed *m) -{ - if (!m) - return QV4::Primitive::undefinedValue(); - Value v; -#if QT_POINTER_SIZE == 8 - v.m = m; -#else - v.tag = Managed_Type; - v.m = m; -#endif - return v; -} - template <typename T> struct TypedValue : public Value { @@ -546,11 +575,17 @@ struct ValueRef { ReturnedValue asReturnedValue() const { return ptr->val; } // ### get rid of this one! - ValueRef(Value *v) { ptr = reinterpret_cast<Value *>(v); } + ValueRef(Value *v) { ptr = v; } private: Value *ptr; }; +inline +ReturnedValue HeapObject::asReturnedValue() const +{ + return Value::fromHeapObject(const_cast<HeapObject *>(this)).asReturnedValue(); +} + template<typename T> T *value_cast(const Value &v) @@ -561,7 +596,8 @@ T *value_cast(const Value &v) template<typename T> ReturnedValue value_convert(ExecutionEngine *e, const Value &v); - +template <typename T> +ReturnedValue Returned<T>::asReturnedValue() { return Value::fromHeapObject(this).asReturnedValue(); } } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index cd73314bce..35ac5eac5f 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -184,7 +184,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code qDebug("Starting VME with context=%p and code=%p", context, code); #endif // DO_TRACE_INSTR - QV4::StringValue * const runtimeStrings = context->d()->compilationUnit->runtimeStrings; + QV4::String ** const runtimeStrings = context->d()->compilationUnit->runtimeStrings; // setup lookup scopes int scopeDepth = 0; @@ -240,7 +240,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_BEGIN_INSTR(LoadRuntimeString) // TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData()); - VALUE(instr.result) = runtimeStrings[instr.stringId].asReturnedValue(); + VALUE(instr.result) = runtimeStrings[instr.stringId]->asReturnedValue(); MOTH_END_INSTR(LoadRuntimeString) MOTH_BEGIN_INSTR(LoadRegExp) diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 26fe659616..cabb76db48 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -76,8 +76,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, const QString &handlerName, const QString ¶meterString) : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), - m_target(target), m_index(index), + m_target(target), m_extra(new ExtraData(handlerName, parameterString, expression, fileName, line, column)) { setExpressionFunctionValid(false); @@ -88,9 +88,9 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::ValueRef &function) : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + m_index(index), m_v8function(function), m_target(target), - m_index(index), m_extra(0) { setExpressionFunctionValid(true); @@ -101,8 +101,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction) : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), - m_target(target), m_index(index), + m_target(target), m_extra(0) { setExpressionFunctionValid(true); diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index b9f519a920..d2fec2afc8 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -98,10 +98,10 @@ private: bool invalidParameterName() const { return m_extra.flag2(); } void setInvalidParameterName(bool v) { m_extra.setFlag2Value(v); } + int m_index; QV4::PersistentValue m_v8function; QObject *m_target; - int m_index; // only needed when !expressionFunctionValid() struct ExtraData { diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 63a43966b1..980fc99b92 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1090,7 +1090,7 @@ struct QmlIncubatorObject : public QV4::Object static QV4::ReturnedValue method_forceCompletion(QV4::CallContext *ctx); static void destroy(Managed *that); - static void markObjects(Managed *that, QV4::ExecutionEngine *e); + static void markObjects(QV4::HeapObject *that, QV4::ExecutionEngine *e); void statusChanged(QQmlIncubator::Status); void setInitialState(QObject *); @@ -1416,7 +1416,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_get_object(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return QV4::QObjectWrapper::wrap(ctx->d()->engine, o->d()->incubator->object()); } @@ -1426,7 +1426,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::CallContext * QV4::Scope scope(ctx); QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); o->d()->incubator->forceCompletion(); @@ -1438,7 +1438,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_get_status(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return QV4::Encode(o->d()->incubator->status()); } @@ -1448,7 +1448,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_get_statusChanged(QV4::CallContext QV4::Scope scope(ctx); QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return o->d()->statusChanged.asReturnedValue(); } @@ -1458,7 +1458,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_set_statusChanged(QV4::CallContext QV4::Scope scope(ctx); QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o || ctx->d()->callData->argc < 1) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); o->d()->statusChanged = ctx->d()->callData->args[0]; @@ -1503,13 +1503,12 @@ void QmlIncubatorObject::destroy(Managed *that) static_cast<QmlIncubatorObject *>(that)->d()->~Data(); } -void QmlIncubatorObject::markObjects(QV4::Managed *that, QV4::ExecutionEngine *e) +void QmlIncubatorObject::markObjects(QV4::HeapObject *that, QV4::ExecutionEngine *e) { - QmlIncubatorObject *o = static_cast<QmlIncubatorObject *>(that); - Q_ASSERT(that->as<QmlIncubatorObject>()); - o->d()->valuemap.mark(e); - o->d()->qmlGlobal.mark(e); - o->d()->statusChanged.mark(e); + QmlIncubatorObject::Data *o = static_cast<QmlIncubatorObject::Data *>(that); + o->valuemap.mark(e); + o->qmlGlobal.mark(e); + o->statusChanged.mark(e); Object::markObjects(that, e); } diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 0816bc05df..df62f285e3 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -291,7 +291,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const ValueRef value) QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); Scoped<String> e(scope, v4->currentContext()->d()->engine->newString(error)); - v4->currentContext()->throwError(e); + v4->throwError(e); return; } @@ -335,7 +335,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const ValueRef value) if (wrapper->d()->readOnly) { QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); - v4->currentContext()->throwError(error); + v4->throwError(error); return; } @@ -347,11 +347,11 @@ void QmlContextWrapper::destroy(Managed *that) static_cast<QmlContextWrapper *>(that)->d()->~Data(); } -void QmlContextWrapper::markObjects(Managed *m, ExecutionEngine *engine) +void QmlContextWrapper::markObjects(HeapObject *m, ExecutionEngine *engine) { - QmlContextWrapper *This = static_cast<QmlContextWrapper*>(m); - if (This->d()->idObjectsWrapper) - This->d()->idObjectsWrapper->mark(engine); + QmlContextWrapper::Data *This = static_cast<QmlContextWrapper::Data *>(m); + if (This->idObjectsWrapper) + This->idObjectsWrapper->mark(engine); Object::markObjects(m, engine); } @@ -465,10 +465,10 @@ ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasPr return QObjectWrapper::wrap(This->engine(), context->idValues[index].data()); } -void QQmlIdObjectsArray::markObjects(Managed *that, ExecutionEngine *engine) +void QQmlIdObjectsArray::markObjects(HeapObject *that, ExecutionEngine *engine) { - QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(that); - This->d()->contextWrapper->mark(engine); + QQmlIdObjectsArray::Data *This = static_cast<QQmlIdObjectsArray::Data *>(that); + This->contextWrapper->mark(engine); Object::markObjects(that, engine); } diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index cae6800f48..ae9e795a5c 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -93,7 +93,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object static ReturnedValue get(Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const ValueRef value); static void destroy(Managed *that); - static void markObjects(Managed *m, ExecutionEngine *engine); + static void markObjects(HeapObject *m, ExecutionEngine *engine); static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction); @@ -111,7 +111,7 @@ struct QQmlIdObjectsArray : public Object V4_OBJECT(Object) static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); - static void markObjects(Managed *that, ExecutionEngine *engine); + static void markObjects(HeapObject *that, ExecutionEngine *engine); }; diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index 13e5e49b55..b62689c454 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -35,6 +35,7 @@ #include <private/qv8engine_p.h> #include <private/qqmllist_p.h> #include <private/qv4objectproto_p.h> +#include <qv4objectiterator_p.h> #include <private/qv4functionobject_p.h> diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index 3787517038..233624453f 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -137,7 +137,7 @@ struct QQmlLocaleData : public QV4::Object QV4::Object *o = ctx->d()->callData->thisObject.asObject(); QQmlLocaleData *thisObject = o ? o->as<QQmlLocaleData>() : 0; if (!thisObject) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return 0; } return &thisObject->d()->locale; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index d8f282c030..ddd934c840 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -262,7 +262,7 @@ void QmlTypeWrapper::put(Managed *m, String *name, const ValueRef value) QV4::ScopedObject apiprivate(scope, QJSValuePrivate::get(siinfo->scriptApi(e))->value); if (!apiprivate) { QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); - v4->currentContext()->throwError(error); + v4->throwError(error); return; } else { apiprivate->put(name, value); diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index b0125b4c13..7de15eac7d 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -144,7 +144,7 @@ ReturnedValue QmlValueTypeWrapper::create(QV8Engine *v8, QObject *object, int pr Scope scope(v4); initProto(v4); - QmlValueTypeReference *r = v4->memoryManager->alloc<QmlValueTypeReference>(v8); + Scoped<QmlValueTypeReference> r(scope, v4->memoryManager->alloc<QmlValueTypeReference>(v8)); r->d()->internalClass = r->d()->internalClass->changePrototype(v4->qmlExtensions()->valueTypeWrapperPrototype); r->d()->type = type; r->d()->object = object; r->d()->property = property; return r->asReturnedValue(); @@ -156,7 +156,7 @@ ReturnedValue QmlValueTypeWrapper::create(QV8Engine *v8, const QVariant &value, Scope scope(v4); initProto(v4); - QmlValueTypeCopy *r = v4->memoryManager->alloc<QmlValueTypeCopy>(v8); + Scoped<QmlValueTypeCopy> r(scope, v4->memoryManager->alloc<QmlValueTypeCopy>(v8)); r->d()->internalClass = r->d()->internalClass->changePrototype(v4->qmlExtensions()->valueTypeWrapperPrototype); r->d()->type = type; r->d()->value = value; return r->asReturnedValue(); @@ -242,10 +242,10 @@ ReturnedValue QmlValueTypeWrapper::method_toString(CallContext *ctx) { Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QmlValueTypeWrapper *w = o->as<QmlValueTypeWrapper>(); if (!w) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (w->d()->objectType == QmlValueTypeWrapper::Reference) { QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(w); @@ -355,7 +355,7 @@ void QmlValueTypeWrapper::put(Managed *m, String *name, const ValueRef value) // assigning a JS function to a non-var-property is not allowed. QString error = QLatin1String("Cannot assign JavaScript function to value-type property"); Scoped<String> e(scope, r->d()->v8->toString(error)); - v4->currentContext()->throwError(e); + v4->throwError(e); return; } diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 0730cbc363..2acd40ae44 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -55,6 +55,7 @@ #include <QtCore/qxmlstream.h> #include <QtCore/qstack.h> #include <QtCore/qdebug.h> +#include <QtCore/qbuffer.h> #include <private/qv4objectproto_p.h> #include <private/qv4scopedvalue_p.h> @@ -65,7 +66,7 @@ using namespace QV4; #define V4THROW_REFERENCE(string) { \ Scoped<Object> error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \ - return ctx->throwError(error); \ + return ctx->engine()->throwError(error); \ } QT_BEGIN_NAMESPACE @@ -420,7 +421,7 @@ ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QString name; switch (r->d()->d->type) { @@ -445,7 +446,7 @@ ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (r->d()->d->type == NodeImpl::Document || r->d()->d->type == NodeImpl::DocumentFragment || @@ -464,7 +465,7 @@ ReturnedValue NodePrototype::method_get_nodeType(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return Encode(r->d()->d->type); } @@ -474,7 +475,7 @@ ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -489,7 +490,7 @@ ReturnedValue NodePrototype::method_get_childNodes(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -501,7 +502,7 @@ ReturnedValue NodePrototype::method_get_firstChild(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -516,7 +517,7 @@ ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -531,7 +532,7 @@ ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -555,7 +556,7 @@ ReturnedValue NodePrototype::method_get_nextSibling(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -579,7 +580,7 @@ ReturnedValue NodePrototype::method_get_attributes(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -899,7 +900,7 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty if (!r) { if (hasProperty) *hasProperty = false; - return v4->currentContext()->throwTypeError(); + return v4->throwTypeError(); } QV8Engine *engine = v4->v8Engine; @@ -1249,16 +1250,23 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url) } } - if (m_method == QLatin1String("GET")) + if (m_method == QLatin1String("GET")) { m_network = networkAccessManager()->get(request); - else if (m_method == QLatin1String("HEAD")) + } else if (m_method == QLatin1String("HEAD")) { m_network = networkAccessManager()->head(request); - else if (m_method == QLatin1String("POST")) + } else if (m_method == QLatin1String("POST")) { m_network = networkAccessManager()->post(request, m_data); - else if (m_method == QLatin1String("PUT")) + } else if (m_method == QLatin1String("PUT")) { m_network = networkAccessManager()->put(request, m_data); - else if (m_method == QLatin1String("DELETE")) + } else if (m_method == QLatin1String("DELETE")) { m_network = networkAccessManager()->deleteResource(request); + } else if (m_method == QLatin1String("OPTIONS")) { + QBuffer *buffer = new QBuffer; + buffer->setData(m_data); + buffer->open(QIODevice::ReadOnly); + m_network = networkAccessManager()->sendCustomRequest(request, QByteArrayLiteral("OPTIONS"), buffer); + buffer->setParent(m_network); + } QObject::connect(m_network, SIGNAL(readyRead()), this, SLOT(readyRead())); @@ -1526,14 +1534,14 @@ void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me) QV4::Scope scope(v4); Scoped<Object> o(scope, me); if (!o) { - ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); + ctx->engine()->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); return; } ScopedString s(scope, v4->newString(QStringLiteral("ThisObject"))); Scoped<Object> thisObj(scope, o->get(s.getPointer())); if (!thisObj) { - ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); + ctx->engine()->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); return; } @@ -1547,7 +1555,7 @@ void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me) s = v4->newString(QStringLiteral("ActivationObject")); Scoped<Object> activationObject(scope, o->get(s.getPointer())); if (!activationObject) { - v4->currentContext()->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject")); + v4->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject")); return; } @@ -1631,10 +1639,10 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject Object *proto; }; V4_OBJECT(FunctionObject) - static void markObjects(Managed *that, ExecutionEngine *e) { - QQmlXMLHttpRequestCtor *c = static_cast<QQmlXMLHttpRequestCtor *>(that); - if (c->d()->proto) - c->d()->proto->mark(e); + static void markObjects(HeapObject *that, ExecutionEngine *e) { + QQmlXMLHttpRequestCtor::Data *c = static_cast<QQmlXMLHttpRequestCtor::Data *>(that); + if (c->proto) + c->proto->mark(e); FunctionObject::markObjects(that, e); } static ReturnedValue construct(Managed *that, QV4::CallData *) @@ -1642,7 +1650,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject Scope scope(that->engine()); Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>()); if (!ctor) - return that->engine()->currentContext()->throwTypeError(); + return that->engine()->throwTypeError(); QV8Engine *engine = that->engine()->v8Engine; QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(engine, engine->networkAccessManager()); @@ -1724,7 +1732,8 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) method != QLatin1String("PUT") && method != QLatin1String("HEAD") && method != QLatin1String("POST") && - method != QLatin1String("DELETE")) + method != QLatin1String("DELETE") && + method != QLatin1String("OPTIONS")) V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type"); // Argument 1 - URL diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index f222d59494..3a593d1c5b 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1004,7 +1004,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) if (component.isError()) { ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors())); - return ctx->throwError(v); + return ctx->engine()->throwError(v); } if (!component.isReady()) @@ -1028,7 +1028,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) if (component.isError()) { ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors())); - return ctx->throwError(v); + return ctx->engine()->throwError(v); } Q_ASSERT(obj); @@ -1070,7 +1070,7 @@ use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}. ReturnedValue QtObject::method_createComponent(CallContext *ctx) { if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 3) - return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); + return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); Scope scope(ctx); @@ -1098,13 +1098,13 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) if (ctx->d()->callData->args[1].isInteger()) { int mode = ctx->d()->callData->args[1].integerValue(); if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous)) - return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); + return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); compileMode = QQmlComponent::CompilationMode(mode); consumedCount += 1; } else { // The second argument could be the parent only if there are exactly two args if ((ctx->d()->callData->argc != 2) || !(lastArg->isObject() || lastArg->isNull())) - return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); + return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); } if (consumedCount < ctx->d()->callData->argc) { @@ -1113,11 +1113,11 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) if (qobjectWrapper) parentArg = qobjectWrapper->object(); if (!parentArg) - return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object")); + return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object")); } else if (lastArg->isNull()) { parentArg = 0; } else { - return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object")); + return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object")); } } } @@ -1187,10 +1187,10 @@ ReturnedValue QQmlBindingFunction::call(Managed *that, CallData *callData) return This->d()->originalFunction->call(callData); } -void QQmlBindingFunction::markObjects(Managed *that, ExecutionEngine *e) +void QQmlBindingFunction::markObjects(HeapObject *that, ExecutionEngine *e) { - QQmlBindingFunction *This = static_cast<QQmlBindingFunction*>(that); - This->d()->originalFunction->mark(e); + QQmlBindingFunction::Data *This = static_cast<QQmlBindingFunction::Data *>(that); + This->originalFunction->mark(e); QV4::FunctionObject::markObjects(that, e); } @@ -1257,10 +1257,10 @@ ReturnedValue QtObject::method_get_platform(CallContext *ctx) // ### inefficient. Should be just a value based getter Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QtObject *qt = o->as<QtObject>(); if (!qt) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (!qt->d()->platform) // Only allocate a platform object once @@ -1274,10 +1274,10 @@ ReturnedValue QtObject::method_get_application(CallContext *ctx) // ### inefficient. Should be just a value based getter Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QtObject *qt = o->as<QtObject>(); if (!qt) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (!qt->d()->application) // Only allocate an application object once diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index f7728aa120..7fe7d2b914 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -155,7 +155,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject static ReturnedValue call(Managed *that, CallData *callData); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); static void destroy(Managed *that) { static_cast<QQmlBindingFunction *>(that)->d()->~Data(); } diff --git a/src/qml/qml/v8/qv4domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h index 59ed744f5e..facf7972ad 100644 --- a/src/qml/qml/v8/qv4domerrors_p.h +++ b/src/qml/qml/v8/qv4domerrors_p.h @@ -72,7 +72,7 @@ QT_BEGIN_NAMESPACE QV4::ScopedValue v(scope, scope.engine->newString(QStringLiteral(string))); \ QV4::Scoped<Object> ex(scope, scope.engine->newErrorObject(v)); \ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(error))); \ - return ctx->throwError(ex); \ + return ctx->engine()->throwError(ex); \ } namespace QV4 { diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 39b816f97c..d472120b4e 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -305,21 +305,6 @@ QVariant QV8Engine::objectToVariant(QV4::Object *o, V8ObjectSet *visitedObjects) return result; } -static QV4::ReturnedValue arrayFromStringList(QV8Engine *engine, const QStringList &list) -{ - QV4::ExecutionEngine *e = QV8Engine::getV4(engine); - QV4::Scope scope(e); - QV4::Scoped<QV4::ArrayObject> a(scope, e->newArrayObject()); - int len = list.count(); - a->arrayReserve(len); - QV4::ScopedValue v(scope); - for (int ii = 0; ii < len; ++ii) - a->arrayPut(ii, (v = QV4::Encode(e->newString(list.at(ii))))); - - a->setArrayLengthUnchecked(len); - return a.asReturnedValue(); -} - static QV4::ReturnedValue arrayFromVariantList(QV8Engine *engine, const QVariantList &list) { QV4::ExecutionEngine *e = QV8Engine::getV4(engine); @@ -409,7 +394,7 @@ QV4::ReturnedValue QV8Engine::fromVariant(const QVariant &variant) QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(m_v4Engine, variant, &succeeded)); if (succeeded) return retn.asReturnedValue(); - return arrayFromStringList(this, *reinterpret_cast<const QStringList *>(ptr)); + return QV4::Encode(m_v4Engine->newArrayObject(*reinterpret_cast<const QStringList *>(ptr))); } case QMetaType::QVariantList: return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr)); diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index 51e857c8a2..2379689fb3 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -78,10 +78,10 @@ namespace QV4 { // #define QML_GLOBAL_HANDLE_DEBUGGING #define V4THROW_ERROR(string) \ - return ctx->throwError(QString::fromUtf8(string)); + return ctx->engine()->throwError(QString::fromUtf8(string)); #define V4THROW_TYPE(string) \ - return ctx->throwTypeError(QStringLiteral(string)); + return ctx->engine()->throwTypeError(QStringLiteral(string)); #define V8_DEFINE_EXTENSION(dataclass, datafunction) \ static inline dataclass *datafunction(QV8Engine *engine) \ diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri index b4eb706574..3d6a012481 100644 --- a/src/qml/qml/v8/v8.pri +++ b/src/qml/qml/v8/v8.pri @@ -1,5 +1,4 @@ HEADERS += \ - $$PWD/qv8debug_p.h \ $$PWD/qv8engine_p.h \ $$PWD/qv4domerrors_p.h \ $$PWD/qv4sqlerrors_p.h \ diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 639df4f846..e150545926 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -46,6 +46,7 @@ #include <private/qv4value_inl_p.h> #include <private/qv4functionobject_p.h> +#include <qv4objectiterator_p.h> QT_BEGIN_NAMESPACE @@ -67,14 +68,14 @@ struct DelegateModelGroupFunction: QV4::FunctionObject }; V4_OBJECT(QV4::FunctionObject) - static DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg)) + static QV4::Returned<DelegateModelGroupFunction> *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg)) { return scope->engine()->memoryManager->alloc<DelegateModelGroupFunction>(scope, flag, code); } static QV4::ReturnedValue construct(QV4::Managed *m, QV4::CallData *) { - return m->engine()->currentContext()->throwTypeError(); + return m->engine()->throwTypeError(); } static QV4::ReturnedValue call(QV4::Managed *that, QV4::CallData *callData) @@ -84,7 +85,7 @@ struct DelegateModelGroupFunction: QV4::FunctionObject QV4::Scoped<DelegateModelGroupFunction> f(scope, that, QV4::Scoped<DelegateModelGroupFunction>::Cast); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject); if (!o) - return v4->currentContext()->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return v4->throwTypeError(QStringLiteral("Not a valid VisualData object")); QV4::ScopedValue v(scope, callData->argument(0)); return f->d()->code(o->d()->item, f->d()->flag, v); @@ -1780,7 +1781,7 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_model(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); if (!o->d()->item->metaType->model) return QV4::Encode::undefined(); @@ -1792,7 +1793,7 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); QStringList groups; for (int i = 1; i < o->d()->item->metaType->groupCount; ++i) { @@ -1808,9 +1809,9 @@ QV4::ReturnedValue QQmlDelegateModelItem::set_groups(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); if (!ctx->d()->callData->argc) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (!o->d()->item->metaType->model) return QV4::Encode::undefined(); @@ -3220,7 +3221,7 @@ struct QQmlDelegateModelGroupChange : QV4::Object }; V4_OBJECT(QV4::Object) - static QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) { + static QV4::Returned<QQmlDelegateModelGroupChange> *create(QV4::ExecutionEngine *e) { return e->memoryManager->alloc<QQmlDelegateModelGroupChange>(e); } @@ -3228,21 +3229,21 @@ struct QQmlDelegateModelGroupChange : QV4::Object QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return QV4::Encode(that->d()->change.index); } static QV4::ReturnedValue method_get_count(QV4::CallContext *ctx) { QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return QV4::Encode(that->d()->change.count); } static QV4::ReturnedValue method_get_moveId(QV4::CallContext *ctx) { QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (that->d()->change.moveId < 0) return QV4::Encode::undefined(); return QV4::Encode(that->d()->change.moveId); @@ -3267,7 +3268,7 @@ struct QQmlDelegateModelGroupChangeArray : public QV4::Object }; V4_OBJECT(QV4::Object) public: - static QQmlDelegateModelGroupChangeArray *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes) + static QV4::Returned<QQmlDelegateModelGroupChangeArray> *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes) { return engine->memoryManager->alloc<QQmlDelegateModelGroupChangeArray>(engine, changes); } diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index b147f56bfa..943947f577 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -60,7 +60,7 @@ static QV4::ReturnedValue get_index(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); return QV4::Encode(o->d()->item->index); } @@ -192,7 +192,7 @@ public: QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->d()->item)->type->model; if (o->d()->item->index >= 0 && *model) { @@ -339,7 +339,7 @@ QV4::ReturnedValue QQmlDMCachedModelData::get_property(QV4::CallContext *ctx, ui QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item); if (o->d()->item->index == -1) { @@ -359,9 +359,9 @@ QV4::ReturnedValue QQmlDMCachedModelData::set_property(QV4::CallContext *ctx, ui QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); if (!ctx->d()->callData->argc) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (o->d()->item->index == -1) { QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item); @@ -581,7 +581,7 @@ public: QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); return scope.engine->v8Engine->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData); } @@ -591,9 +591,9 @@ public: QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); if (!ctx->d()->callData->argc) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(scope.engine->v8Engine->toVariant(ctx->d()->callData->args[0], QVariant::Invalid)); return QV4::Encode::undefined(); |