diff options
author | Lars Knoll <lars.knoll@qt.io> | 2017-01-05 18:48:20 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2017-01-25 08:31:10 +0000 |
commit | c2a4277ae5c60a7b7f1e2a083a89ae4e528794c5 (patch) | |
tree | e525af4b0b241b9cdbcc1b10bc0103ac1695a83b /src/qml/jsruntime | |
parent | 3e67a40860e0cda4cf6118c97e47cbe55aa672d6 (diff) |
Speed up invocation of builtin functions
Completely avoid creation of a CallContext for those methods,
as we don't need it.
Change-Id: Iff1a38fd3c7e846df6ec0374cb7b3fb8f1b4de3a
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4arrayobject.cpp | 675 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4arrayobject_p.h | 48 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 37 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject_p.h | 24 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 21 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object_p.h | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectproto.cpp | 412 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectproto_p.h | 52 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4scopedvalue_p.h | 26 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 4 |
10 files changed, 690 insertions, 613 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 20ba11fd75..759354f4e2 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -44,6 +44,7 @@ #include "qv4argumentsobject_p.h" #include "qv4runtime_p.h" #include "qv4string_p.h" +#include <QtCore/qscopedvaluerollback.h> using namespace QV4; @@ -118,42 +119,40 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("reduceRight"), method_reduceRight, 1); } -ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx) +void ArrayPrototype::method_isArray(const BuiltinFunction *, Scope &scope, CallData *callData) { - bool isArray = ctx->argc() && ctx->args()[0].as<ArrayObject>(); - return Encode(isArray); + bool isArray = callData->argc && callData->args[0].as<ArrayObject>(); + scope.result = Encode(isArray); } -ReturnedValue ArrayPrototype::method_toString(CallContext *ctx) +void ArrayPrototype::method_toString(const BuiltinFunction *builtin, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject(), ScopedObject::Convert); - if (ctx->d()->engine->hasException) - return Encode::undefined(); - ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("join"))); + ScopedObject o(scope, callData->thisObject, ScopedObject::Convert); + CHECK_EXCEPTION(); + ScopedString s(scope, scope.engine->newString(QStringLiteral("join"))); ScopedFunctionObject f(scope, o->get(s)); if (!!f) { ScopedCallData d(scope, 0); - d->thisObject = ctx->thisObject(); + d->thisObject = callData->thisObject; f->call(scope, d); - return scope.result.asReturnedValue(); + return; } - return ObjectPrototype::method_toString(ctx); + ObjectPrototype::method_toString(builtin, scope, callData); } -ReturnedValue ArrayPrototype::method_toLocaleString(CallContext *ctx) +void ArrayPrototype::method_toLocaleString(const BuiltinFunction *builtin, Scope &scope, CallData *callData) { - return method_toString(ctx); + return method_toString(builtin, scope, callData); } -ReturnedValue ArrayPrototype::method_concat(CallContext *ctx) +void ArrayPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject result(scope, ctx->d()->engine->newArrayObject()); - - ScopedObject thisObject(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject thisObject(scope, callData->thisObject.toObject(scope.engine)); if (!thisObject) - return Encode::undefined(); + RETURN_UNDEFINED(); + + ScopedArrayObject result(scope, scope.engine->newArrayObject()); + if (thisObject->isArrayObject()) { result->copyArrayData(thisObject); } else { @@ -163,9 +162,9 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx) ScopedArrayObject elt(scope); ScopedObject eltAsObj(scope); ScopedValue entry(scope); - for (int i = 0; i < ctx->argc(); ++i) { - eltAsObj = ctx->args()[i]; - elt = ctx->args()[i]; + for (int i = 0; i < callData->argc; ++i) { + eltAsObj = callData->args[i]; + elt = callData->args[i]; if (elt) { uint n = elt->getLength(); uint newLen = ArrayData::append(result, elt, n); @@ -177,95 +176,90 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx) result->putIndexed(startIndex + i, entry); } } else { - result->arraySet(result->getLength(), ctx->args()[i]); + result->arraySet(result->getLength(), callData->args[i]); } } - return result.asReturnedValue(); + scope.result = result; } -ReturnedValue ArrayPrototype::method_find(CallContext *ctx) +void ArrayPrototype::method_find(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); for (uint k = 0; k < len; ++k) { v = instance->getIndexed(k); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); - if (scope.hasException()) - return Encode::undefined(); - else if (scope.result.toBoolean()) - return v->asReturnedValue(); + CHECK_EXCEPTION(); + if (scope.result.toBoolean()) + RETURN_RESULT(v); } - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue ArrayPrototype::method_findIndex(CallContext *ctx) +void ArrayPrototype::method_findIndex(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); for (uint k = 0; k < len; ++k) { v = instance->getIndexed(k); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); - if (scope.hasException()) - return Encode::undefined(); - else if (scope.result.toBoolean()) - return Encode(k); + CHECK_EXCEPTION(); + if (scope.result.toBoolean()) + RETURN_RESULT(Encode(k)); } - return Encode(-1); + RETURN_RESULT(Encode(-1)); } -ReturnedValue ArrayPrototype::method_join(CallContext *ctx) +void ArrayPrototype::method_join(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue arg(scope, ctx->argument(0)); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedValue arg(scope, callData->argument(0)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); - if (!instance) - return ctx->d()->engine->newString()->asReturnedValue(); + if (!instance) { + scope.result = scope.engine->newString(); + return; + } QString r4; if (arg->isUndefined()) @@ -273,11 +267,13 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) else r4 = arg->toQString(); - ScopedValue length(scope, instance->get(ctx->d()->engine->id_length())); + ScopedValue length(scope, instance->get(scope.engine->id_length())); const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32(); - if (!r2) - return ctx->d()->engine->newString()->asReturnedValue(); + if (!r2) { + scope.result = scope.engine->newString(); + return; + } QString R; @@ -289,8 +285,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) R += r4; e = a->getIndexed(i); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (!e->isNullOrUndefined()) R += e->toQString(); } @@ -298,7 +293,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) // // crazy! // - ScopedString name(scope, ctx->d()->engine->newString(QStringLiteral("0"))); + ScopedString name(scope, scope.engine->newString(QStringLiteral("0"))); ScopedValue r6(scope, instance->get(name)); if (!r6->isNullOrUndefined()) R = r6->toQString(); @@ -309,99 +304,98 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) name = Primitive::fromDouble(k).toString(scope.engine); r12 = instance->get(name); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (!r12->isNullOrUndefined()) R += r12->toQString(); } } - return ctx->d()->engine->newString(R)->asReturnedValue(); + scope.result = scope.engine->newString(R); } -ReturnedValue ArrayPrototype::method_pop(CallContext *ctx) +void ArrayPrototype::method_pop(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); + uint len = instance->getLength(); if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); - return Encode::undefined(); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); + RETURN_UNDEFINED(); } ScopedValue result(scope, instance->getIndexed(len - 1)); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); instance->deleteIndexedProperty(len - 1); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); + if (instance->isArrayObject()) instance->setArrayLength(len - 1); else - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); - return result->asReturnedValue(); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); + scope.result = result; } -ReturnedValue ArrayPrototype::method_push(CallContext *ctx) +void ArrayPrototype::method_push(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); instance->arrayCreate(); Q_ASSERT(instance->arrayData()); uint len = instance->getLength(); - if (len + ctx->argc() < len) { + if (len + callData->argc < len) { // ughh... double l = len; ScopedString s(scope); - for (int i = 0; i < ctx->argc(); ++i) { + for (int i = 0; i < callData->argc; ++i) { s = Primitive::fromDouble(l + i).toString(scope.engine); - instance->put(s, ctx->args()[i]); + instance->put(s, callData->args[i]); } - double newLen = l + ctx->argc(); + double newLen = l + callData->argc; if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); else { - ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); - return ctx->engine()->throwRangeError(str); + ScopedString str(scope, scope.engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); + scope.result = scope.engine->throwRangeError(str); + return; } - return Encode(newLen); + scope.result = Encode(newLen); + return; } - if (!ctx->argc()) + if (!callData->argc) ; else if (!instance->protoHasArray() && instance->arrayData()->length() <= len && instance->arrayData()->type == Heap::ArrayData::Simple) { - instance->arrayData()->vtable()->putArray(instance, len, ctx->args(), ctx->argc()); + instance->arrayData()->vtable()->putArray(instance, len, callData->args, callData->argc); len = instance->arrayData()->length(); } else { - for (int i = 0; i < ctx->argc(); ++i) - instance->putIndexed(len + i, ctx->args()[i]); - len += ctx->argc(); + for (int i = 0; i < callData->argc; ++i) + instance->putIndexed(len + i, callData->args[i]); + len += callData->argc; } if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len); else - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len))); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len))); - return Encode(len); + scope.result = Encode(len); } -ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx) +void ArrayPrototype::method_reverse(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); + uint length = instance->getLength(); int lo = 0, hi = length - 1; @@ -412,28 +406,25 @@ ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx) bool loExists, hiExists; lval = instance->getIndexed(lo, &loExists); hval = instance->getIndexed(hi, &hiExists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (hiExists) instance->putIndexed(lo, hval); else instance->deleteIndexedProperty(lo); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (loExists) instance->putIndexed(hi, lval); else instance->deleteIndexedProperty(hi); } - return instance.asReturnedValue(); + scope.result = instance; } -ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) +void ArrayPrototype::method_shift(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); instance->arrayCreate(); Q_ASSERT(instance->arrayData()); @@ -442,54 +433,46 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); - return Encode::undefined(); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); + RETURN_UNDEFINED(); } - ScopedValue result(scope); - if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len && instance->arrayData()->type != Heap::ArrayData::Custom) { - result = instance->arrayData()->vtable()->pop_front(instance); + scope.result = instance->arrayData()->vtable()->pop_front(instance); } else { - result = instance->getIndexed(0); - if (scope.hasException()) - return Encode::undefined(); + scope.result = instance->getIndexed(0); + CHECK_EXCEPTION(); ScopedValue v(scope); // do it the slow way for (uint k = 1; k < len; ++k) { bool exists; v = instance->getIndexed(k, &exists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (exists) instance->putIndexed(k - 1, v); else instance->deleteIndexedProperty(k - 1); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); } instance->deleteIndexedProperty(len - 1); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); } if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len - 1); else - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); - return result->asReturnedValue(); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); } -ReturnedValue ArrayPrototype::method_slice(CallContext *ctx) +void ArrayPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject o(scope, callData->thisObject.toObject(scope.engine)); if (!o) - return Encode::undefined(); + RETURN_UNDEFINED(); - ScopedArrayObject result(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject result(scope, scope.engine->newArrayObject()); uint len = o->getLength(); - double s = ScopedValue(scope, ctx->argument(0))->toInteger(); + double s = ScopedValue(scope, callData->argument(0))->toInteger(); uint start; if (s < 0) start = (uint)qMax(len + s, 0.); @@ -498,8 +481,8 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx) else start = (uint) s; uint end = len; - if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) { - double e = ctx->args()[1].toInteger(); + if (callData->argc > 1 && !callData->args[1].isUndefined()) { + double e = callData->args[1].toInteger(); if (e < 0) end = (uint)qMax(len + e, 0.); else if (e > len) @@ -513,115 +496,107 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx) for (uint i = start; i < end; ++i) { bool exists; v = o->getIndexed(i, &exists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (exists) result->arraySet(n, v); ++n; } - return result.asReturnedValue(); + scope.result = result; } -ReturnedValue ArrayPrototype::method_sort(CallContext *ctx) +void ArrayPrototype::method_sort(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedValue comparefn(scope, ctx->argument(0)); + ScopedValue comparefn(scope, callData->argument(0)); ArrayData::sort(scope.engine, instance, comparefn, len); - return ctx->thisObject().asReturnedValue(); + scope.result = callData->thisObject; } -ReturnedValue ArrayPrototype::method_splice(CallContext *ctx) +void ArrayPrototype::method_splice(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); + uint len = instance->getLength(); - ScopedArrayObject newArray(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject newArray(scope, scope.engine->newArrayObject()); - double rs = ScopedValue(scope, ctx->argument(0))->toInteger(); + double rs = ScopedValue(scope, callData->argument(0))->toInteger(); uint start; if (rs < 0) start = (uint) qMax(0., len + rs); else start = (uint) qMin(rs, (double)len); - uint deleteCount = (uint)qMin(qMax(ScopedValue(scope, ctx->argument(1))->toInteger(), 0.), (double)(len - start)); + uint deleteCount = (uint)qMin(qMax(ScopedValue(scope, callData->argument(1))->toInteger(), 0.), (double)(len - start)); newArray->arrayReserve(deleteCount); ScopedValue v(scope); for (uint i = 0; i < deleteCount; ++i) { bool exists; v = instance->getIndexed(start + i, &exists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (exists) newArray->arrayPut(i, v); } newArray->setArrayLengthUnchecked(deleteCount); - uint itemCount = ctx->argc() < 2 ? 0 : ctx->argc() - 2; + uint itemCount = callData->argc < 2 ? 0 : callData->argc - 2; if (itemCount < deleteCount) { for (uint k = start; k < len - deleteCount; ++k) { bool exists; v = instance->getIndexed(k + deleteCount, &exists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (exists) instance->putIndexed(k + itemCount, v); else instance->deleteIndexedProperty(k + itemCount); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); } for (uint k = len; k > len - deleteCount + itemCount; --k) { instance->deleteIndexedProperty(k - 1); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); } } else if (itemCount > deleteCount) { uint k = len - deleteCount; while (k > start) { bool exists; v = instance->getIndexed(k + deleteCount - 1, &exists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (exists) instance->putIndexed(k + itemCount - 1, v); else instance->deleteIndexedProperty(k + itemCount - 1); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); --k; } } for (uint i = 0; i < itemCount; ++i) { - instance->putIndexed(start + i, ctx->args()[i + 2]); - if (scope.hasException()) - return Encode::undefined(); + instance->putIndexed(start + i, callData->args[i + 2]); + CHECK_EXCEPTION(); } - ctx->d()->strictMode = true; - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); + bool wasStrict = scope.engine->current->strictMode; + scope.engine->current->strictMode = true; + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); - return newArray.asReturnedValue(); + scope.result = newArray; + scope.engine->current->strictMode = wasStrict; } -ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx) +void ArrayPrototype::method_unshift(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); instance->arrayCreate(); Q_ASSERT(instance->arrayData()); @@ -630,50 +605,52 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx) if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len && instance->arrayData()->type != Heap::ArrayData::Custom) { - instance->arrayData()->vtable()->push_front(instance, ctx->args(), ctx->argc()); + instance->arrayData()->vtable()->push_front(instance, callData->args, callData->argc); } else { ScopedValue v(scope); for (uint k = len; k > 0; --k) { bool exists; v = instance->getIndexed(k - 1, &exists); if (exists) - instance->putIndexed(k + ctx->argc() - 1, v); + instance->putIndexed(k + callData->argc - 1, v); else - instance->deleteIndexedProperty(k + ctx->argc() - 1); + instance->deleteIndexedProperty(k + callData->argc - 1); } - for (int i = 0; i < ctx->argc(); ++i) - instance->putIndexed(i, ctx->args()[i]); + for (int i = 0; i < callData->argc; ++i) + instance->putIndexed(i, callData->args[i]); } - uint newLen = len + ctx->argc(); + uint newLen = len + callData->argc; if (instance->isArrayObject()) instance->setArrayLengthUnchecked(newLen); else - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); - return Encode(newLen); + scope.result = Encode(newLen); } -ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) +void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); + uint len = instance->getLength(); - if (!len) - return Encode(-1); + if (!len) { + scope.result = Encode(-1); + return; + } - ScopedValue searchValue(scope, ctx->argument(0)); + ScopedValue searchValue(scope, callData->argument(0)); uint fromIndex = 0; - if (ctx->argc() >= 2) { - double f = ctx->args()[1].toInteger(); - if (scope.hasException()) - return Encode::undefined(); - if (f >= len) - return Encode(-1); + if (callData->argc >= 2) { + double f = callData->args[1].toInteger(); + CHECK_EXCEPTION(); + if (f >= len) { + scope.result = Encode(-1); + return; + } if (f < 0) f = qMax(len + f, 0.); fromIndex = (uint) f; @@ -684,10 +661,13 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) for (uint k = fromIndex; k < len; ++k) { bool exists; v = instance->getIndexed(k, &exists); - if (exists && RuntimeHelpers::strictEqual(v, searchValue)) - return Encode(k); + if (exists && RuntimeHelpers::strictEqual(v, searchValue)) { + scope.result = Encode(k); + return; + } } - return Encode(-1); + scope.result = Encode(-1); + return; } ScopedValue value(scope); @@ -698,13 +678,15 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) for (uint i = fromIndex; i < len; ++i) { bool exists; value = instance->getIndexed(i, &exists); - if (scope.hasException()) - return Encode::undefined(); - if (exists && RuntimeHelpers::strictEqual(value, searchValue)) - return Encode(i); + CHECK_EXCEPTION(); + if (exists && RuntimeHelpers::strictEqual(value, searchValue)) { + scope.result = Encode(i); + return; + } } } else if (!instance->arrayData()) { - return Encode(-1); + scope.result = Encode(-1); + return; } else { Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex); Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>(); @@ -713,45 +695,48 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) uint idx = fromIndex; while (idx < len) { value = sa->data(idx); - if (scope.hasException()) - return Encode::undefined(); - if (RuntimeHelpers::strictEqual(value, searchValue)) - return Encode(idx); + CHECK_EXCEPTION(); + if (RuntimeHelpers::strictEqual(value, searchValue)) { + scope.result = Encode(idx); + return; + } ++idx; } } - return Encode(-1); + scope.result = Encode(-1); } -ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx) +void ArrayPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); + uint len = instance->getLength(); - if (!len) - return Encode(-1); + if (!len) { + scope.result = Encode(-1); + return; + } ScopedValue searchValue(scope); uint fromIndex = len; - if (ctx->argc() >= 1) - searchValue = ctx->argument(0); + if (callData->argc >= 1) + searchValue = callData->argument(0); else searchValue = Primitive::undefinedValue(); - if (ctx->argc() >= 2) { - double f = ctx->args()[1].toInteger(); - if (scope.hasException()) - return Encode::undefined(); + if (callData->argc >= 2) { + double f = callData->args[1].toInteger(); + CHECK_EXCEPTION(); if (f > 0) f = qMin(f, (double)(len - 1)); else if (f < 0) { f = len + f; - if (f < 0) - return Encode(-1); + if (f < 0) { + scope.result = Encode(-1); + return; + } } fromIndex = (uint) f + 1; } @@ -761,30 +746,30 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx) --k; bool exists; v = instance->getIndexed(k, &exists); - if (scope.hasException()) - return Encode::undefined(); - if (exists && RuntimeHelpers::strictEqual(v, searchValue)) - return Encode(k); + CHECK_EXCEPTION(); + if (exists && RuntimeHelpers::strictEqual(v, searchValue)) { + scope.result = Encode(k); + return; + } } - return Encode(-1); + scope.result = Encode(-1); } -ReturnedValue ArrayPrototype::method_every(CallContext *ctx) +void ArrayPrototype::method_every(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 3); - callData->args[2] = instance; - callData->thisObject = ctx->argument(1); + ScopedCallData cData(scope, 3); + cData->args[2] = instance; + cData->thisObject = callData->argument(1); ScopedValue v(scope); bool ok = true; @@ -794,30 +779,29 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx) if (!exists) continue; - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); ok = scope.result.toBoolean(); } - return Encode(ok); + scope.result = Encode(ok); } -ReturnedValue ArrayPrototype::method_some(CallContext *ctx) +void ArrayPrototype::method_some(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); for (uint k = 0; k < len; ++k) { @@ -826,31 +810,32 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx) if (!exists) continue; - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); - if (scope.result.toBoolean()) - return Encode(true); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); + if (scope.result.toBoolean()) { + scope.result = Encode(true); + return; + } } - return Encode(false); + scope.result = Encode(false); } -ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx) +void ArrayPrototype::method_forEach(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); for (uint k = 0; k < len; ++k) { @@ -859,33 +844,32 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx) if (!exists) continue; - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); } - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue ArrayPrototype::method_map(CallContext *ctx) +void ArrayPrototype::method_map(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject a(scope, scope.engine->newArrayObject()); a->arrayReserve(len); a->setArrayLengthUnchecked(len); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); for (uint k = 0; k < len; ++k) { @@ -894,33 +878,32 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx) if (!exists) continue; - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); a->arraySet(k, scope.result); } - return a.asReturnedValue(); + scope.result = a.asReturnedValue(); } -ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) +void ArrayPrototype::method_filter(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject a(scope, scope.engine->newArrayObject()); a->arrayReserve(len); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); @@ -931,35 +914,34 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) if (!exists) continue; - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); if (scope.result.toBoolean()) { a->arraySet(to, v); ++to; } } - return a.asReturnedValue(); + scope.result = a.asReturnedValue(); } -ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) +void ArrayPrototype::method_reduce(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); uint k = 0; ScopedValue v(scope); - if (ctx->argc() > 1) { - scope.result = ctx->argument(1); + if (callData->argc > 1) { + scope.result = callData->argument(1); } else { bool kPresent = false; while (k < len && !kPresent) { @@ -969,51 +951,50 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) ++k; } if (!kPresent) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); } - ScopedCallData callData(scope, 4); - callData->thisObject = Primitive::undefinedValue(); - callData->args[0] = scope.result; - callData->args[3] = instance; + ScopedCallData cData(scope, 4); + cData->thisObject = Primitive::undefinedValue(); + cData->args[0] = scope.result; + cData->args[3] = instance; while (k < len) { bool kPresent; v = instance->getIndexed(k, &kPresent); if (kPresent) { - callData->args[0] = scope.result; - callData->args[1] = v; - callData->args[2] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = scope.result; + cData->args[1] = v; + cData->args[2] = Primitive::fromDouble(k); + callback->call(scope, cData); } ++k; } - return scope.result.asReturnedValue(); } -ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) +void ArrayPrototype::method_reduceRight(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (len == 0) { - if (ctx->argc() == 1) - return ctx->engine()->throwTypeError(); - return ctx->argument(1); + if (callData->argc == 1) + THROW_TYPE_ERROR(); + scope.result = callData->argument(1); + return; } uint k = len; ScopedValue v(scope); - if (ctx->argc() > 1) { - scope.result = ctx->argument(1); + if (callData->argc > 1) { + scope.result = callData->argument(1); } else { bool kPresent = false; while (k > 0 && !kPresent) { @@ -1023,24 +1004,24 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) --k; } if (!kPresent) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); } - ScopedCallData callData(scope, 4); - callData->thisObject = Primitive::undefinedValue(); - callData->args[3] = instance; + ScopedCallData cData(scope, 4); + cData->thisObject = Primitive::undefinedValue(); + cData->args[3] = instance; while (k > 0) { bool kPresent; v = instance->getIndexed(k - 1, &kPresent); if (kPresent) { - callData->args[0] = scope.result; - callData->args[1] = v; - callData->args[2] = Primitive::fromDouble(k - 1); - callback->call(scope, callData); + cData->args[0] = scope.result; + cData->args[1] = v; + cData->args[2] = Primitive::fromDouble(k - 1); + callback->call(scope, cData); } --k; } - return scope.result.asReturnedValue(); + scope.result = scope.result.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index f00c0c0249..689752433b 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -78,30 +78,30 @@ struct ArrayPrototype: ArrayObject { void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_isArray(CallContext *ctx); - static ReturnedValue method_toString(CallContext *ctx); - static ReturnedValue method_toLocaleString(CallContext *ctx); - static ReturnedValue method_concat(CallContext *ctx); - static ReturnedValue method_find(CallContext *ctx); - static ReturnedValue method_findIndex(CallContext *ctx); - static ReturnedValue method_join(CallContext *ctx); - static ReturnedValue method_pop(CallContext *ctx); - static ReturnedValue method_push(CallContext *ctx); - static ReturnedValue method_reverse(CallContext *ctx); - static ReturnedValue method_shift(CallContext *ctx); - static ReturnedValue method_slice(CallContext *ctx); - static ReturnedValue method_sort(CallContext *ctx); - static ReturnedValue method_splice(CallContext *ctx); - static ReturnedValue method_unshift(CallContext *ctx); - static ReturnedValue method_indexOf(CallContext *ctx); - static ReturnedValue method_lastIndexOf(CallContext *ctx); - static ReturnedValue method_every(CallContext *ctx); - static ReturnedValue method_some(CallContext *ctx); - static ReturnedValue method_forEach(CallContext *ctx); - static ReturnedValue method_map(CallContext *ctx); - static ReturnedValue method_filter(CallContext *ctx); - static ReturnedValue method_reduce(CallContext *ctx); - static ReturnedValue method_reduceRight(CallContext *ctx); + static void method_isArray(const BuiltinFunction *, Scope &, CallData *callData); + static void method_toString(const BuiltinFunction *, Scope &, CallData *callData); + static void method_toLocaleString(const BuiltinFunction *builtin, Scope &, CallData *callData); + static void method_concat(const BuiltinFunction *, Scope &, CallData *callData); + static void method_find(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_findIndex(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_join(const BuiltinFunction *, Scope &, CallData *callData); + static void method_pop(const BuiltinFunction *, Scope &, CallData *callData); + static void method_push(const BuiltinFunction *, Scope &, CallData *callData); + static void method_reverse(const BuiltinFunction *, Scope &, CallData *callData); + static void method_shift(const BuiltinFunction *, Scope &, CallData *callData); + static void method_slice(const BuiltinFunction *, Scope &, CallData *callData); + static void method_sort(const BuiltinFunction *, Scope &, CallData *callData); + static void method_splice(const BuiltinFunction *, Scope &, CallData *callData); + static void method_unshift(const BuiltinFunction *, Scope &, CallData *callData); + static void method_indexOf(const BuiltinFunction *, Scope &, CallData *callData); + static void method_lastIndexOf(const BuiltinFunction *, Scope &, CallData *callData); + static void method_every(const BuiltinFunction *, Scope &, CallData *callData); + static void method_some(const BuiltinFunction *, Scope &, CallData *callData); + static void method_forEach(const BuiltinFunction *, Scope &, CallData *callData); + static void method_map(const BuiltinFunction *, Scope &, CallData *callData); + static void method_filter(const BuiltinFunction *, Scope &, CallData *callData); + static void method_reduce(const BuiltinFunction *, Scope &, CallData *callData); + static void method_reduceRight(const BuiltinFunction *, Scope &, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 3bbccdba2f..1458c77d88 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -459,22 +459,22 @@ Heap::Object *ScriptFunction::protoForConstructor() const -DEFINE_OBJECT_VTABLE(BuiltinFunction); +DEFINE_OBJECT_VTABLE(OldBuiltinFunction); -void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)) +void Heap::OldBuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)) { Heap::FunctionObject::init(scope, name); this->code = code; } -void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *) +void OldBuiltinFunction::construct(const Managed *f, Scope &scope, CallData *) { - scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); + scope.result = static_cast<const OldBuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); } -void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) +void OldBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) { - const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that); + const OldBuiltinFunction *f = static_cast<const OldBuiltinFunction *>(that); ExecutionEngine *v4 = scope.engine; if (v4->hasException) { scope.result = Encode::undefined(); @@ -494,6 +494,31 @@ void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData v4->memoryManager->freeSimpleCallContext(); } +DEFINE_OBJECT_VTABLE(BuiltinFunction); + +void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *)) +{ + Heap::FunctionObject::init(scope, name); + this->code = code; +} + +void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *) +{ + scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); +} + +void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) +{ + const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + f->d()->code(f, scope, callData); +} + + void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) { const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index a02e89e883..31b05666a7 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -61,6 +61,8 @@ struct QQmlSourceLocation; namespace QV4 { +struct BuiltinFunction; + namespace Heap { struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { @@ -93,11 +95,16 @@ struct FunctionPrototype : FunctionObject { void init(); }; -struct Q_QML_EXPORT BuiltinFunction : FunctionObject { +struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject { void init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)); ReturnedValue (*code)(QV4::CallContext *); }; +struct Q_QML_EXPORT BuiltinFunction : FunctionObject { + void init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *)); + void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *); +}; + struct IndexedBuiltinFunction : FunctionObject { inline void init(QV4::ExecutionContext *scope, uint index, ReturnedValue (*code)(QV4::CallContext *ctx, uint index)); ReturnedValue (*code)(QV4::CallContext *, uint index); @@ -183,10 +190,21 @@ struct FunctionPrototype: FunctionObject static ReturnedValue method_bind(CallContext *ctx); }; -struct Q_QML_EXPORT BuiltinFunction: FunctionObject { +struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject { + V4_OBJECT2(OldBuiltinFunction, FunctionObject) + + static void construct(const Managed *, Scope &scope, CallData *); + static void call(const Managed *that, Scope &scope, CallData *callData); +}; + +struct Q_QML_EXPORT BuiltinFunction : FunctionObject { V4_OBJECT2(BuiltinFunction, FunctionObject) - static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) + static Heap::OldBuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) + { + return scope->engine()->memoryManager->allocObject<OldBuiltinFunction>(scope, name, code); + } + static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *)) { return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code); } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index f217e301ac..cb13069ca0 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -166,6 +166,17 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca defineDefaultProperty(s, function); } +void Object::defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount) +{ + ExecutionEngine *e = engine(); + Scope scope(e); + ScopedString s(scope, e->newIdentifier(name)); + ExecutionContext *global = e->rootContext(); + ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code)); + function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); + defineDefaultProperty(s, function); +} + void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount) { ExecutionEngine *e = engine(); @@ -176,6 +187,16 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte defineDefaultProperty(name, function); } +void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount) +{ + ExecutionEngine *e = engine(); + Scope scope(e); + ExecutionContext *global = e->rootContext(); + ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); + function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); + defineDefaultProperty(name, function); +} + void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)) { ExecutionEngine *e = engine(); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 65820911db..cf9d7bbcdf 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -63,6 +63,8 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct BuiltinFunction; + namespace Heap { struct Object : Base { @@ -236,7 +238,9 @@ struct Q_QML_EXPORT Object: Managed { } void defineDefaultProperty(const QString &name, const Value &value); void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); + void defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0); void defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); + void defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0); void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); void defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); /* Fixed: Writable: false, Enumerable: false, Configurable: false */ diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 8191083544..97dbe24339 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -121,100 +121,100 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) insertMember(v4->id___proto__(), p, Attr_Accessor|Attr_NotEnumerable); } -ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx) +void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); ScopedObject p(scope, o->prototype()); - return !!p ? p->asReturnedValue() : Encode::null(); + scope.result = !!p ? p->asReturnedValue() : Encode::null(); } -ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) +void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject O(scope, ctx->argument(0)); - if (!O) - return ctx->engine()->throwTypeError(); + ScopedObject O(scope, callData->argument(0)); + if (!O) { + scope.result = scope.engine->throwTypeError(); + return; + } if (ArgumentsObject::isNonStrictArgumentsObject(O)) static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate(); - ScopedValue v(scope, ctx->argument(1)); + ScopedValue v(scope, callData->argument(1)); ScopedString name(scope, v->toString(scope.engine)); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); + PropertyAttributes attrs; ScopedProperty desc(scope); O->getOwnProperty(name, &attrs, desc); - return fromPropertyDescriptor(scope.engine, desc, attrs); + scope.result = fromPropertyDescriptor(scope.engine, desc, attrs); } -ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context) +void ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(context); - ScopedObject O(scope, context->argument(0)); - if (!O) - return context->engine()->throwTypeError(); + ScopedObject O(scope, callData->argument(0)); + if (!O) { + scope.result = scope.engine->throwTypeError(); + return; + } - ScopedArrayObject array(scope, getOwnPropertyNames(context->d()->engine, context->args()[0])); - return array.asReturnedValue(); + scope.result = getOwnPropertyNames(scope.engine, callData->args[0]); } -ReturnedValue ObjectPrototype::method_create(CallContext *ctx) +void ObjectPrototype::method_create(const BuiltinFunction *builtin, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue O(scope, ctx->argument(0)); - if (!O->isObject() && !O->isNull()) - return ctx->engine()->throwTypeError(); + ScopedValue O(scope, callData->argument(0)); + if (!O->isObject() && !O->isNull()) { + scope.result = scope.engine->throwTypeError(); + return; + } - ScopedObject newObject(scope, ctx->d()->engine->newObject()); + ScopedObject newObject(scope, scope.engine->newObject()); newObject->setPrototype(O->as<Object>()); - if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) { - ctx->d()->callData->args[0] = newObject.asReturnedValue(); - return method_defineProperties(ctx); + if (callData->argc > 1 && !callData->args[1].isUndefined()) { + callData->args[0] = newObject; + method_defineProperties(builtin, scope, callData); + return; } - return newObject.asReturnedValue(); + scope.result = newObject; } -ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx) +void ObjectPrototype::method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject O(scope, ctx->argument(0)); - if (!O) - return ctx->engine()->throwTypeError(); + ScopedObject O(scope, callData->argument(0)); + if (!O) { + scope.result = scope.engine->throwTypeError(); + return; + } - ScopedString name(scope, ctx->argument(1), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString name(scope, callData->argument(1), ScopedString::Convert); + CHECK_EXCEPTION(); - ScopedValue attributes(scope, ctx->argument(2)); + ScopedValue attributes(scope, callData->argument(2)); ScopedProperty pd(scope); PropertyAttributes attrs; toPropertyDescriptor(scope.engine, attributes, pd, &attrs); - if (scope.engine->hasException) - return Encode::undefined(); + CHECK_EXCEPTION(); if (!O->__defineOwnProperty__(scope.engine, name, pd, attrs)) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return O.asReturnedValue(); + scope.result = O; } -ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) +void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject O(scope, ctx->argument(0)); + ScopedObject O(scope, callData->argument(0)); if (!O) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); + + ScopedObject o(scope, callData->argument(1), ScopedObject::Convert); + CHECK_EXCEPTION(); - ScopedObject o(scope, ctx->argument(1), ScopedObject::Convert); - if (scope.engine->hasException) - return Encode::undefined(); ScopedValue val(scope); ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); @@ -230,26 +230,24 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) PropertyAttributes nattrs; val = o->getValue(pd->value, attrs); toPropertyDescriptor(scope.engine, val, n, &nattrs); - if (scope.engine->hasException) - return Encode::undefined(); + CHECK_EXCEPTION(); bool ok; if (name) ok = O->__defineOwnProperty__(scope.engine, name, n, nattrs); else ok = O->__defineOwnProperty__(scope.engine, index, n, nattrs); if (!ok) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); } - return O.asReturnedValue(); + scope.result = O; } -ReturnedValue ObjectPrototype::method_seal(CallContext *ctx) +void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); o->setInternalClass(o->internalClass()->sealed()); @@ -261,15 +259,14 @@ ReturnedValue ObjectPrototype::method_seal(CallContext *ctx) } } - return o.asReturnedValue(); + scope.result = o; } -ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx) +void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (ArgumentsObject::isNonStrictArgumentsObject(o)) static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate(); @@ -285,96 +282,111 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx) o->arrayData()->attrs[i].setWritable(false); } } - return o.asReturnedValue(); + scope.result = o; } -ReturnedValue ObjectPrototype::method_preventExtensions(CallContext *ctx) +void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); o->setInternalClass(o->internalClass()->nonExtensible()); - return o.asReturnedValue(); + scope.result = o; } -ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx) +void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - if (o->isExtensible()) - return Encode(false); + if (o->isExtensible()) { + scope.result = Encode(false); + return; + } - if (o->internalClass() != o->internalClass()->sealed()) - return Encode(false); + if (o->internalClass() != o->internalClass()->sealed()) { + scope.result = Encode(false); + return; + } - if (!o->arrayData() || !o->arrayData()->length()) - return Encode(true); + if (!o->arrayData() || !o->arrayData()->length()) { + scope.result = Encode(true); + return; + } Q_ASSERT(o->arrayData() && o->arrayData()->length()); - if (!o->arrayData()->attrs) - return Encode(false); + if (!o->arrayData()->attrs) { + scope.result = Encode(false); + return; + } for (uint i = 0; i < o->arrayData()->alloc; ++i) { if (!o->arrayData()->isEmpty(i)) - if (o->arrayData()->attributes(i).isConfigurable()) - return Encode(false); + if (o->arrayData()->attributes(i).isConfigurable()) { + scope.result = Encode(false); + return; + } } - return Encode(true); + scope.result = Encode(true); } -ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx) +void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - if (o->isExtensible()) - return Encode(false); + if (o->isExtensible()) { + scope.result = Encode(false); + return; + } - if (o->internalClass() != o->internalClass()->frozen()) - return Encode(false); + if (o->internalClass() != o->internalClass()->frozen()) { + scope.result = Encode(false); + return; + } - if (!o->arrayData() || !o->arrayData()->length()) - return Encode(true); + if (!o->arrayData() || !o->arrayData()->length()) { + scope.result = Encode(true); + return; + } Q_ASSERT(o->arrayData() && o->arrayData()->length()); - if (!o->arrayData()->attrs) - return Encode(false); + if (!o->arrayData()->attrs) { + scope.result = Encode(false); + return; + } for (uint i = 0; i < o->arrayData()->alloc; ++i) { if (!o->arrayData()->isEmpty(i)) - if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) - return Encode(false); + if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) { + scope.result = Encode(false); + return; + } } - return Encode(true); + scope.result = Encode(true); } -ReturnedValue ObjectPrototype::method_isExtensible(CallContext *ctx) +void ObjectPrototype::method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode((bool)o->isExtensible()); + scope.result = Encode((bool)o->isExtensible()); } -ReturnedValue ObjectPrototype::method_keys(CallContext *ctx) +void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject a(scope, scope.engine->newArrayObject()); ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); @@ -385,175 +397,159 @@ ReturnedValue ObjectPrototype::method_keys(CallContext *ctx) a->push_back(name); } - return a.asReturnedValue(); + scope.result = a; } -ReturnedValue ObjectPrototype::method_toString(CallContext *ctx) +void ObjectPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - if (ctx->thisObject().isUndefined()) { - return ctx->d()->engine->newString(QStringLiteral("[object Undefined]"))->asReturnedValue(); - } else if (ctx->thisObject().isNull()) { - return ctx->d()->engine->newString(QStringLiteral("[object Null]"))->asReturnedValue(); + if (callData->thisObject.isUndefined()) { + scope.result = scope.engine->newString(QStringLiteral("[object Undefined]")); + } else if (callData->thisObject.isNull()) { + scope.result = scope.engine->newString(QStringLiteral("[object Null]")); } else { - ScopedObject obj(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject obj(scope, callData->thisObject.toObject(scope.engine)); QString className = obj->className(); - return ctx->d()->engine->newString(QStringLiteral("[object %1]").arg(className))->asReturnedValue(); + scope.result = scope.engine->newString(QStringLiteral("[object %1]").arg(className)); } } -ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx) +void ObjectPrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject o(scope, callData->thisObject.toObject(scope.engine)); if (!o) - return Encode::undefined(); - ScopedFunctionObject f(scope, o->get(ctx->d()->engine->id_toString())); + RETURN_UNDEFINED(); + + ScopedFunctionObject f(scope, o->get(scope.engine->id_toString())); if (!f) - return ctx->engine()->throwTypeError(); - ScopedCallData callData(scope); - callData->thisObject = o; + THROW_TYPE_ERROR(); + ScopedCallData cData(scope); + cData->thisObject = o; f->call(scope, callData); - return scope.result.asReturnedValue(); } -ReturnedValue ObjectPrototype::method_valueOf(CallContext *ctx) +void ObjectPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue v(scope, ctx->thisObject().toObject(scope.engine)); - if (ctx->d()->engine->hasException) - return Encode::undefined(); - return v->asReturnedValue(); + scope.result = callData->thisObject.toObject(scope.engine); } -ReturnedValue ObjectPrototype::method_hasOwnProperty(CallContext *ctx) +void ObjectPrototype::method_hasOwnProperty(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedString P(scope, ctx->argument(0), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); - ScopedObject O(scope, ctx->thisObject(), ScopedObject::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString P(scope, callData->argument(0), ScopedString::Convert); + CHECK_EXCEPTION(); + ScopedObject O(scope, callData->thisObject, ScopedObject::Convert); + CHECK_EXCEPTION(); bool r = O->hasOwnProperty(P); if (!r) r = !O->query(P).isEmpty(); - return Encode(r); + scope.result = Encode(r); } -ReturnedValue ObjectPrototype::method_isPrototypeOf(CallContext *ctx) +void ObjectPrototype::method_isPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject V(scope, ctx->argument(0)); - if (!V) - return Encode(false); + ScopedObject V(scope, callData->argument(0)); + if (!V) { + scope.result = Encode(false); + return; + } - ScopedObject O(scope, ctx->thisObject(), ScopedObject::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedObject O(scope, callData->thisObject, ScopedObject::Convert); + CHECK_EXCEPTION(); ScopedObject proto(scope, V->prototype()); while (proto) { - if (O->d() == proto->d()) - return Encode(true); + if (O->d() == proto->d()) { + scope.result = Encode(true); + return; + } proto = proto->prototype(); } - return Encode(false); + scope.result = Encode(false); } -ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx) +void ObjectPrototype::method_propertyIsEnumerable(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedString p(scope, ctx->argument(0), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString p(scope, callData->argument(0), ScopedString::Convert); + CHECK_EXCEPTION(); - ScopedObject o(scope, ctx->thisObject(), ScopedObject::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedObject o(scope, callData->thisObject, ScopedObject::Convert); + CHECK_EXCEPTION(); PropertyAttributes attrs; o->getOwnProperty(p, &attrs); - return Encode(attrs.isEnumerable()); + scope.result = Encode(attrs.isEnumerable()); } -ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) +void ObjectPrototype::method_defineGetter(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 2) - return ctx->engine()->throwTypeError(); + if (callData->argc < 2) + THROW_TYPE_ERROR(); - Scope scope(ctx); - ScopedFunctionObject f(scope, ctx->argument(1)); + ScopedFunctionObject f(scope, callData->argument(1)); if (!f) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedString prop(scope, ctx->argument(0), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString prop(scope, callData->argument(0), ScopedString::Convert); + CHECK_EXCEPTION(); - ScopedObject o(scope, ctx->thisObject()); + ScopedObject o(scope, callData->thisObject); if (!o) { - if (!ctx->thisObject().isUndefined()) - return Encode::undefined(); - o = ctx->d()->engine->globalObject; + if (!callData->thisObject.isUndefined()) + RETURN_UNDEFINED(); + o = scope.engine->globalObject; } ScopedProperty pd(scope); pd->value = f; pd->set = Primitive::emptyValue(); o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor); - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) +void ObjectPrototype::method_defineSetter(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 2) - return ctx->engine()->throwTypeError(); + if (callData->argc < 2) + THROW_TYPE_ERROR(); - Scope scope(ctx); - ScopedFunctionObject f(scope, ctx->argument(1)); + ScopedFunctionObject f(scope, callData->argument(1)); if (!f) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedString prop(scope, ctx->argument(0), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString prop(scope, callData->argument(0), ScopedString::Convert); + CHECK_EXCEPTION(); - ScopedObject o(scope, ctx->thisObject()); + ScopedObject o(scope, callData->thisObject); if (!o) { - if (!ctx->thisObject().isUndefined()) - return Encode::undefined(); - o = ctx->d()->engine->globalObject; + if (!callData->thisObject.isUndefined()) + RETURN_UNDEFINED(); + o = scope.engine->globalObject; } ScopedProperty pd(scope); pd->value = Primitive::emptyValue(); pd->set = f; o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor); - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx) +void ObjectPrototype::method_get_proto(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject().as<Object>()); + ScopedObject o(scope, callData->thisObject.as<Object>()); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return o->prototype()->asReturnedValue(); + scope.result = o->prototype(); } -ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx) +void ObjectPrototype::method_set_proto(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject()); - if (!o || !ctx->argc()) - return ctx->engine()->throwTypeError(); + ScopedObject o(scope, callData->thisObject); + if (!o || !callData->argc) + THROW_TYPE_ERROR(); - if (ctx->args()[0].isNull()) { + if (callData->args[0].isNull()) { o->setPrototype(0); - return Encode::undefined(); + RETURN_UNDEFINED(); } - ScopedObject p(scope, ctx->args()[0]); + ScopedObject p(scope, callData->args[0]); bool ok = false; if (!!p) { if (o->prototype() == p->d()) { @@ -562,9 +558,11 @@ ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx) ok = o->setPrototype(p); } } - if (!ok) - return ctx->engine()->throwTypeError(QStringLiteral("Cyclic __proto__ value")); - return Encode::undefined(); + if (!ok) { + scope.result = scope.engine->throwTypeError(QStringLiteral("Cyclic __proto__ value")); + return; + } + RETURN_UNDEFINED(); } void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs) diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index e3d85782d5..1db8615511 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -78,32 +78,32 @@ struct ObjectPrototype: Object { void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_getPrototypeOf(CallContext *ctx); - static ReturnedValue method_getOwnPropertyDescriptor(CallContext *ctx); - static ReturnedValue method_getOwnPropertyNames(CallContext *context); - static ReturnedValue method_create(CallContext *ctx); - static ReturnedValue method_defineProperty(CallContext *ctx); - static ReturnedValue method_defineProperties(CallContext *ctx); - static ReturnedValue method_seal(CallContext *ctx); - static ReturnedValue method_freeze(CallContext *ctx); - static ReturnedValue method_preventExtensions(CallContext *ctx); - static ReturnedValue method_isSealed(CallContext *ctx); - static ReturnedValue method_isFrozen(CallContext *ctx); - static ReturnedValue method_isExtensible(CallContext *ctx); - static ReturnedValue method_keys(CallContext *ctx); - - static ReturnedValue method_toString(CallContext *ctx); - static ReturnedValue method_toLocaleString(CallContext *ctx); - static ReturnedValue method_valueOf(CallContext *ctx); - static ReturnedValue method_hasOwnProperty(CallContext *ctx); - static ReturnedValue method_isPrototypeOf(CallContext *ctx); - static ReturnedValue method_propertyIsEnumerable(CallContext *ctx); - - static ReturnedValue method_defineGetter(CallContext *ctx); - static ReturnedValue method_defineSetter(CallContext *ctx); - - static ReturnedValue method_get_proto(CallContext *ctx); - static ReturnedValue method_set_proto(CallContext *ctx); + static void method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_create(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_seal(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_keys(const BuiltinFunction *, Scope &scope, CallData *callData); + + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_hasOwnProperty(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_propertyIsEnumerable(const BuiltinFunction *, Scope &scope, CallData *callData); + + static void method_defineGetter(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_defineSetter(const BuiltinFunction *, Scope &scope, CallData *callData); + + static void method_get_proto(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_set_proto(const BuiltinFunction *, Scope &scope, CallData *callData); static void toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs); static ReturnedValue fromPropertyDescriptor(ExecutionEngine *engine, const Property *desc, PropertyAttributes attrs); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 4e627e003f..379c3babda 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -68,6 +68,32 @@ namespace QV4 { struct ScopedValue; +#define CHECK_EXCEPTION() \ + do { \ + if (scope.hasException()) { \ + scope.result = Encode::undefined(); \ + return; \ + } \ + } while (false) + +#define RETURN_UNDEFINED() \ + do { \ + scope.result = Encode::undefined(); \ + return; \ + } while (false) + +#define RETURN_RESULT(r) \ + do { \ + scope.result = r; \ + return; \ + } while (false) + +#define THROW_TYPE_ERROR() \ + do { \ + scope.result = scope.engine->throwTypeError(); \ + return; \ + } while (false) + struct Scope { inline Scope(ExecutionContext *ctx) : engine(ctx->d()->engine) diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 622359a7d9..b9183313cd 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -347,6 +347,10 @@ Param traceParam(const Param ¶m) goto catchException; \ VALUE(param) = tmp; \ } +// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro +#ifdef CHECK_EXCEPTION +#undef CHECK_EXCEPTION +#endif #define CHECK_EXCEPTION \ if (engine->hasException) \ goto catchException |