diff options
author | Erik Verbruggen <erik.verbruggen@qt.io> | 2016-06-22 10:12:13 +0200 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@qt.io> | 2016-06-22 11:07:05 +0000 |
commit | 702c4247d74ffb7e4fb1aaca96d70f4591203ba2 (patch) | |
tree | 6c0a41332cf4a8ab0051600efdd27b0746574795 /src | |
parent | fd0e3c6d569a7410fff33974ce9f908dc2de0e22 (diff) |
V4: Pass scope around as parameters inside the runtime.
The implementation of many (or all) runtime functions consist of first
creating a QV4::Scope, which saves and restores the JS stack pointer.
It also prevents tail-calls because of that restoring behavior. In many
cases it suffices to do that at the entry-point of the runtime.
The return value of a JS function call is now also stored in the scope.
Previously, all return values were stored in a ScopedValue, got loaded
on return, and immediately stored in another ScopedValue in the caller.
This resulted in a lot of stores, where now there is only one store
needed, and no extra ScopedValue for every function.
Change-Id: I13d80fc0ce72c5702ef1536d41d12f710c5914fa
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
60 files changed, 659 insertions, 570 deletions
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index a619030100..7d96f11768 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -426,7 +426,7 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx) callData->args[0] = w; TransactionRollback rollbackOnException(&db, &w->d()->inTransaction); - callback->call(callData); + callback->call(scope, callData); rollbackOnException.clear(); if (!db.commit()) { db.rollback(); @@ -474,7 +474,7 @@ static ReturnedValue qmlsqldatabase_transaction_shared(CallContext *ctx, bool re callData->thisObject = scope.engine->globalObject; callData->args[0] = w; TransactionRollback rollbackOnException(&db, &w->d()->inTransaction); - callback->call(callData); + callback->call(scope, callData); rollbackOnException.clear(); if (!db.commit()) @@ -745,7 +745,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) ScopedCallData callData(scope, 1); callData->thisObject = scope.engine->globalObject; callData->args[0] = db; - dbcreationCallback->call(callData); + dbcreationCallback->call(scope, callData); } args->setReturnValue(db.asReturnedValue()); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp index 43036e9c3c..d54bf98068 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp @@ -208,7 +208,7 @@ private: void handleDebuggerDeleted(QObject *debugger); - QV4::ReturnedValue evaluateExpression(QV4::Scope &scope, const QString &expression); + void evaluateExpression(QV4::Scope &scope, const QString &expression); bool checkCondition(const QString &expression); QStringList breakOnSignals; @@ -241,12 +241,11 @@ private: bool NativeDebugger::checkCondition(const QString &expression) { QV4::Scope scope(m_engine); - QV4::ReturnedValue result = evaluateExpression(scope, expression); - QV4::ScopedValue val(scope, result); - return val->booleanValue(); + evaluateExpression(scope, expression); + return scope.result.booleanValue(); } -QV4::ReturnedValue NativeDebugger::evaluateExpression(QV4::Scope &scope, const QString &expression) +void NativeDebugger::evaluateExpression(QV4::Scope &scope, const QString &expression) { m_runningJob = true; @@ -261,12 +260,10 @@ QV4::ReturnedValue NativeDebugger::evaluateExpression(QV4::Scope &scope, const Q // That is a side-effect of inheritContext. script.inheritContext = true; script.parse(); - QV4::ScopedValue result(scope); if (!m_engine->hasException) - result = script.run(); + scope.result = script.run(); m_runningJob = false; - return result->asReturnedValue(); } NativeDebugger::NativeDebugger(QQmlNativeDebugServiceImpl *service, QV4::ExecutionEngine *engine) @@ -545,8 +542,8 @@ void NativeDebugger::handleExpressions(QJsonObject *response, const QJsonObject TRACE_PROTOCOL("Evaluate expression: " << expression); m_runningJob = true; - QV4::ReturnedValue eval = evaluateExpression(scope, expression); - QV4::ScopedValue result(scope, eval); + evaluateExpression(scope, expression); + QV4::ScopedValue result(scope, scope.result); m_runningJob = false; if (result->isUndefined()) { diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index 44746b8c2b..e5c1dcdb80 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -663,11 +663,11 @@ QJSValue QJSValue::call(const QJSValueList &args) callData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i)); } - ScopedValue result(scope, f->call(callData)); + f->call(scope, callData); if (engine->hasException) - result = engine->catchException(); + scope.result = engine->catchException(); - return QJSValue(engine, result->asReturnedValue()); + return QJSValue(engine, scope.result.asReturnedValue()); } /*! @@ -719,11 +719,11 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList callData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i)); } - ScopedValue result(scope, f->call(callData)); + f->call(scope, callData); if (engine->hasException) - result = engine->catchException(); + scope.result = engine->catchException(); - return QJSValue(engine, result->asReturnedValue()); + return QJSValue(engine, scope.result.asReturnedValue()); } /*! @@ -767,11 +767,11 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) callData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i)); } - ScopedValue result(scope, f->construct(callData)); + f->construct(scope, callData); if (engine->hasException) - result = engine->catchException(); + scope.result = engine->catchException(); - return QJSValue(engine, result->asReturnedValue()); + return QJSValue(engine, scope.result.asReturnedValue()); } #ifdef QT_DEPRECATED diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 94f418cae1..b55494823c 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -134,7 +134,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con ScopedCallData callData(scope, 1); callData->thisObject = this->asReturnedValue(); callData->args[0] = desc->value; - setter->call(callData); + setter->call(scope, callData); if (attrs.isWritable()) { setArrayAttributes(index, mapAttrs); @@ -203,33 +203,35 @@ PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index) DEFINE_OBJECT_VTABLE(ArgumentsGetterFunction); -ReturnedValue ArgumentsGetterFunction::call(const Managed *getter, CallData *callData) +void ArgumentsGetterFunction::call(const Managed *getter, Scope &scope, CallData *callData) { ExecutionEngine *v4 = static_cast<const ArgumentsGetterFunction *>(getter)->engine(); - Scope scope(v4); Scoped<ArgumentsGetterFunction> g(scope, static_cast<const ArgumentsGetterFunction *>(getter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); - if (!o) - return v4->throwTypeError(); + if (!o) { + scope.result = v4->throwTypeError(); + return; + } Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->callData->argc)); - return o->context()->callData->args[g->index()].asReturnedValue(); + scope.result = o->context()->callData->args[g->index()]; } DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction); -ReturnedValue ArgumentsSetterFunction::call(const Managed *setter, CallData *callData) +void ArgumentsSetterFunction::call(const Managed *setter, Scope &scope, CallData *callData) { ExecutionEngine *v4 = static_cast<const ArgumentsSetterFunction *>(setter)->engine(); - Scope scope(v4); Scoped<ArgumentsSetterFunction> s(scope, static_cast<const ArgumentsSetterFunction *>(setter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); - if (!o) - return v4->throwTypeError(); + if (!o) { + scope.result = v4->throwTypeError(); + return; + } Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->callData->argc)); o->context()->callData->args[s->index()] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined(); - return Encode::undefined(); + scope.result = Encode::undefined(); } void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e) diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index eeedcaf995..6ccfd89fd4 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -88,7 +88,7 @@ struct ArgumentsGetterFunction: FunctionObject V4_OBJECT2(ArgumentsGetterFunction, FunctionObject) uint index() const { return d()->index; } - static ReturnedValue call(const Managed *that, CallData *d); + static void call(const Managed *that, Scope &scope, CallData *d); }; inline @@ -103,7 +103,7 @@ struct ArgumentsSetterFunction: FunctionObject V4_OBJECT2(ArgumentsSetterFunction, FunctionObject) uint index() const { return d()->index; } - static ReturnedValue call(const Managed *that, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; inline diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index d170bde0e8..e006773c9e 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -51,29 +51,34 @@ Heap::ArrayBufferCtor::ArrayBufferCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ArrayBufferCtor::construct(const Managed *m, CallData *callData) +void ArrayBufferCtor::construct(const Managed *m, Scope &scope, CallData *callData) { ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); - Scope scope(v4); ScopedValue l(scope, callData->argument(0)); double dl = l->toInteger(); - if (v4->hasException) - return Encode::undefined(); + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } uint len = (uint)qBound(0., dl, (double)UINT_MAX); - if (len != dl) - return v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length")); + if (len != dl) { + scope.result = v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length")); + return; + } Scoped<ArrayBuffer> a(scope, v4->newArrayBuffer(len)); - if (scope.engine->hasException) - return Encode::undefined(); - return a.asReturnedValue(); + if (scope.engine->hasException) { + scope.result = Encode::undefined(); + } else { + scope.result = a->asReturnedValue(); + } } -ReturnedValue ArrayBufferCtor::call(const Managed *that, CallData *callData) +void ArrayBufferCtor::call(const Managed *that, Scope &scope, CallData *callData) { - return construct(that, callData); + construct(that, scope, callData); } ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx) @@ -184,7 +189,8 @@ ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx) ScopedCallData callData(scope, 1); double newLen = qMax(final - first, 0.); callData->args[0] = QV4::Encode(newLen); - QV4::Scoped<ArrayBuffer> newBuffer(scope, constructor->construct(callData)); + constructor->construct(scope, callData); + QV4::Scoped<ArrayBuffer> newBuffer(scope, scope.result.asReturnedValue()); if (!newBuffer || newBuffer->d()->data->size < (int)newLen) return scope.engine->throwTypeError(); diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index 0413d2f28d..d079aeb9f7 100644 --- a/src/qml/jsruntime/qv4arraybuffer_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -78,8 +78,8 @@ struct ArrayBufferCtor: FunctionObject { V4_OBJECT2(ArrayBufferCtor, FunctionObject) - static ReturnedValue construct(const Managed *m, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); static ReturnedValue method_isView(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 3521673461..4d15c6c137 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -54,18 +54,19 @@ Heap::ArrayCtor::ArrayCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ArrayCtor::construct(const Managed *m, CallData *callData) +void ArrayCtor::construct(const Managed *m, Scope &scope, CallData *callData) { ExecutionEngine *v4 = static_cast<const ArrayCtor *>(m)->engine(); - Scope scope(v4); ScopedArrayObject a(scope, v4->newArrayObject()); uint len; if (callData->argc == 1 && callData->args[0].isNumber()) { bool ok; len = callData->args[0].asArrayLength(&ok); - if (!ok) - return v4->throwRangeError(callData->args[0]); + if (!ok) { + scope.result = v4->throwRangeError(callData->args[0]); + return; + } if (len < 0x1000) a->arrayReserve(len); @@ -76,12 +77,12 @@ ReturnedValue ArrayCtor::construct(const Managed *m, CallData *callData) } a->setArrayLengthUnchecked(len); - return a.asReturnedValue(); + scope.result = a.asReturnedValue(); } -ReturnedValue ArrayCtor::call(const Managed *that, CallData *callData) +void ArrayCtor::call(const Managed *that, Scope &scope, CallData *callData) { - return construct(that, callData); + construct(that, scope, callData); } void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) @@ -132,7 +133,8 @@ ReturnedValue ArrayPrototype::method_toString(CallContext *ctx) if (!!f) { ScopedCallData d(scope, 0); d->thisObject = ctx->thisObject(); - return f->call(d); + f->call(scope, d); + return scope.result.asReturnedValue(); } return ObjectPrototype::method_toString(ctx); } @@ -704,7 +706,6 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx) ScopedCallData callData(scope, 3); callData->args[2] = instance; callData->thisObject = ctx->argument(1); - ScopedValue r(scope); ScopedValue v(scope); bool ok = true; @@ -716,8 +717,8 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx) callData->args[0] = v; callData->args[1] = Primitive::fromDouble(k); - r = callback->call(callData); - ok = r->toBoolean(); + callback->call(scope, callData); + ok = scope.result.toBoolean(); } return Encode(ok); } @@ -740,7 +741,6 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx) callData->args[2] = instance; ScopedValue v(scope); - ScopedValue r(scope); for (uint k = 0; k < len; ++k) { bool exists; v = instance->getIndexed(k, &exists); @@ -749,8 +749,8 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx) callData->args[0] = v; callData->args[1] = Primitive::fromDouble(k); - r = callback->call(callData); - if (r->toBoolean()) + callback->call(scope, callData); + if (scope.result.toBoolean()) return Encode(true); } return Encode(false); @@ -782,7 +782,7 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx) callData->args[0] = v; callData->args[1] = Primitive::fromDouble(k); - callback->call(callData); + callback->call(scope, callData); } return Encode::undefined(); } @@ -804,7 +804,6 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx) a->arrayReserve(len); a->setArrayLengthUnchecked(len); - ScopedValue mapped(scope); ScopedCallData callData(scope, 3); callData->thisObject = ctx->argument(1); callData->args[2] = instance; @@ -818,8 +817,8 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx) callData->args[0] = v; callData->args[1] = Primitive::fromDouble(k); - mapped = callback->call(callData); - a->arraySet(k, mapped); + callback->call(scope, callData); + a->arraySet(k, scope.result); } return a.asReturnedValue(); } @@ -840,7 +839,6 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject()); a->arrayReserve(len); - ScopedValue selected(scope); ScopedCallData callData(scope, 3); callData->thisObject = ctx->argument(1); callData->args[2] = instance; @@ -856,8 +854,8 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) callData->args[0] = v; callData->args[1] = Primitive::fromDouble(k); - selected = callback->call(callData); - if (selected->toBoolean()) { + callback->call(scope, callData); + if (scope.result.toBoolean()) { a->arraySet(to, v); ++to; } @@ -879,17 +877,16 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) return ctx->engine()->throwTypeError(); uint k = 0; - ScopedValue acc(scope); ScopedValue v(scope); if (ctx->argc() > 1) { - acc = ctx->argument(1); + scope.result = ctx->argument(1); } else { bool kPresent = false; while (k < len && !kPresent) { v = instance->getIndexed(k, &kPresent); if (kPresent) - acc = v; + scope.result = v; ++k; } if (!kPresent) @@ -898,21 +895,21 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) ScopedCallData callData(scope, 4); callData->thisObject = Primitive::undefinedValue(); - callData->args[0] = acc; + callData->args[0] = scope.result; callData->args[3] = instance; while (k < len) { bool kPresent; v = instance->getIndexed(k, &kPresent); if (kPresent) { - callData->args[0] = acc; + callData->args[0] = scope.result; callData->args[1] = v; callData->args[2] = Primitive::fromDouble(k); - acc = callback->call(callData); + callback->call(scope, callData); } ++k; } - return acc->asReturnedValue(); + return scope.result.asReturnedValue(); } ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) @@ -935,16 +932,15 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) } uint k = len; - ScopedValue acc(scope); ScopedValue v(scope); if (ctx->argc() > 1) { - acc = ctx->argument(1); + scope.result = ctx->argument(1); } else { bool kPresent = false; while (k > 0 && !kPresent) { v = instance->getIndexed(k - 1, &kPresent); if (kPresent) - acc = v; + scope.result = v; --k; } if (!kPresent) @@ -959,13 +955,13 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) bool kPresent; v = instance->getIndexed(k - 1, &kPresent); if (kPresent) { - callData->args[0] = acc; + callData->args[0] = scope.result; callData->args[1] = v; callData->args[2] = Primitive::fromDouble(k - 1); - acc = callback->call(callData); + callback->call(scope, callData); } --k; } - return acc->asReturnedValue(); + return scope.result.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index bae5f9e0da..f49ed76b02 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -70,8 +70,8 @@ struct ArrayCtor: FunctionObject { V4_OBJECT2(ArrayCtor, FunctionObject) - static ReturnedValue construct(const Managed *m, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; struct ArrayPrototype: ArrayObject diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index d9da7d7754..57c54e15c4 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -50,17 +50,16 @@ Heap::BooleanCtor::BooleanCtor(QV4::ExecutionContext *scope) { } -ReturnedValue BooleanCtor::construct(const Managed *m, CallData *callData) +void BooleanCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const BooleanCtor *>(m)->engine()); bool n = callData->argc ? callData->args[0].toBoolean() : false; - return Encode(scope.engine->newBooleanObject(n)); + scope.result = Encode(scope.engine->newBooleanObject(n)); } -ReturnedValue BooleanCtor::call(const Managed *, CallData *callData) +void BooleanCtor::call(const Managed *, Scope &scope, CallData *callData) { bool value = callData->argc ? callData->args[0].toBoolean() : 0; - return Encode(value); + scope.result = Encode(value); } void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor) diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h index eedafa6126..17543e33e0 100644 --- a/src/qml/jsruntime/qv4booleanobject_p.h +++ b/src/qml/jsruntime/qv4booleanobject_p.h @@ -70,8 +70,8 @@ struct BooleanCtor: FunctionObject { V4_OBJECT2(BooleanCtor, FunctionObject) - static ReturnedValue construct(const Managed *, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; struct BooleanPrototype: BooleanObject diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index f296ffd71e..fac3d5316c 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -54,32 +54,34 @@ Heap::DataViewCtor::DataViewCtor(QV4::ExecutionContext *scope) { } -ReturnedValue DataViewCtor::construct(const Managed *m, CallData *callData) +void DataViewCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const Object *>(m)->engine()); Scoped<ArrayBuffer> buffer(scope, callData->argument(0)); - if (!buffer) - return scope.engine->throwTypeError(); + if (!buffer) { + scope.result = scope.engine->throwTypeError(); + return; + } 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")); + if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength) { + scope.result = scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range")); + return; + } Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>()); a->d()->buffer = buffer->d(); a->d()->byteLength = byteLength; a->d()->byteOffset = byteOffset; - return a.asReturnedValue(); - + scope.result = a.asReturnedValue(); } -ReturnedValue DataViewCtor::call(const Managed *that, CallData *callData) +void DataViewCtor::call(const Managed *that, Scope &scope, CallData *callData) { - return construct(that, callData); + construct(that, scope, callData); } diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h index 2e8e94cecd..f996a4c2f1 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -76,8 +76,8 @@ struct DataViewCtor: FunctionObject { V4_OBJECT2(DataViewCtor, FunctionObject) - static ReturnedValue construct(const Managed *m, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; struct DataView : Object diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 0cd72d6811..6acc76cdd8 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -651,9 +651,8 @@ Heap::DateCtor::DateCtor(QV4::ExecutionContext *scope) { } -ReturnedValue DateCtor::construct(const Managed *m, CallData *callData) +void DateCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const DateCtor *>(m)->engine()); double t = 0; if (callData->argc == 0) @@ -687,13 +686,13 @@ ReturnedValue DateCtor::construct(const Managed *m, CallData *callData) t = TimeClip(UTC(t)); } - return Encode(scope.engine->newDateObject(Primitive::fromDouble(t))); + scope.result = Encode(scope.engine->newDateObject(Primitive::fromDouble(t))); } -ReturnedValue DateCtor::call(const Managed *m, CallData *) +void DateCtor::call(const Managed *m, Scope &scope, CallData *) { double t = currentTime(); - return static_cast<const DateCtor *>(m)->engine()->newString(ToString(t))->asReturnedValue(); + scope.result = static_cast<const DateCtor *>(m)->engine()->newString(ToString(t)); } void DatePrototype::init(ExecutionEngine *engine, Object *ctor) @@ -1311,7 +1310,8 @@ ReturnedValue DatePrototype::method_toJSON(CallContext *ctx) ScopedCallData callData(scope); callData->thisObject = ctx->thisObject(); - return toIso->call(callData); + toIso->call(scope, callData); + return scope.result.asReturnedValue(); } void DatePrototype::timezoneUpdated() diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index e3615d76a7..13e9e04040 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -104,8 +104,8 @@ struct DateCtor: FunctionObject { V4_OBJECT2(DateCtor, FunctionObject) - static ReturnedValue construct(const Managed *, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *); + static void construct(const Managed *, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *); }; struct DatePrototype: DateObject diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index f560b3be4f..4a26b8b662 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1506,6 +1506,11 @@ void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject) Q_UNUSED(baseObject); } +void ExecutionEngine::failStackLimitCheck(Scope &scope) +{ + scope.result = throwRangeError(QStringLiteral("Maximum call stack size exceeded.")); +} + // Converts a JS value to a meta-type. // data must point to a place that can store a value of the given type. // Returns true if conversion succeeded, false otherwise. diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 933241ea27..ada6941381 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -478,7 +478,10 @@ public: void assertObjectBelongsToEngine(const Heap::Base &baseObject); - bool checkStackLimits(ReturnedValue &exception); + bool checkStackLimits(Scope &scope); + +private: + void failStackLimitCheck(Scope &scope); }; // This is a trick to tell the code generators that functions taking a NoThrowContext won't @@ -571,7 +574,7 @@ inline void Value::mark(ExecutionEngine *e) o->mark(e); } -#define CHECK_STACK_LIMITS(v4) { ReturnedValue e; if ((v4)->checkStackLimits(e)) return e; } \ +#define CHECK_STACK_LIMITS(v4, scope) if ((v4)->checkStackLimits(scope)) return; \ ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4); struct ExecutionEngineCallDepthRecorder @@ -582,10 +585,10 @@ struct ExecutionEngineCallDepthRecorder ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; } }; -inline bool ExecutionEngine::checkStackLimits(ReturnedValue &exception) +inline bool ExecutionEngine::checkStackLimits(Scope &scope) { if (Q_UNLIKELY((jsStackTop > jsStackLimit) || (callDepth >= maxCallDepth))) { - exception = throwRangeError(QStringLiteral("Maximum call stack size exceeded.")); + failStackLimitCheck(scope); return true; } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 2db04bbfda..3763bf2613 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -239,16 +239,15 @@ Heap::ErrorCtor::ErrorCtor(QV4::ExecutionContext *scope, const QString &name) { } -ReturnedValue ErrorCtor::construct(const Managed *m, CallData *callData) +void ErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const ErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return ErrorObject::create<ErrorObject>(scope.engine, v)->asReturnedValue(); + scope.result = ErrorObject::create<ErrorObject>(scope.engine, v); } -ReturnedValue ErrorCtor::call(const Managed *that, CallData *callData) +void ErrorCtor::call(const Managed *that, Scope &scope, CallData *callData) { - return static_cast<const Object *>(that)->construct(callData); + static_cast<const Object *>(that)->construct(scope, callData); } Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope) @@ -256,11 +255,10 @@ Heap::EvalErrorCtor::EvalErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue EvalErrorCtor::construct(const Managed *m, CallData *callData) +void EvalErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const EvalErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return ErrorObject::create<EvalErrorObject>(scope.engine, v)->asReturnedValue(); + scope.result = ErrorObject::create<EvalErrorObject>(scope.engine, v); } Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope) @@ -268,11 +266,10 @@ Heap::RangeErrorCtor::RangeErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue RangeErrorCtor::construct(const Managed *m, CallData *callData) +void RangeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const RangeErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return ErrorObject::create<RangeErrorObject>(scope.engine, v)->asReturnedValue(); + scope.result = ErrorObject::create<RangeErrorObject>(scope.engine, v); } Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope) @@ -280,11 +277,10 @@ Heap::ReferenceErrorCtor::ReferenceErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ReferenceErrorCtor::construct(const Managed *m, CallData *callData) +void ReferenceErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const ReferenceErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return ErrorObject::create<ReferenceErrorObject>(scope.engine, v)->asReturnedValue(); + scope.result = ErrorObject::create<ReferenceErrorObject>(scope.engine, v); } Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope) @@ -292,11 +288,10 @@ Heap::SyntaxErrorCtor::SyntaxErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue SyntaxErrorCtor::construct(const Managed *m, CallData *callData) +void SyntaxErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const SyntaxErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return ErrorObject::create<SyntaxErrorObject>(scope.engine, v)->asReturnedValue(); + scope.result = ErrorObject::create<SyntaxErrorObject>(scope.engine, v); } Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope) @@ -304,11 +299,10 @@ Heap::TypeErrorCtor::TypeErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue TypeErrorCtor::construct(const Managed *m, CallData *callData) +void TypeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const TypeErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return ErrorObject::create<TypeErrorObject>(scope.engine, v)->asReturnedValue(); + scope.result = ErrorObject::create<TypeErrorObject>(scope.engine, v); } Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope) @@ -316,11 +310,10 @@ Heap::URIErrorCtor::URIErrorCtor(QV4::ExecutionContext *scope) { } -ReturnedValue URIErrorCtor::construct(const Managed *m, CallData *callData) +void URIErrorCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const URIErrorCtor *>(m)->engine()); ScopedValue v(scope, callData->argument(0)); - return ErrorObject::create<URIErrorObject>(scope.engine, v)->asReturnedValue(); + scope.result = ErrorObject::create<URIErrorObject>(scope.engine, v); } void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t) diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 1ca2fedd7b..42a3d05d9f 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -221,50 +221,50 @@ struct ErrorCtor: FunctionObject { V4_OBJECT2(ErrorCtor, FunctionObject) - static ReturnedValue construct(const Managed *, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; struct EvalErrorCtor: ErrorCtor { V4_OBJECT2(EvalErrorCtor, ErrorCtor) - static ReturnedValue construct(const Managed *m, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); }; struct RangeErrorCtor: ErrorCtor { V4_OBJECT2(RangeErrorCtor, ErrorCtor) - static ReturnedValue construct(const Managed *m, CallData *callData); + static void construct(const Managed *, Scope &scope, CallData *callData); }; struct ReferenceErrorCtor: ErrorCtor { V4_OBJECT2(ReferenceErrorCtor, ErrorCtor) - static ReturnedValue construct(const Managed *m, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); }; struct SyntaxErrorCtor: ErrorCtor { V4_OBJECT2(SyntaxErrorCtor, ErrorCtor) - static ReturnedValue construct(const Managed *m, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); }; struct TypeErrorCtor: ErrorCtor { V4_OBJECT2(TypeErrorCtor, ErrorCtor) - static ReturnedValue construct(const Managed *m, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); }; struct URIErrorCtor: ErrorCtor { V4_OBJECT2(URIErrorCtor, ErrorCtor) - static ReturnedValue construct(const Managed *m, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 5d2c57a2ba..041044930b 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -166,14 +166,6 @@ ReturnedValue FunctionObject::name() const return get(scope()->engine->id_name()); } - -ReturnedValue FunctionObject::newInstance() -{ - Scope scope(internalClass()->engine); - ScopedCallData callData(scope); - return construct(callData); -} - ReturnedValue FunctionObject::construct(const Managed *that, CallData *) { return static_cast<const FunctionObject *>(that)->engine()->throwTypeError(); @@ -251,9 +243,8 @@ Heap::FunctionCtor::FunctionCtor(QV4::ExecutionContext *scope) } // 15.3.2 -ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) +void FunctionCtor::construct(const Managed *that, Scope &scope, CallData *callData) { - Scope scope(static_cast<const Object *>(that)->engine()); Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that)); QString arguments; @@ -266,8 +257,10 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) } body = callData->args[callData->argc - 1].toQString(); } - if (scope.engine->hasException) - return Encode::undefined(); + if (scope.engine->hasException) { + scope.result = Encode::undefined(); + return; + } QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1Char('}'); @@ -278,13 +271,17 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) const bool parsed = parser.parseExpression(); - if (!parsed) - return scope.engine->throwSyntaxError(QLatin1String("Parse error")); + if (!parsed) { + scope.result = scope.engine->throwSyntaxError(QLatin1String("Parse error")); + return; + } using namespace QQmlJS::AST; FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode()); - if (!fe) - return scope.engine->throwSyntaxError(QLatin1String("Parse error")); + if (!fe) { + scope.result = scope.engine->throwSyntaxError(QLatin1String("Parse error")); + return; + } IR::Module module(scope.engine->debugger != 0); @@ -297,13 +294,13 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) Function *vmf = compilationUnit->linkToEngine(scope.engine); ExecutionContext *global = scope.engine->rootContext(); - return FunctionObject::createScriptFunction(global, vmf)->asReturnedValue(); + scope.result = FunctionObject::createScriptFunction(global, vmf); } // 15.3.1: This is equivalent to new Function(...) -ReturnedValue FunctionCtor::call(const Managed *that, CallData *callData) +void FunctionCtor::call(const Managed *that, Scope &scope, CallData *callData) { - return construct(that, callData); + construct(that, scope, callData); } DEFINE_OBJECT_VTABLE(FunctionPrototype); @@ -376,7 +373,8 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) } callData->thisObject = ctx->argument(0); - return o->call(callData); + o->call(scope, callData); + return scope.result.asReturnedValue(); } ReturnedValue FunctionPrototype::method_call(CallContext *ctx) @@ -393,7 +391,9 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) callData->args[i - 1] = ctx->args()[i]; } callData->thisObject = ctx->argument(0); - return o->call(callData); + + o->call(scope, callData); + return scope.result.asReturnedValue(); } ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) @@ -422,14 +422,15 @@ Heap::ScriptFunction::ScriptFunction(QV4::ExecutionContext *scope, Function *fun { } -ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData) +void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData) { - ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); @@ -442,39 +443,37 @@ ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData) Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); v4->pushContext(ctx); - ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); + scope.result = Q_V4_PROFILE(v4, f->function()); if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction); - - if (v4->hasException) - return Encode::undefined(); + QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); - if (result->isObject()) - return result->asReturnedValue(); - return obj.asReturnedValue(); + if (v4->hasException) { + scope.result = Encode::undefined(); + } else if (!scope.result.isObject()) { + scope.result = obj.asReturnedValue(); + } } -ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData) +void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) { - ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); v4->pushContext(ctx); - ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); + scope.result = Q_V4_PROFILE(v4, f->function()); if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(scope.engine, f->function()->compiledFunction); - - return result->asReturnedValue(); + QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); } DEFINE_OBJECT_VTABLE(SimpleScriptFunction); @@ -511,14 +510,15 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F } } -ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *callData) +void SimpleScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData) { - ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); @@ -542,24 +542,24 @@ ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *cal v4->pushContext(&ctx); Q_ASSERT(v4->current == &ctx); - ScopedObject result(scope, Q_V4_PROFILE(v4, f->function())); + scope.result = Q_V4_PROFILE(v4, f->function()); if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction); + QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); - if (!result) - return callData->thisObject.asReturnedValue(); - return result.asReturnedValue(); + if (!scope.result.isManaged() || !scope.result.managed()) + scope.result = callData->thisObject; } -ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData) +void SimpleScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) { - ExecutionEngine *v4 = static_cast<const SimpleScriptFunction *>(that)->internalClass()->engine; - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); @@ -579,12 +579,10 @@ ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData v4->pushContext(&ctx); Q_ASSERT(v4->current == &ctx); - ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); + scope.result = Q_V4_PROFILE(v4, f->function()); if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction); - - return result->asReturnedValue(); + QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); } Heap::Object *SimpleScriptFunction::protoForConstructor() @@ -606,20 +604,21 @@ Heap::BuiltinFunction::BuiltinFunction(QV4::ExecutionContext *scope, QV4::String { } -ReturnedValue BuiltinFunction::construct(const Managed *f, CallData *) +void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *) { - return static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); + scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); } -ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) +void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) { const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that); - ExecutionEngine *v4 = f->internalClass()->engine; - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); CallContext::Data ctx(v4); @@ -630,18 +629,19 @@ ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) v4->pushContext(&ctx); Q_ASSERT(v4->current == &ctx); - return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext)); + scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext)); } -ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callData) +void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) { const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that); - ExecutionEngine *v4 = f->internalClass()->engine; - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); CallContext::Data ctx(v4); @@ -652,7 +652,7 @@ ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callDa v4->pushContext(&ctx); Q_ASSERT(v4->current == &ctx); - return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index); + scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index); } DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction); @@ -685,12 +685,13 @@ Heap::BoundFunction::BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionOb f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } -ReturnedValue BoundFunction::call(const Managed *that, CallData *dd) +void BoundFunction::call(const Managed *that, Scope &scope, CallData *dd) { const BoundFunction *f = static_cast<const BoundFunction *>(that); - Scope scope(f->engine()); - if (scope.hasException()) - return Encode::undefined(); + if (scope.hasException()) { + scope.result = Encode::undefined(); + return; + } Scoped<MemberData> boundArgs(scope, f->boundArgs()); ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc); @@ -702,15 +703,16 @@ ReturnedValue BoundFunction::call(const Managed *that, CallData *dd) } memcpy(argp, dd->args, dd->argc*sizeof(Value)); ScopedFunctionObject t(scope, f->target()); - return t->call(callData); + t->call(scope, callData); } -ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd) +void BoundFunction::construct(const Managed *that, Scope &scope, CallData *dd) { const BoundFunction *f = static_cast<const BoundFunction *>(that); - Scope scope(f->engine()); - if (scope.hasException()) - return Encode::undefined(); + if (scope.hasException()) { + scope.result = Encode::undefined(); + return; + } Scoped<MemberData> boundArgs(scope, f->boundArgs()); ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc); @@ -721,7 +723,7 @@ ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd) } memcpy(argp, dd->args, dd->argc*sizeof(Value)); ScopedFunctionObject t(scope, f->target()); - return t->construct(callData); + t->construct(scope, callData); } void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e) diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 4a4545eca4..be80b87873 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -145,8 +145,6 @@ struct Q_QML_EXPORT FunctionObject: Object { void init(String *name, bool createProto); - ReturnedValue newInstance(); - using Object::construct; using Object::call; static ReturnedValue construct(const Managed *that, CallData *); @@ -178,8 +176,8 @@ struct FunctionCtor: FunctionObject { V4_OBJECT2(FunctionCtor, FunctionObject) - static ReturnedValue construct(const Managed *that, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *that, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; struct FunctionPrototype: FunctionObject @@ -202,20 +200,20 @@ struct Q_QML_EXPORT BuiltinFunction: FunctionObject { return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code); } - static ReturnedValue construct(const Managed *, CallData *); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *, Scope &scope, CallData *); + static void call(const Managed *that, Scope &scope, CallData *callData); }; struct IndexedBuiltinFunction: FunctionObject { V4_OBJECT2(IndexedBuiltinFunction, FunctionObject) - static ReturnedValue construct(const Managed *m, CallData *) + static void construct(const Managed *m, Scope &scope, CallData *) { - return static_cast<const IndexedBuiltinFunction *>(m)->engine()->throwTypeError(); + scope.result = static_cast<const IndexedBuiltinFunction *>(m)->engine()->throwTypeError(); } - static ReturnedValue call(const Managed *that, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; Heap::IndexedBuiltinFunction::IndexedBuiltinFunction(QV4::ExecutionContext *scope, uint index, @@ -231,8 +229,8 @@ struct SimpleScriptFunction: FunctionObject { V4_OBJECT2(SimpleScriptFunction, FunctionObject) V4_INTERNALCLASS(simpleScriptFunctionClass) - static ReturnedValue construct(const Managed *, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); Heap::Object *protoForConstructor(); }; @@ -240,8 +238,8 @@ struct SimpleScriptFunction: FunctionObject { struct ScriptFunction: SimpleScriptFunction { V4_OBJECT2(ScriptFunction, FunctionObject) - static ReturnedValue construct(const Managed *, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; @@ -257,8 +255,8 @@ struct BoundFunction: FunctionObject { Value boundThis() const { return d()->boundThis; } Heap::MemberData *boundArgs() const { return d()->boundArgs; } - static ReturnedValue construct(const Managed *, CallData *d); - static ReturnedValue call(const Managed *that, CallData *dd); + static void construct(const Managed *, Scope &scope, CallData *d); + static void call(const Managed *that, Scope &scope, CallData *dd); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 2c767e3302..d8130c1cac 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -338,13 +338,14 @@ Heap::EvalFunction::EvalFunction(QV4::ExecutionContext *scope) f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(1)); } -ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const +void EvalFunction::evalCall(Scope &scope, CallData *callData, bool directCall) const { - if (callData->argc < 1) - return Encode::undefined(); + if (callData->argc < 1) { + scope.result = Encode::undefined(); + return; + } ExecutionEngine *v4 = engine(); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); ExecutionContext *currentContext = v4->currentContext; @@ -356,8 +357,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const ctx = v4->pushGlobalContext(); } - if (!callData->args[0].isString()) - return callData->args[0].asReturnedValue(); + if (!callData->args[0].isString()) { + scope.result = callData->args[0].asReturnedValue(); + return; + } const QString code = callData->args[0].stringValue()->toQString(); bool inheritContext = !ctx->d()->strictMode; @@ -366,18 +369,23 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const script.strictMode = (directCall && currentContext->d()->strictMode); script.inheritContext = inheritContext; script.parse(); - if (v4->hasException) - return Encode::undefined(); + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } Function *function = script.function(); - if (!function) - return Encode::undefined(); + if (!function) { + scope.result = Encode::undefined(); + return; + } if (function->isStrict() || (ctx->d()->strictMode)) { ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function)); ScopedCallData callData(scope, 0); callData->thisObject = ctx->thisObject(); - return e->call(callData); + e->call(scope, callData); + return; } ContextStateSaver stateSaver(scope, ctx); @@ -386,14 +394,14 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const ctx->d()->strictMode = false; ctx->d()->compilationUnit = function->compilationUnit; - return Q_V4_PROFILE(ctx->engine(), function); + scope.result = Q_V4_PROFILE(ctx->engine(), function); } -ReturnedValue EvalFunction::call(const Managed *that, CallData *callData) +void EvalFunction::call(const Managed *that, Scope &scope, CallData *callData) { // indirect call - return static_cast<const EvalFunction *>(that)->evalCall(callData, false); + static_cast<const EvalFunction *>(that)->evalCall(scope, callData, false); } diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h index ea7a3b06ce..403639f8c1 100644 --- a/src/qml/jsruntime/qv4globalobject_p.h +++ b/src/qml/jsruntime/qv4globalobject_p.h @@ -69,9 +69,9 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject { V4_OBJECT2(EvalFunction, FunctionObject) - ReturnedValue evalCall(CallData *callData, bool directCall) const; + void evalCall(Scope &scope, CallData *callData, bool directCall) const; - static ReturnedValue call(const Managed *that, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; struct GlobalFunctions diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index b3462fe9b1..c33d2cad11 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -122,7 +122,7 @@ void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status) QV4::ScopedCallData callData(scope, 1); callData->thisObject = v4->globalObject->asReturnedValue(); callData->args[0] = status; - f->call(callData); + f->call(scope, callData); if (scope.hasException()) scope.engine->catchException(); } diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 0ae7c33dea..7661dd1903 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -685,53 +685,53 @@ static QString quote(const QString &str) QString Stringify::Str(const QString &key, const Value &v) { Scope scope(v4); + scope.result = v; - ScopedValue value(scope, v); - ScopedObject o(scope, value); + ScopedObject o(scope, scope.result); if (o) { ScopedString s(scope, v4->newString(QStringLiteral("toJSON"))); ScopedFunctionObject toJSON(scope, o->get(s)); if (!!toJSON) { ScopedCallData callData(scope, 1); - callData->thisObject = value; + callData->thisObject = scope.result; callData->args[0] = v4->newString(key); - value = toJSON->call(callData); + toJSON->call(scope, callData); } } if (replacerFunction) { ScopedObject holder(scope, v4->newObject()); - holder->put(scope.engine, QString(), value); + holder->put(scope.engine, QString(), scope.result); ScopedCallData callData(scope, 2); callData->args[0] = v4->newString(key); - callData->args[1] = value; + callData->args[1] = scope.result; callData->thisObject = holder; - value = replacerFunction->call(callData); + replacerFunction->call(scope, callData); } - o = value->asReturnedValue(); + o = scope.result.asReturnedValue(); if (o) { if (NumberObject *n = o->as<NumberObject>()) - value = Encode(n->value()); + scope.result = Encode(n->value()); else if (StringObject *so = o->as<StringObject>()) - value = so->d()->string; + scope.result = so->d()->string; else if (BooleanObject *b = o->as<BooleanObject>()) - value = Encode(b->value()); + scope.result = Encode(b->value()); } - if (value->isNull()) + if (scope.result.isNull()) return QStringLiteral("null"); - if (value->isBoolean()) - return value->booleanValue() ? QStringLiteral("true") : QStringLiteral("false"); - if (value->isString()) - return quote(value->stringValue()->toQString()); - - if (value->isNumber()) { - double d = value->toNumber(); - return std::isfinite(d) ? value->toQString() : QStringLiteral("null"); + if (scope.result.isBoolean()) + return scope.result.booleanValue() ? QStringLiteral("true") : QStringLiteral("false"); + if (scope.result.isString()) + return quote(scope.result.stringValue()->toQString()); + + if (scope.result.isNumber()) { + double d = scope.result.toNumber(); + return std::isfinite(d) ? scope.result.toQString() : QStringLiteral("null"); } - o = value->asReturnedValue(); + o = scope.result.asReturnedValue(); if (o) { if (!o->as<FunctionObject>()) { if (o->as<ArrayObject>()) { diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 46e47307ef..42e561bc7c 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -451,7 +451,8 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const ScopedCallData callData(scope, 0); callData->thisObject = object; - return getter->call(callData); + getter->call(scope, callData); + return scope.result.asReturnedValue(); } } l->getter = getterFallback; @@ -473,7 +474,8 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const ScopedCallData callData(scope, 0); callData->thisObject = object; - return getter->call(callData); + getter->call(scope, callData); + return scope.result.asReturnedValue(); } } l->getter = getterFallback; @@ -498,7 +500,8 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const ScopedCallData callData(scope, 0); callData->thisObject = object; - return getter->call(callData); + getter->call(scope, callData); + return scope.result.asReturnedValue(); } } } @@ -542,7 +545,8 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engin ScopedCallData callData(scope, 0); callData->thisObject = object; - return getter->call(callData); + getter->call(scope, callData); + return scope.result.asReturnedValue(); } } l->getter = getterGeneric; @@ -562,7 +566,8 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin ScopedCallData callData(scope, 0); callData->thisObject = object; - return getter->call(callData); + getter->call(scope, callData); + return scope.result.asReturnedValue(); } } l->getter = getterGeneric; @@ -665,7 +670,8 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine) ScopedCallData callData(scope, 0); callData->thisObject = Primitive::undefinedValue(); - return getter->call(callData); + getter->call(scope, callData); + return scope.result.asReturnedValue(); } l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, engine); @@ -683,7 +689,8 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine) ScopedCallData callData(scope, 0); callData->thisObject = Primitive::undefinedValue(); - return getter->call(callData); + getter->call(scope, callData); + return scope.result.asReturnedValue(); } l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, engine); @@ -704,7 +711,8 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) ScopedCallData callData(scope, 0); callData->thisObject = Primitive::undefinedValue(); - return getter->call(callData); + getter->call(scope, callData); + return scope.result.asReturnedValue(); } } } diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index f6b3e9a2b3..d27eef1d79 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -76,17 +76,16 @@ Heap::NumberCtor::NumberCtor(QV4::ExecutionContext *scope) { } -ReturnedValue NumberCtor::construct(const Managed *m, CallData *callData) +void NumberCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(m->cast<NumberCtor>()->engine()); double dbl = callData->argc ? callData->args[0].toNumber() : 0.; - return Encode(scope.engine->newNumberObject(dbl)); + scope.result = Encode(scope.engine->newNumberObject(dbl)); } -ReturnedValue NumberCtor::call(const Managed *, CallData *callData) +void NumberCtor::call(const Managed *, Scope &scope, CallData *callData) { double dbl = callData->argc ? callData->args[0].toNumber() : 0.; - return Encode(dbl); + scope.result = Encode(dbl); } void NumberPrototype::init(ExecutionEngine *engine, Object *ctor) diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index bbe22af4bb..2416165c78 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -79,8 +79,8 @@ struct NumberCtor: FunctionObject { V4_OBJECT2(NumberCtor, FunctionObject) - static ReturnedValue construct(const Managed *that, CallData *callData); - static ReturnedValue call(const Managed *, CallData *callData); + static void construct(const Managed *that, Scope &scope, CallData *callData); + static void call(const Managed *, Scope &scope, CallData *callData); }; struct NumberPrototype: NumberObject diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index ff3208485e..0fc5f95dad 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -109,7 +109,8 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property Scope scope(f->engine()); ScopedCallData callData(scope); callData->thisObject = thisObject; - return f->call(callData); + f->call(scope, callData); + return scope.result.asReturnedValue(); } void Object::putValue(uint memberIndex, const Value &value) @@ -128,7 +129,7 @@ void Object::putValue(uint memberIndex, const Value &value) ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; - setter->call(callData); + setter->call(scope, callData); return; } goto reject; @@ -389,14 +390,14 @@ bool Object::hasOwnProperty(uint index) const return false; } -ReturnedValue Object::construct(const Managed *m, CallData *) +void Object::construct(const Managed *m, Scope &scope, CallData *) { - return static_cast<const Object *>(m)->engine()->throwTypeError(); + scope.result = static_cast<const Object *>(m)->engine()->throwTypeError(); } -ReturnedValue Object::call(const Managed *m, CallData *) +void Object::call(const Managed *m, Scope &scope, CallData *) { - return static_cast<const Object *>(m)->engine()->throwTypeError(); + scope.result = static_cast<const Object *>(m)->engine()->throwTypeError(); } ReturnedValue Object::get(const Managed *m, String *name, bool *hasProperty) @@ -744,7 +745,7 @@ void Object::internalPut(String *name, const Value &value) ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; - setter->call(callData); + setter->call(scope, callData); return; } @@ -814,7 +815,7 @@ void Object::internalPutIndexed(uint index, const Value &value) ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; - setter->call(callData); + setter->call(scope, callData); return; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index e4431a9fc9..114f542d18 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -112,8 +112,8 @@ struct Object : Base { struct ObjectVTable { VTable vTable; - ReturnedValue (*call)(const Managed *, CallData *data); - ReturnedValue (*construct)(const Managed *, CallData *data); + void (*call)(const Managed *, Scope &scope, CallData *data); + void (*construct)(const Managed *, Scope &scope, CallData *data); ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty); ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty); void (*put)(Managed *, String *name, const Value &value); @@ -324,14 +324,14 @@ public: { vtable()->advanceIterator(this, it, name, index, p, attributes); } uint getLength() const { return vtable()->getLength(this); } - inline ReturnedValue construct(CallData *d) const - { return vtable()->construct(this, d); } - inline ReturnedValue call(CallData *d) const - { return vtable()->call(this, d); } + inline void construct(Scope &scope, CallData *d) const + { return vtable()->construct(this, scope, d); } + inline void call(Scope &scope, CallData *d) const + { vtable()->call(this, scope, d); } protected: static void markObjects(Heap::Base *that, ExecutionEngine *e); - static ReturnedValue construct(const Managed *m, CallData *); - static ReturnedValue call(const Managed *m, CallData *); + static void construct(const Managed *m, Scope &scope, CallData *); + static void call(const Managed *m, Scope &scope, CallData *); static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 015294e48a..cfd76166f2 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -59,28 +59,30 @@ Heap::ObjectCtor::ObjectCtor(QV4::ExecutionContext *scope) { } -ReturnedValue ObjectCtor::construct(const Managed *that, CallData *callData) +void ObjectCtor::construct(const Managed *that, Scope &scope, CallData *callData) { const ObjectCtor *ctor = static_cast<const ObjectCtor *>(that); ExecutionEngine *v4 = ctor->engine(); - Scope scope(v4); if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) { ScopedObject obj(scope, v4->newObject()); ScopedObject proto(scope, ctor->get(v4->id_prototype())); if (!!proto) obj->setPrototype(proto); - return obj.asReturnedValue(); + scope.result = obj.asReturnedValue(); + } else { + scope.result = RuntimeHelpers::toObject(scope.engine, callData->args[0]); } - return RuntimeHelpers::toObject(scope.engine, callData->args[0]); } -ReturnedValue ObjectCtor::call(const Managed *m, CallData *callData) +void ObjectCtor::call(const Managed *m, Scope &scope, CallData *callData) { const ObjectCtor *ctor = static_cast<const ObjectCtor *>(m); ExecutionEngine *v4 = ctor->engine(); - if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) - return v4->newObject()->asReturnedValue(); - return RuntimeHelpers::toObject(v4, callData->args[0]); + if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) { + scope.result = v4->newObject()->asReturnedValue(); + } else { + scope.result = RuntimeHelpers::toObject(v4, callData->args[0]); + } } void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) @@ -413,7 +415,8 @@ ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx) return ctx->engine()->throwTypeError(); ScopedCallData callData(scope); callData->thisObject = o; - return f->call(callData); + f->call(scope, callData); + return scope.result.asReturnedValue(); } ReturnedValue ObjectPrototype::method_valueOf(CallContext *ctx) diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index ac1964103e..47a37b196f 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -70,8 +70,8 @@ struct ObjectCtor: FunctionObject { V4_OBJECT2(ObjectCtor, FunctionObject) - static ReturnedValue construct(const Managed *that, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *that, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; struct ObjectPrototype: Object diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 44c7fc9823..deed9b86a2 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -816,7 +816,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase } } - f->call(callData); + f->call(scope, callData); if (scope.hasException()) { QQmlError error = v4->catchExceptionAsQmlError(); if (error.description().isEmpty()) { @@ -1750,7 +1750,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index) { Scope valueScope(scope); - Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->allocObject<QObjectMethod>(scope)); + Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope)); method->d()->propertyCache = valueType->d()->propertyCache; method->d()->index = index; method->d()->valueTypeWrapper = valueType->d(); @@ -1810,25 +1810,32 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con return Encode::undefined(); } -ReturnedValue QObjectMethod::call(const Managed *m, CallData *callData) +void QObjectMethod::call(const Managed *m, Scope &scope, CallData *callData) { const QObjectMethod *This = static_cast<const QObjectMethod*>(m); - return This->callInternal(callData); + This->callInternal(callData, scope); } -ReturnedValue QObjectMethod::callInternal(CallData *callData) const +void QObjectMethod::callInternal(CallData *callData, Scope &scope) const { ExecutionEngine *v4 = engine(); ExecutionContext *context = v4->currentContext; - if (d()->index == DestroyMethod) - return method_destroy(context, callData->args, callData->argc); - else if (d()->index == ToStringMethod) - return method_toString(context); + if (d()->index == DestroyMethod) { + scope.result = method_destroy(context, callData->args, callData->argc); + return; + } + + else if (d()->index == ToStringMethod) { + scope.result = method_toString(context); + return; + } QQmlObjectOrGadget object(d()->object.data()); if (!d()->object) { - if (!d()->valueTypeWrapper) - return Encode::undefined(); + if (!d()->valueTypeWrapper) { + scope.result = Encode::undefined(); + return; + } object = QQmlObjectOrGadget(d()->propertyCache.data(), d()->valueTypeWrapper->gadgetPtr); } @@ -1837,16 +1844,20 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const if (d()->propertyCache) { QQmlPropertyData *data = d()->propertyCache->method(d()->index); - if (!data) - return QV4::Encode::undefined(); + if (!data) { + scope.result = QV4::Encode::undefined(); + return; + } method = *data; } else { const QMetaObject *mo = d()->object->metaObject(); const QMetaMethod moMethod = mo->method(d()->index); method.load(moMethod); - if (method.coreIndex == -1) - return QV4::Encode::undefined(); + if (method.coreIndex == -1) { + scope.result = QV4::Encode::undefined(); + return; + } // Look for overloaded methods QByteArray methodName = moMethod.name(); @@ -1862,21 +1873,20 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) const } if (method.isV4Function()) { - Scope scope(v4); - QV4::ScopedValue rv(scope, QV4::Primitive::undefinedValue()); - QQmlV4Function func(callData, rv, v4); + scope.result = QV4::Encode::undefined(); + QQmlV4Function func(callData, &scope.result, v4); QQmlV4Function *funcptr = &func; void *args[] = { 0, &funcptr }; object.metacall(QMetaObject::InvokeMetaMethod, method.coreIndex, args); - return rv->asReturnedValue(); + return; } if (!method.isOverload()) { - return CallPrecise(object, method, v4, callData); + scope.result = CallPrecise(object, method, v4, callData); } else { - return CallOverloaded(object, method, v4, callData, d()->propertyCache); + scope.result = CallOverloaded(object, method, v4, callData, d()->propertyCache); } } @@ -1936,10 +1946,10 @@ void QMetaObjectWrapper::init(ExecutionEngine *) { } } -ReturnedValue QMetaObjectWrapper::construct(const Managed *m, CallData *callData) +void QMetaObjectWrapper::construct(const Managed *m, Scope &scope, CallData *callData) { const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(m); - return This->constructInternal(callData); + scope.result = This->constructInternal(callData); } ReturnedValue QMetaObjectWrapper::constructInternal(CallData * callData) const { diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index c384321f1c..dab59886de 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -193,9 +193,9 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx) const; QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const; - static ReturnedValue call(const Managed *, CallData *callData); + static void call(const Managed *, Scope &scope, CallData *callData); - ReturnedValue callInternal(CallData *callData) const; + void callInternal(CallData *callData, Scope &scope) const; static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); @@ -209,7 +209,7 @@ struct Q_QML_EXPORT QMetaObjectWrapper : public QV4::FunctionObject V4_NEEDS_DESTROY static ReturnedValue create(ExecutionEngine *engine, const QMetaObject* metaObject); - static ReturnedValue construct(const Managed *, CallData *callData); + static void construct(const Managed *, Scope &scope, CallData *callData); static bool isEqualTo(Managed *a, Managed *b); const QMetaObject *metaObject() const { return d()->metaObject; } diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 05752dc6dc..ab00859b3b 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -231,34 +231,39 @@ void Heap::RegExpCtor::clearLastMatch() lastMatchEnd = 0; } -ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData) +void RegExpCtor::construct(const Managed *, Scope &scope, CallData *callData) { - Scope scope(static_cast<const Object *>(m)->engine()); - ScopedValue r(scope, callData->argument(0)); ScopedValue f(scope, callData->argument(1)); Scoped<RegExpObject> re(scope, r); if (re) { - if (!f->isUndefined()) - return scope.engine->throwTypeError(); + if (!f->isUndefined()) { + scope.result = scope.engine->throwTypeError(); + return; + } Scoped<RegExp> regexp(scope, re->value()); - return Encode(scope.engine->newRegExpObject(regexp, re->global())); + scope.result = Encode(scope.engine->newRegExpObject(regexp, re->global())); + return; } QString pattern; if (!r->isUndefined()) pattern = r->toQString(); - if (scope.hasException()) - return Encode::undefined(); + if (scope.hasException()) { + scope.result = Encode::undefined(); + return; + } bool global = false; bool ignoreCase = false; bool multiLine = false; if (!f->isUndefined()) { f = RuntimeHelpers::toString(scope.engine, f); - if (scope.hasException()) - return Encode::undefined(); + if (scope.hasException()) { + scope.result = Encode::undefined(); + return; + } QString str = f->stringValue()->toQString(); for (int i = 0; i < str.length(); ++i) { if (str.at(i) == QLatin1Char('g') && !global) { @@ -268,26 +273,31 @@ ReturnedValue RegExpCtor::construct(const Managed *m, CallData *callData) } else if (str.at(i) == QLatin1Char('m') && !multiLine) { multiLine = true; } else { - return scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor")); + scope.result = scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor")); + return; } } } Scoped<RegExp> regexp(scope, RegExp::create(scope.engine, pattern, ignoreCase, multiLine)); - if (!regexp->isValid()) - return scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression")); + if (!regexp->isValid()) { + scope.result = scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression")); + return; + } - return Encode(scope.engine->newRegExpObject(regexp, global)); + scope.result = Encode(scope.engine->newRegExpObject(regexp, global)); } -ReturnedValue RegExpCtor::call(const Managed *that, CallData *callData) +void RegExpCtor::call(const Managed *that, Scope &scope, CallData *callData) { if (callData->argc > 0 && callData->args[0].as<RegExpObject>()) { - if (callData->argc == 1 || callData->args[1].isUndefined()) - return callData->args[0].asReturnedValue(); + if (callData->argc == 1 || callData->args[1].isUndefined()) { + scope.result = callData->args[0]; + return; + } } - return construct(that, callData); + construct(that, scope, callData); } void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e) @@ -419,7 +429,8 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx) ScopedCallData callData(scope, ctx->argc()); memcpy(callData->args, ctx->args(), ctx->argc()*sizeof(Value)); - Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(callData)); + ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(scope, callData); + Scoped<RegExpObject> re(scope, scope.result.asReturnedValue()); r->d()->value = re->value(); r->d()->global = re->global(); diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 4bd91bbedd..655e120c16 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -140,8 +140,8 @@ struct RegExpCtor: FunctionObject int lastMatchStart() { return d()->lastMatchStart; } int lastMatchEnd() { return d()->lastMatchEnd; } - static ReturnedValue construct(const Managed *m, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 8f377dd664..c2dfdb1497 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -438,9 +438,9 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH ScopedValue conv(scope, object->get(meth1)); if (FunctionObject *o = conv->as<FunctionObject>()) { - ScopedValue r(scope, o->call(callData)); - if (r->isPrimitive()) - return r->asReturnedValue(); + o->call(scope, callData); + if (scope.result.isPrimitive()) + return scope.result.asReturnedValue(); } if (engine->hasException) @@ -448,9 +448,9 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH conv = object->get(meth2); if (FunctionObject *o = conv->as<FunctionObject>()) { - ScopedValue r(scope, o->call(callData)); - if (r->isPrimitive()) - return r->asReturnedValue(); + o->call(scope, callData); + if (scope.result.isPrimitive()) + return scope.result.asReturnedValue(); } return engine->throwTypeError(); @@ -943,10 +943,13 @@ ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint ind return engine->throwTypeError(); ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]); - if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) - return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true); + if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) { + static_cast<EvalFunction *>(o.getPointer())->evalCall(scope, callData, true); + } else { + o->call(scope, callData); + } - return o->call(callData); + return scope.result.asReturnedValue(); } @@ -974,10 +977,12 @@ ReturnedValue Runtime::method_callActivationProperty(ExecutionEngine *engine, in } if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) { - return static_cast<EvalFunction *>(o)->evalCall(callData, true); + static_cast<EvalFunction *>(o)->evalCall(scope, callData, true); + } else { + o->call(scope, callData); } - return o->call(callData); + return scope.result.asReturnedValue(); } ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData) @@ -988,7 +993,9 @@ ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex); return engine->throwTypeError(error); } - return o->call(callData); + + o->call(scope, callData); + return scope.result.asReturnedValue(); } ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData) @@ -1000,7 +1007,8 @@ ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engi return engine->throwTypeError(error); } - return o->call(callData); + o->call(scope, callData); + return scope.result.asReturnedValue(); } ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData) @@ -1022,12 +1030,14 @@ ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, int nameInde } ScopedFunctionObject o(scope, baseObject->get(name)); - if (!o) { + if (o) { + o->call(scope, callData); + return scope.result.asReturnedValue(); + } else { QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString(), callData->thisObject.toQStringNoThrow()); return engine->throwTypeError(error); } - return o->call(callData); } ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData) @@ -1035,10 +1045,13 @@ ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, uint i Lookup *l = engine->current->lookups + index; Value v; v = l->getter(l, engine, callData->thisObject); - if (!v.isObject()) + if (v.isObject()) { + Scope scope(engine); + v.objectValue()->call(scope, callData); + return scope.result.asReturnedValue(); + } else { return engine->throwTypeError(); - - return v.objectValue()->call(callData); + } } ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, const Value &index, CallData *callData) @@ -1055,7 +1068,8 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, const Value & if (!o) return engine->throwTypeError(); - return o->call(callData); + o->call(scope, callData); + return scope.result.asReturnedValue(); } ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, CallData *callData) @@ -1063,7 +1077,9 @@ ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &fu if (!func.isObject()) return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); - return func.objectValue()->call(callData); + Scope scope(engine); + func.objectValue()->call(scope, callData); + return scope.result.asReturnedValue(); } @@ -1074,10 +1090,12 @@ ReturnedValue Runtime::method_constructGlobalLookup(ExecutionEngine *engine, uin Lookup *l = engine->current->lookups + index; ScopedObject f(scope, l->globalGetter(l, engine)); - if (!f) + if (f) { + f->construct(scope, callData); + return scope.result.asReturnedValue(); + } else { return engine->throwTypeError(); - - return f->construct(callData); + } } @@ -1093,7 +1111,8 @@ ReturnedValue Runtime::method_constructActivationProperty(ExecutionEngine *engin if (!f) return engine->throwTypeError(); - return f->construct(callData); + f->construct(scope, callData); + return scope.result.asReturnedValue(); } ReturnedValue Runtime::method_constructValue(ExecutionEngine *engine, const Value &func, CallData *callData) @@ -1102,7 +1121,9 @@ ReturnedValue Runtime::method_constructValue(ExecutionEngine *engine, const Valu if (!f) return engine->throwTypeError(); - return f->construct(callData); + Scope scope(engine); + f->construct(scope, callData); + return scope.result.asReturnedValue(); } ReturnedValue Runtime::method_constructProperty(ExecutionEngine *engine, int nameIndex, CallData *callData) @@ -1114,10 +1135,13 @@ ReturnedValue Runtime::method_constructProperty(ExecutionEngine *engine, int nam return Encode::undefined(); ScopedObject f(scope, thisObject->get(name)); - if (!f) + if (f) { + Scope scope(engine); + f->construct(scope, callData); + return scope.result.asReturnedValue(); + } else { return engine->throwTypeError(); - - return f->construct(callData); + } } ReturnedValue Runtime::method_constructPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData) @@ -1125,10 +1149,14 @@ ReturnedValue Runtime::method_constructPropertyLookup(ExecutionEngine *engine, u Lookup *l = engine->current->lookups + index; Value v; v = l->getter(l, engine, callData->thisObject); - if (!v.isObject()) + if (v.isObject()) { + Scope scope(engine); + ScopedValue result(scope); + v.objectValue()->construct(scope, callData); + return scope.result.asReturnedValue(); + } else { return engine->throwTypeError(); - - return v.objectValue()->construct(callData); + } } diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index a6f7f8e0e7..aa811ddba4 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -71,14 +71,18 @@ struct ScopedValue; struct Scope { inline Scope(ExecutionContext *ctx) : engine(ctx->d()->engine) + , mark(engine->jsStackTop) + , result(*engine->jsAlloca(1)) { - mark = engine->jsStackTop; + result = Encode::undefined(); } explicit Scope(ExecutionEngine *e) : engine(e) + , mark(engine->jsStackTop) + , result(*engine->jsAlloca(1)) { - mark = engine->jsStackTop; + result = Encode::undefined(); } ~Scope() { @@ -93,7 +97,7 @@ struct Scope { engine->jsStackTop = mark; } - Value *alloc(int nValues) { + Value *alloc(int nValues) const { return engine->jsAlloca(nValues); } @@ -103,6 +107,7 @@ struct Scope { ExecutionEngine *engine; Value *mark; + Value &result; private: Q_DISABLE_COPY(Scope) @@ -190,59 +195,59 @@ struct Scoped Scoped(const Scope &scope) { - ptr = scope.engine->jsStackTop++; - ptr->setM(0); + ptr = scope.engine->jsAlloca(1); } Scoped(const Scope &scope, const Value &v) { - ptr = scope.engine->jsStackTop++; + ptr = scope.engine->jsAlloca(1); setPointer(v.as<T>()); } Scoped(const Scope &scope, Heap::Base *o) { Value v; v = o; - ptr = scope.engine->jsStackTop++; + ptr = scope.engine->jsAlloca(1); setPointer(v.as<T>()); } Scoped(const Scope &scope, const ScopedValue &v) { - ptr = scope.engine->jsStackTop++; + ptr = scope.engine->jsAlloca(1); setPointer(v.ptr->as<T>()); } Scoped(const Scope &scope, const Value &v, ConvertType) { - ptr = scope.engine->jsStackTop++; + ptr = scope.engine->jsAlloca(1); ptr->setRawValue(value_convert<T>(scope.engine, v)); } Scoped(const Scope &scope, const Value *v) { - ptr = scope.engine->jsStackTop++; + ptr = scope.engine->jsAlloca(1); setPointer(v ? v->as<T>() : 0); } Scoped(const Scope &scope, T *t) { - ptr = scope.engine->jsStackTop++; + ptr = scope.engine->jsAlloca(1); setPointer(t); } Scoped(const Scope &scope, typename T::Data *t) { - ptr = scope.engine->jsStackTop++; + ptr = scope.engine->jsAlloca(1); *ptr = t; } Scoped(const Scope &scope, const ReturnedValue &v) { - ptr = scope.engine->jsStackTop++; + ptr = scope.engine->jsAlloca(1); setPointer(QV4::Value::fromReturnedValue(v).as<T>()); } + Scoped(const Scope &scope, const ReturnedValue &v, ConvertType) { - ptr = scope.engine->jsStackTop++; + ptr = scope.engine->jsAlloca(1); ptr->setRawValue(value_convert<T>(scope.engine, QV4::Value::fromReturnedValue(v))); } @@ -311,7 +316,7 @@ struct Scoped }; struct ScopedCallData { - ScopedCallData(Scope &scope, int argc = 0) + ScopedCallData(const Scope &scope, int argc = 0) { int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value); ptr = reinterpret_cast<CallData *>(scope.alloc(size)); @@ -362,19 +367,19 @@ struct ScopedProperty struct ExecutionContextSaver { - ExecutionEngine *engine; + Scope scope; // this makes sure that a reference to context on the JS stack goes out of scope as soon as the context is not used anymore. ExecutionContext *savedContext; - ExecutionContextSaver(Scope &scope) - : engine(scope.engine) + ExecutionContextSaver(const Scope &scope) + : scope(scope.engine) { - savedContext = engine->currentContext; + savedContext = scope.engine->currentContext; } ~ExecutionContextSaver() { - Q_ASSERT(engine->jsStackTop > engine->currentContext); - engine->currentContext = savedContext; - engine->current = savedContext->d(); + Q_ASSERT(scope.engine->jsStackTop > scope.engine->currentContext); + scope.engine->currentContext = savedContext; + scope.engine->current = savedContext->d(); } }; diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 4b847600b4..e8d562cf4c 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -91,7 +91,7 @@ Heap::CompilationUnitHolder::CompilationUnitHolder(CompiledData::CompilationUnit struct QmlBindingWrapper : FunctionObject { V4_OBJECT2(QmlBindingWrapper, FunctionObject) - static ReturnedValue call(const Managed *that, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; } @@ -113,27 +113,28 @@ Heap::QmlBindingWrapper::QmlBindingWrapper(QV4::QmlContext *scope, Function *f) function->compilationUnit->addref(); } -ReturnedValue QmlBindingWrapper::call(const Managed *that, CallData *callData) +void QmlBindingWrapper::call(const Managed *that, Scope &scope, CallData *callData) { const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that); ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); QV4::Function *f = This->function(); - if (!f) - return QV4::Encode::undefined(); + if (!f) { + scope.result = QV4::Encode::undefined(); + return; + } Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(This, callData)); v4->pushContext(ctx); - ScopedValue result(scope, Q_V4_PROFILE(v4, f)); - - return result->asReturnedValue(); + scope.result = Q_V4_PROFILE(v4, f); } Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit) @@ -255,7 +256,8 @@ ReturnedValue Script::run() ScopedFunctionObject f(valueScope, engine->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction)); ScopedCallData callData(valueScope); callData->thisObject = Primitive::undefinedValue(); - return f->call(callData); + f->call(valueScope, callData); + return valueScope.result.asReturnedValue(); } } diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index d7b82218e7..e13388393b 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -74,7 +74,7 @@ struct ContextStateSaver { CompiledData::CompilationUnit *compilationUnit; int lineNumber; - ContextStateSaver(Scope &scope, ExecutionContext *context) + ContextStateSaver(const Scope &scope, ExecutionContext *context) : savedContext(scope.alloc(1)) , strictMode(context->d()->strictMode) , lookups(context->d()->lookups) @@ -83,7 +83,7 @@ struct ContextStateSaver { { savedContext->setM(context->d()); } - ContextStateSaver(Scope &scope, Heap::ExecutionContext *context) + ContextStateSaver(const Scope &scope, Heap::ExecutionContext *context) : savedContext(scope.alloc(1)) , strictMode(context->strictMode) , lookups(context->lookups) diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index fa2409a85c..d3b021ac37 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -411,8 +411,8 @@ public: callData->args[0] = convertElementToValue(this->m_ctx->d()->engine, lhs); callData->args[1] = convertElementToValue(this->m_ctx->d()->engine, rhs); callData->thisObject = this->m_ctx->d()->engine->globalObject; - QV4::ScopedValue result(scope, compare->call(callData)); - return result->toNumber() < 0; + compare->call(scope, callData); + return scope.result.toNumber() < 0; } private: diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index b4f04bbc76..1989f747e9 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -157,28 +157,24 @@ Heap::StringCtor::StringCtor(QV4::ExecutionContext *scope) { } -ReturnedValue StringCtor::construct(const Managed *m, CallData *callData) +void StringCtor::construct(const Managed *m, Scope &scope, CallData *callData) { ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); - Scope scope(v4); ScopedString value(scope); if (callData->argc) value = callData->args[0].toString(v4); else value = v4->newString(); - return Encode(v4->newStringObject(value)); + scope.result = Encode(v4->newStringObject(value)); } -ReturnedValue StringCtor::call(const Managed *m, CallData *callData) +void StringCtor::call(const Managed *, Scope &scope, CallData *callData) { - ExecutionEngine *v4 = static_cast<const Object *>(m)->engine(); - Scope scope(v4); - ScopedValue value(scope); + ExecutionEngine *v4 = scope.engine; if (callData->argc) - value = callData->args[0].toString(v4); + scope.result = callData->args[0].toString(v4); else - value = v4->newString(); - return value->asReturnedValue(); + scope.result = v4->newString(); } void StringPrototype::init(ExecutionEngine *engine, Object *ctor) @@ -423,7 +419,8 @@ ReturnedValue StringPrototype::method_match(CallContext *context) if (!rx) { ScopedCallData callData(scope, 1); callData->args[0] = regexp; - rx = context->d()->engine->regExpCtor()->construct(callData); + context->d()->engine->regExpCtor()->construct(scope, callData); + rx = scope.result.asReturnedValue(); } if (!rx) @@ -439,8 +436,10 @@ ReturnedValue StringPrototype::method_match(CallContext *context) ScopedCallData callData(scope, 1); callData->thisObject = rx; callData->args[0] = s; - if (!global) - return exec->call(callData); + if (!global) { + exec->call(scope, callData); + return scope.result.asReturnedValue(); + } ScopedString lastIndex(scope, context->d()->engine->newString(QStringLiteral("lastIndex"))); rx->put(lastIndex, ScopedValue(scope, Primitive::fromInt32(0))); @@ -448,14 +447,13 @@ ReturnedValue StringPrototype::method_match(CallContext *context) double previousLastIndex = 0; uint n = 0; - ScopedValue result(scope); ScopedValue matchStr(scope); ScopedValue index(scope); while (1) { - result = exec->call(callData); - if (result->isNull()) + exec->call(scope, callData); + if (scope.result.isNull()) break; - assert(result->isObject()); + assert(scope.result.isObject()); index = rx->get(lastIndex, 0); double thisIndex = index->toInteger(); if (previousLastIndex == thisIndex) { @@ -464,7 +462,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context) } else { previousLastIndex = thisIndex; } - matchStr = result->objectValue()->getIndexed(0); + matchStr = scope.result.objectValue()->getIndexed(0); a->arraySet(n, matchStr); ++n; } @@ -580,7 +578,6 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) } QString result; - ScopedValue replacement(scope); ScopedValue replaceValue(scope, ctx->argument(1)); ScopedFunctionObject searchCallback(scope, replaceValue); if (!!searchCallback) { @@ -605,9 +602,9 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) callData->args[numCaptures] = Primitive::fromUInt32(matchStart); callData->args[numCaptures + 1] = ctx->d()->engine->newString(string); - replacement = searchCallback->call(callData); + searchCallback->call(scope, callData); result += string.midRef(lastEnd, matchStart - lastEnd); - result += replacement->toQString(); + result += scope.result.toQString(); lastEnd = matchEnd; } result += string.midRef(lastEnd); @@ -640,17 +637,17 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx) { Scope scope(ctx); QString string = getThisString(ctx); - ScopedValue regExpValue(scope, ctx->argument(0)); + scope.result = ctx->argument(0); if (scope.engine->hasException) return Encode::undefined(); - Scoped<RegExpObject> regExp(scope, regExpValue->as<RegExpObject>()); + Scoped<RegExpObject> regExp(scope, scope.result.as<RegExpObject>()); if (!regExp) { ScopedCallData callData(scope, 1); - callData->args[0] = regExpValue; - regExpValue = ctx->d()->engine->regExpCtor()->construct(callData); + callData->args[0] = scope.result; + ctx->d()->engine->regExpCtor()->construct(scope, callData); if (scope.engine->hasException) return Encode::undefined(); - regExp = regExpValue->as<RegExpObject>(); + regExp = scope.result.as<RegExpObject>(); Q_ASSERT(regExp); } Scoped<RegExp> re(scope, regExp->value()); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index fb229d4aff..54425b0909 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -103,8 +103,8 @@ struct StringCtor: FunctionObject { V4_OBJECT2(StringCtor, FunctionObject) - static ReturnedValue construct(const Managed *m, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); + static void call(const Managed *, Scope &scope, CallData *callData); }; struct StringPrototype: StringObject diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index c86f252353..ae5ebcad1b 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -208,30 +208,34 @@ Heap::TypedArrayCtor::TypedArrayCtor(QV4::ExecutionContext *scope, TypedArray::T { } -ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) +void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callData) { - Scope scope(static_cast<const Object *>(m)->engine()); Scoped<TypedArrayCtor> that(scope, static_cast<const 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(); + if (scope.engine->hasException) { + scope.result = Encode::undefined(); + return; + } 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->newArrayBuffer(byteLength)); - if (scope.engine->hasException) - return Encode::undefined(); + if (scope.engine->hasException) { + scope.result = Encode::undefined(); + return; + } Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = buffer->d(); array->d()->byteLength = byteLength; array->d()->byteOffset = 0; - return array.asReturnedValue(); + scope.result = array.asReturnedValue(); + return; } Scoped<TypedArray> typedArray(scope, callData->argument(0)); if (!!typedArray) { @@ -243,8 +247,10 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) uint destByteLength = byteLength*destElementSize/srcElementSize; Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(destByteLength)); - if (scope.engine->hasException) - return Encode::undefined(); + if (scope.engine->hasException) { + scope.result = Encode::undefined(); + return; + } Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = newBuffer->d(); @@ -269,7 +275,8 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) } } - return array.asReturnedValue(); + scope.result = array.asReturnedValue(); + return; } Scoped<ArrayBuffer> buffer(scope, callData->argument(0)); if (!!buffer) { @@ -278,21 +285,29 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) 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")); + if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->byteLength()) { + scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset")); + return; + } 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")); + if (buffer->byteLength() < byteOffset || byteLength % elementSize) { + scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length")); + return; + } } else { double l = qBound(0., callData->args[2].toInteger(), (double)UINT_MAX); - if (scope.engine->hasException) - return Encode::undefined(); + if (scope.engine->hasException) { + scope.result = Encode::undefined(); + return; + } l *= elementSize; - if (buffer->byteLength() - byteOffset < l) - return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length")); + if (buffer->byteLength() - byteOffset < l) { + scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length")); + return; + } byteLength = (uint)l; } @@ -300,20 +315,25 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) array->d()->buffer = buffer->d(); array->d()->byteLength = byteLength; array->d()->byteOffset = byteOffset; - return array.asReturnedValue(); + scope.result = array.asReturnedValue(); + return; } // 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(); + if (scope.engine->hasException) { + scope.result = scope.engine->throwTypeError(); + return; + } uint elementSize = operations[that->d()->type].bytesPerElement; Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(l * elementSize)); - if (scope.engine->hasException) - return Encode::undefined(); + if (scope.engine->hasException) { + scope.result = Encode::undefined(); + return; + } Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); array->d()->buffer = newBuffer->d(); @@ -326,19 +346,21 @@ ReturnedValue TypedArrayCtor::construct(const Managed *m, CallData *callData) while (idx < l) { val = o->getIndexed(idx); array->d()->type->write(scope.engine, b, 0, val); - if (scope.engine->hasException) - return Encode::undefined(); + if (scope.engine->hasException) { + scope.result = Encode::undefined(); + return; + } ++idx; b += elementSize; } - return array.asReturnedValue(); + scope.result = array.asReturnedValue(); } -ReturnedValue TypedArrayCtor::call(const Managed *that, CallData *callData) +void TypedArrayCtor::call(const Managed *that, Scope &scope, CallData *callData) { - return construct(that, callData); + construct(that, scope, callData); } Heap::TypedArray::TypedArray(Type t) @@ -582,5 +604,6 @@ ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx) 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); + constructor->construct(scope, callData); + return scope.result.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index 757273e4ed..d96027b96a 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -140,8 +140,8 @@ struct TypedArrayCtor: FunctionObject { V4_OBJECT2(TypedArrayCtor, FunctionObject) - static ReturnedValue construct(const Managed *m, CallData *callData); - static ReturnedValue call(const Managed *that, CallData *callData); + static void construct(const Managed *m, Scope &scope, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); }; diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index eacb928901..3940176107 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -189,11 +189,12 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) bool isUndefined = false; - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); + QV4::ScopedCallData callData(scope); + QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope); bool error = false; if (!watcher.wasDeleted() && isAddedToObject() && !hasError()) - error = !write(pd, result, isUndefined, flags); + error = !write(pd, scope.result, isUndefined, flags); if (!watcher.wasDeleted()) { @@ -377,11 +378,12 @@ QVariant QQmlBinding::evaluate() bool isUndefined = false; QV4::Scope scope(ep->v4engine()); - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); + QV4::ScopedCallData callData(scope); + QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope); ep->dereferenceScarceResources(); - return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >()); + return scope.engine->toVariant(scope.result, qMetaTypeId<QList<QObject*> >()); } QString QQmlBinding::expressionIdentifier() diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 7d6e1ffa1a..e3c4464584 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -234,7 +234,7 @@ void QQmlBoundSignalExpression::evaluate(void **a) } } - QQmlJavaScriptExpression::evaluate(callData, 0); + QQmlJavaScriptExpression::evaluate(callData, 0, scope); ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. } @@ -256,7 +256,7 @@ void QQmlBoundSignalExpression::evaluate(const QList<QVariant> &args) callData->args[ii] = scope.engine->fromVariant(args[ii]); } - QQmlJavaScriptExpression::evaluate(callData, 0); + QQmlJavaScriptExpression::evaluate(callData, 0, scope); ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. } diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 52f6837842..854090f20b 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1527,7 +1527,7 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) QV4::ScopedCallData callData(scope, 1); callData->thisObject = this; callData->args[0] = QV4::Primitive::fromUInt32(s); - f->call(callData); + f->call(scope, callData); if (scope.hasException()) { QQmlError error = scope.engine->catchExceptionAsQmlError(); QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error); diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp index b3a0baffb4..d10a8c7718 100644 --- a/src/qml/qml/qqmldelayedcallqueue.cpp +++ b/src/qml/qml/qqmldelayedcallqueue.cpp @@ -74,7 +74,7 @@ void QQmlDelayedCallQueue::DelayedFunctionCall::execute(QV4::ExecutionEngine *en const QV4::FunctionObject *callback = m_function.as<QV4::FunctionObject>(); Q_ASSERT(callback); - callback->call(callData); + callback->call(scope, callData); if (scope.engine->hasException) { QQmlError error = scope.engine->catchExceptionAsQmlError(); diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index d48b6ad1d3..6afbd05e3e 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -245,14 +245,15 @@ void QQmlExpression::setExpression(const QString &expression) } // Must be called with a valid handle scope -QV4::ReturnedValue QQmlExpressionPrivate::v4value(bool *isUndefined) +void QQmlExpressionPrivate::v4value(bool *isUndefined, QV4::Scope &scope) { if (!expressionFunctionValid) { createQmlBinding(context(), scopeObject(), expression, url, line); expressionFunctionValid = true; } - return evaluate(isUndefined); + QV4::ScopedCallData callData(scope); + evaluate(callData, isUndefined, scope); } QVariant QQmlExpressionPrivate::value(bool *isUndefined) @@ -271,9 +272,9 @@ QVariant QQmlExpressionPrivate::value(bool *isUndefined) { QV4::Scope scope(QV8Engine::getV4(ep->v8engine())); - QV4::ScopedValue result(scope, v4value(isUndefined)); + v4value(isUndefined, scope); if (!hasError()) - rv = scope.engine->toVariant(result, -1); + rv = scope.engine->toVariant(scope.result, -1); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h index ccc629a3a3..741c25e206 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -76,7 +76,7 @@ public: QVariant value(bool *isUndefined = 0); - QV4::ReturnedValue v4value(bool *isUndefined = 0); + void v4value(bool *isUndefined, QV4::Scope &scope); static inline QQmlExpressionPrivate *get(QQmlExpression *expr); static inline QQmlExpression *get(QQmlExpressionPrivate *expr); diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 8ba4b5eba1..eff1a6e039 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -147,16 +147,9 @@ void QQmlJavaScriptExpression::refresh() { } -QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(bool *isUndefined) -{ - QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_context->engine); - QV4::Scope scope(v4); - QV4::ScopedCallData callData(scope); - return evaluate(callData, isUndefined); -} -QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined) +void QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined, QV4::Scope &scope) { Q_ASSERT(m_context && m_context->engine); @@ -164,7 +157,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b if (!f || f->isUndefined()) { if (isUndefined) *isUndefined = true; - return QV4::Encode::undefined(); + return; } QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_context->engine); @@ -184,8 +177,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b capture.guards.copyAndClearPrepend(activeGuards); QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); - QV4::Scope scope(v4); - QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue()); + scope.result = QV4::Primitive::undefinedValue(); callData->thisObject = v4->globalObject; if (scopeObject()) { QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(v4, scopeObject())); @@ -193,7 +185,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b callData->thisObject = value; } - result = f->as<QV4::FunctionObject>()->call(callData); + f->as<QV4::FunctionObject>()->call(scope, callData); if (scope.hasException()) { if (watcher.wasDeleted()) scope.engine->catchException(); // ignore exception @@ -203,7 +195,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b *isUndefined = true; } else { if (isUndefined) - *isUndefined = result->isUndefined(); + *isUndefined = scope.result.isUndefined(); if (!watcher.wasDeleted() && hasDelayedError()) delayedError()->clearError(); @@ -220,8 +212,6 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b g->Delete(); ep->propertyCapture = lastPropertyCapture; - - return result->asReturnedValue(); } void QQmlPropertyCapture::captureProperty(QQmlNotifier *n) @@ -294,11 +284,12 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n) } } -void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction) +void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Function *compiledFunction, const QV4::Scope &scope) { // Let the caller check and avoid the function call :) Q_ASSERT(compiledFunction->hasQmlDependencies()); + QV4::ExecutionEngine *engine = scope.engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine()); if (!ep) return; @@ -306,7 +297,6 @@ void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine, if (!capture) return; - QV4::Scope scope(engine); QV4::Scoped<QV4::QmlContext> context(scope, engine->qmlContext()); QQmlContextData *qmlContext = context->qmlContext(); diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 94479f6c5e..4472a643ff 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -103,8 +103,7 @@ public: virtual QString expressionIdentifier() = 0; virtual void expressionChanged() = 0; - QV4::ReturnedValue evaluate(bool *isUndefined); - QV4::ReturnedValue evaluate(QV4::CallData *callData, bool *isUndefined); + void evaluate(QV4::CallData *callData, bool *isUndefined, QV4::Scope &scope); inline bool notifyOnValueChanged() const; @@ -181,7 +180,7 @@ public: void captureProperty(QQmlNotifier *); void captureProperty(QObject *, int, int); - static void registerQmlDependencies(QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction); + static void registerQmlDependencies(const QV4::CompiledData::Function *compiledFunction, const QV4::Scope &scope); QQmlEngine *engine; QQmlJavaScriptExpression *expression; diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 6907b26cd8..a9aec4cded 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -945,15 +945,14 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * for (uint ii = 0; ii < parameterCount; ++ii) callData->args[ii] = scope.engine->fromVariant(*(QVariant *)a[ii + 1]); - QV4::ScopedValue result(scope); - result = function->call(callData); + function->call(scope, callData); if (scope.hasException()) { QQmlError error = scope.engine->catchExceptionAsQmlError(); if (error.isValid()) ep->warning(error); if (a[0]) *(QVariant *)a[0] = QVariant(); } else { - if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(result, 0); + if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(scope.result, 0); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index e2784103b0..74de30c96c 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1560,7 +1560,7 @@ void QQmlXMLHttpRequest::dispatchCallback(Object *thisObj, QQmlContextData *cont QV4::ScopedCallData callData(scope); callData->thisObject = Encode::undefined(); - callback->call(callData); + callback->call(scope, callData); if (scope.engine->hasException) { QQmlError error = scope.engine->catchExceptionAsQmlError(); @@ -1621,22 +1621,23 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject c->proto->mark(e); FunctionObject::markObjects(that, e); } - static ReturnedValue construct(const Managed *that, QV4::CallData *) + static void construct(const Managed *that, Scope &scope, QV4::CallData *) { - Scope scope(static_cast<const QQmlXMLHttpRequestCtor *>(that)->engine()); Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>()); - if (!ctor) - return scope.engine->throwTypeError(); + if (!ctor) { + scope.result = scope.engine->throwTypeError(); + return; + } QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager()); Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocObject<QQmlXMLHttpRequestWrapper>(r)); ScopedObject proto(scope, ctor->d()->proto); w->setPrototype(proto); - return w.asReturnedValue(); + scope.result = w.asReturnedValue(); } - static ReturnedValue call(const Managed *, QV4::CallData *) { - return Primitive::undefinedValue().asReturnedValue(); + static void call(const Managed *, Scope &scope, QV4::CallData *) { + scope.result = Primitive::undefinedValue(); } void setupProto(); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 482da31779..a0dff482b1 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1285,11 +1285,10 @@ void QQmlBindingFunction::initBindingLocation() d()->bindingLocation.line = frame.line; } -ReturnedValue QQmlBindingFunction::call(const Managed *that, CallData *callData) +void QQmlBindingFunction::call(const Managed *that, Scope &scope, CallData *callData) { - Scope scope(static_cast<const QQmlBindingFunction*>(that)->engine()); ScopedFunctionObject function(scope, static_cast<const QQmlBindingFunction*>(that)->d()->originalFunction); - return function->call(callData); + function->call(scope, callData); } void QQmlBindingFunction::markObjects(Heap::Base *that, ExecutionEngine *e) diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index 5404ab3616..d29983c476 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -188,7 +188,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject void initBindingLocation(); // from caller stack trace - static ReturnedValue call(const Managed *that, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 1585f3eda0..9a1d9e50d1 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -91,17 +91,17 @@ struct DelegateModelGroupFunction : QV4::FunctionObject return scope->engine()->memoryManager->allocObject<DelegateModelGroupFunction>(scope, flag, code); } - static QV4::ReturnedValue call(const QV4::Managed *that, QV4::CallData *callData) + static void call(const QV4::Managed *that, QV4::Scope &scope, QV4::CallData *callData) { - QV4::ExecutionEngine *v4 = static_cast<const DelegateModelGroupFunction *>(that)->engine(); - QV4::Scope scope(v4); QV4::Scoped<DelegateModelGroupFunction> f(scope, static_cast<const DelegateModelGroupFunction *>(that)); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject); - if (!o) - return v4->throwTypeError(QStringLiteral("Not a valid VisualData object")); + if (!o) { + scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return; + } QV4::ScopedValue v(scope, callData->argument(0)); - return f->d()->code(o->d()->item, f->d()->flag, v); + scope.result = f->d()->code(o->d()->item, f->d()->flag, v); } }; diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index bc15b2fd9b..10666476fe 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -251,7 +251,8 @@ void QQuickWorkerScriptEnginePrivate::WorkerEngine::init() QV4::ScopedCallData callData(scope, 1); callData->args[0] = function; callData->thisObject = global(); - createsend.set(scope.engine, createsendconstructor->call(callData)); + createsendconstructor->call(scope, callData); + createsend.set(scope.engine, scope.result.asReturnedValue()); } // Requires handle and context scope @@ -264,14 +265,13 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(i QV4::Scope scope(v4); QV4::ScopedFunctionObject f(scope, createsend.value()); - QV4::ScopedValue v(scope); QV4::ScopedCallData callData(scope, 1); callData->args[0] = QV4::Primitive::fromInt32(id); callData->thisObject = global(); - v = f->call(callData); + f->call(scope, callData); if (scope.hasException()) - v = scope.engine->catchException(); - return v->asReturnedValue(); + scope.result = scope.engine->catchException(); + return scope.result.asReturnedValue(); } #ifndef QT_NO_NETWORK @@ -380,7 +380,7 @@ void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &d callData->thisObject = workerEngine->global(); callData->args[0] = qmlContext->d()->qml; // ### callData->args[1] = value; - f->call(callData); + f->call(scope, callData); if (scope.hasException()) { QQmlError error = scope.engine->catchExceptionAsQmlError(); reportScriptException(script, error); diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index b340d9bf94..9d5ddab155 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -709,7 +709,7 @@ void QQuickCanvasItem::updatePolish() for (auto it = animationCallbacks.cbegin(), end = animationCallbacks.cend(); it != end; ++it) { QV4::ScopedFunctionObject f(scope, it.value().value()); callData->args[0] = QV4::Primitive::fromUInt32(QDateTime::currentDateTimeUtc().toTime_t()); - f->call(callData); + f->call(scope, callData); } } else { |