aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/jsruntime.pri3
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp86
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h11
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp98
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h12
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp16
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h2
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp553
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h52
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp31
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4context.cpp447
-rw-r--r--src/qml/jsruntime/qv4context_p.h244
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp133
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h22
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp541
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h106
-rw-r--r--src/qml/jsruntime/qv4engine.cpp189
-rw-r--r--src/qml/jsruntime/qv4engine_p.h86
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h29
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp74
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h20
-rw-r--r--src/qml/jsruntime/qv4function.cpp78
-rw-r--r--src/qml/jsruntime/qv4function_p.h21
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp347
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h79
-rw-r--r--src/qml/jsruntime/qv4global_p.h21
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp140
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h24
-rw-r--r--src/qml/jsruntime/qv4include.cpp20
-rw-r--r--src/qml/jsruntime/qv4include_p.h2
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h139
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp76
-rw-r--r--src/qml/jsruntime/qv4jsonobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp269
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h31
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp82
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h38
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp181
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h24
-rw-r--r--src/qml/jsruntime/qv4object.cpp184
-rw-r--r--src/qml/jsruntime/qv4object_p.h48
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp367
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h58
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h39
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp8
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h8
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp112
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h16
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp26
-rw-r--r--src/qml/jsruntime/qv4regexp_p.h12
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp170
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h28
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp724
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h15
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h99
-rw-r--r--src/qml/jsruntime/qv4runtimecodegen.cpp79
-rw-r--r--src/qml/jsruntime/qv4runtimecodegen_p.h82
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h79
-rw-r--r--src/qml/jsruntime/qv4script.cpp88
-rw-r--r--src/qml/jsruntime/qv4script_p.h40
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp45
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4string_p.h3
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp441
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h52
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp176
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h16
-rw-r--r--src/qml/jsruntime/qv4value.cpp119
-rw-r--r--src/qml/jsruntime/qv4value_p.h337
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp36
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp1377
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h5
74 files changed, 4517 insertions, 4727 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 9938f60aea..a270cb1aa3 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -33,6 +33,7 @@ SOURCES += \
$$PWD/qv4variantobject.cpp \
$$PWD/qv4objectiterator.cpp \
$$PWD/qv4regexp.cpp \
+ $$PWD/qv4runtimecodegen.cpp \
$$PWD/qv4serialize.cpp \
$$PWD/qv4script.cpp \
$$PWD/qv4sequenceobject.cpp \
@@ -58,6 +59,7 @@ HEADERS += \
$$PWD/qv4identifiertable_p.h \
$$PWD/qv4managed_p.h \
$$PWD/qv4internalclass_p.h \
+ $$PWD/qv4jscall_p.h \
$$PWD/qv4sparsearray_p.h \
$$PWD/qv4arraydata_p.h \
$$PWD/qv4arrayobject_p.h \
@@ -76,6 +78,7 @@ HEADERS += \
$$PWD/qv4objectproto_p.h \
$$PWD/qv4qmlcontext_p.h \
$$PWD/qv4regexpobject_p.h \
+ $$PWD/qv4runtimecodegen_p.h \
$$PWD/qv4stringobject_p.h \
$$PWD/qv4variantobject_p.h \
$$PWD/qv4property_p.h \
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 0905c2828a..5833e39561 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -41,24 +41,26 @@
#include <qv4scopedvalue_p.h>
#include <qv4string_p.h>
#include <qv4function_p.h>
+#include <qv4jscall_p.h>
using namespace QV4;
DEFINE_OBJECT_VTABLE(ArgumentsObject);
-void Heap::ArgumentsObject::init(QV4::CallContext *context)
+void Heap::ArgumentsObject::init(QV4::CallContext *context, bool strict)
{
ExecutionEngine *v4 = internalClass->engine;
Object::init();
fullyCreated = false;
+ isStrict = strict;
this->context.set(v4, context->d());
Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
Scope scope(v4);
Scoped<QV4::ArgumentsObject> args(scope, this);
- if (context->d()->strictMode) {
+ if (isStrict) {
Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee()));
Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(v4->id_caller()));
args->setProperty(CalleePropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
@@ -74,7 +76,7 @@ void Heap::ArgumentsObject::init(QV4::CallContext *context)
args->setProperty(CalleePropertyIndex, context->d()->function);
}
Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(v4->id_length()));
- args->setProperty(LengthPropertyIndex, Primitive::fromInt32(context->d()->callData->argc));
+ args->setProperty(LengthPropertyIndex, Primitive::fromInt32(context->argc()));
}
void ArgumentsObject::fullyCreate()
@@ -84,7 +86,7 @@ void ArgumentsObject::fullyCreate()
Scope scope(engine());
- uint argCount = context()->callData->argc;
+ uint argCount = context()->argc();
uint numAccessors = qMin(context()->formalParameterCount(), argCount);
ArrayData::realloc(this, Heap::ArrayData::Sparse, argCount, true);
scope.engine->requireArgumentsAccessors(numAccessors);
@@ -93,11 +95,11 @@ void ArgumentsObject::fullyCreate()
if (numAccessors) {
d()->mappedArguments.set(scope.engine, md->allocate(scope.engine, numAccessors));
for (uint i = 0; i < numAccessors; ++i) {
- d()->mappedArguments->values.set(scope.engine, i, context()->callData->args[i]);
+ d()->mappedArguments->values.set(scope.engine, i, context()->args()[i]);
arraySet(i, scope.engine->argumentsAccessors + i, Attr_Accessor);
}
}
- arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors);
+ arrayPut(numAccessors, context()->args() + numAccessors, argCount - numAccessors);
for (uint i = numAccessors; i < argCount; ++i)
setArrayAttributes(i, Attr_Data);
@@ -111,7 +113,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
Scope scope(engine);
ScopedProperty map(scope);
PropertyAttributes mapAttrs;
- uint numAccessors = qMin(context()->formalParameterCount(), static_cast<uint>(context()->callData->argc));
+ uint numAccessors = qMin(context()->formalParameterCount(), static_cast<uint>(context()->argc()));
bool isMapped = false;
if (arrayData() && index < numAccessors &&
arrayData()->attributes(index).isAccessor() &&
@@ -127,18 +129,20 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
arrayIndex.set(scope.engine, d()->mappedArguments->values[index]);
}
- bool strict = engine->current->strictMode;
- engine->current->strictMode = false;
bool result = Object::defineOwnProperty2(scope.engine, index, desc, attrs);
- engine->current->strictMode = strict;
+ if (!result) {
+ if (d()->isStrict)
+ return engine->throwTypeError();
+ return false;
+ }
if (isMapped && attrs.isData()) {
Q_ASSERT(arrayData());
ScopedFunctionObject setter(scope, map->setter());
- ScopedCallData callData(scope, 1);
- callData->thisObject = this->asReturnedValue();
- callData->args[0] = desc->value;
- setter->call(scope, callData);
+ JSCallData jsCallData(scope, 1);
+ *jsCallData->thisObject = this->asReturnedValue();
+ jsCallData->args[0] = desc->value;
+ setter->call(jsCallData);
if (attrs.isWritable()) {
setArrayAttributes(index, mapAttrs);
@@ -146,8 +150,6 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
}
}
- if (engine->current->strictMode && !result)
- return engine->throwTypeError();
return result;
}
@@ -157,10 +159,10 @@ ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *ha
if (args->fullyCreated())
return Object::getIndexed(m, index, hasProperty);
- if (index < static_cast<uint>(args->context()->callData->argc)) {
+ if (index < static_cast<uint>(args->context()->argc())) {
if (hasProperty)
*hasProperty = true;
- return args->context()->callData->args[index].asReturnedValue();
+ return args->context()->args()[index].asReturnedValue();
}
if (hasProperty)
*hasProperty = false;
@@ -170,13 +172,13 @@ ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *ha
bool ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
- if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->callData->argc))
+ if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->argc()))
args->fullyCreate();
if (args->fullyCreated())
return Object::putIndexed(m, index, value);
- args->context()->callData->args[index] = value;
+ args->context()->setArg(index, value);
return true;
}
@@ -194,8 +196,8 @@ PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index)
if (args->fullyCreated())
return Object::queryIndexed(m, index);
- uint numAccessors = qMin((int)args->context()->formalParameterCount(), args->context()->callData->argc);
- uint argCount = args->context()->callData->argc;
+ uint numAccessors = qMin((int)args->context()->formalParameterCount(), args->context()->argc());
+ uint argCount = args->context()->argc();
if (index >= argCount)
return PropertyAttributes();
if (index >= numAccessors)
@@ -205,35 +207,33 @@ PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index)
DEFINE_OBJECT_VTABLE(ArgumentsGetterFunction);
-void ArgumentsGetterFunction::call(const Managed *getter, Scope &scope, CallData *callData)
+ReturnedValue ArgumentsGetterFunction::call(const FunctionObject *getter, const Value *thisObject, const Value *, int)
{
- ExecutionEngine *v4 = static_cast<const ArgumentsGetterFunction *>(getter)->engine();
- Scoped<ArgumentsGetterFunction> g(scope, static_cast<const ArgumentsGetterFunction *>(getter));
- Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
- if (!o) {
- scope.result = v4->throwTypeError();
- return;
- }
+ ExecutionEngine *v4 = getter->engine();
+ Scope scope(v4);
+ const ArgumentsGetterFunction *g = static_cast<const ArgumentsGetterFunction *>(getter);
+ Scoped<ArgumentsObject> o(scope, thisObject->as<ArgumentsObject>());
+ if (!o)
+ return v4->throwTypeError();
- Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->callData->argc));
- scope.result = o->context()->callData->args[g->index()];
+ Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->argc()));
+ return o->context()->args()[g->index()].asReturnedValue();
}
DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction);
-void ArgumentsSetterFunction::call(const Managed *setter, Scope &scope, CallData *callData)
+ReturnedValue ArgumentsSetterFunction::call(const FunctionObject *setter, const Value *thisObject, const Value *argv, int argc)
{
- ExecutionEngine *v4 = static_cast<const ArgumentsSetterFunction *>(setter)->engine();
- Scoped<ArgumentsSetterFunction> s(scope, static_cast<const ArgumentsSetterFunction *>(setter));
- Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
- if (!o) {
- scope.result = v4->throwTypeError();
- return;
- }
+ ExecutionEngine *v4 = setter->engine();
+ Scope scope(v4);
+ const ArgumentsSetterFunction *s = static_cast<const ArgumentsSetterFunction *>(setter);
+ Scoped<ArgumentsObject> o(scope, thisObject->as<ArgumentsObject>());
+ if (!o)
+ return v4->throwTypeError();
- Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->callData->argc));
- o->context()->callData->args[s->index()] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined();
- scope.result = Encode::undefined();
+ Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->argc()));
+ o->context()->setArg(s->index(), argc ? argv[0] : Primitive::undefinedValue());
+ return Encode::undefined();
}
uint ArgumentsObject::getLength(const Managed *m)
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 46e1f884e8..cd270e8b47 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -78,7 +78,8 @@ DECLARE_HEAP_OBJECT(ArgumentsSetterFunction, FunctionObject) {
#define ArgumentsObjectMembers(class, Member) \
Member(class, Pointer, CallContext *, context) \
Member(class, Pointer, MemberData *, mappedArguments) \
- Member(class, NoMark, bool, fullyCreated)
+ Member(class, NoMark, bool, fullyCreated) \
+ Member(class, NoMark, bool, isStrict)
DECLARE_HEAP_OBJECT(ArgumentsObject, Object) {
DECLARE_MARK_TABLE(ArgumentsObject);
@@ -87,7 +88,7 @@ DECLARE_HEAP_OBJECT(ArgumentsObject, Object) {
CalleePropertyIndex = 1,
CallerPropertyIndex = 3
};
- void init(QV4::CallContext *context);
+ void init(QV4::CallContext *context, bool strict);
};
}
@@ -97,7 +98,7 @@ struct ArgumentsGetterFunction: FunctionObject
V4_OBJECT2(ArgumentsGetterFunction, FunctionObject)
uint index() const { return d()->index; }
- static void call(const Managed *that, Scope &scope, CallData *d);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
inline void
@@ -112,7 +113,7 @@ struct ArgumentsSetterFunction: FunctionObject
V4_OBJECT2(ArgumentsSetterFunction, FunctionObject)
uint index() const { return d()->index; }
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
inline void
@@ -132,7 +133,7 @@ struct ArgumentsObject: Object {
static bool isNonStrictArgumentsObject(Managed *m) {
return m->d()->vtable()->type == Type_ArgumentsObject &&
- !static_cast<ArgumentsObject *>(m)->context()->strictMode;
+ !static_cast<ArgumentsObject *>(m)->d()->isStrict;
}
bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs);
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index ffe9aa846f..3f06ce8bd5 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -40,6 +40,7 @@
#include "qv4typedarray_p.h"
#include "qv4dataview_p.h"
#include "qv4string_p.h"
+#include "qv4jscall_p.h"
using namespace QV4;
@@ -51,49 +52,42 @@ void Heap::ArrayBufferCtor::init(QV4::ExecutionContext *scope)
Heap::FunctionObject::init(scope, QStringLiteral("ArrayBuffer"));
}
-void ArrayBufferCtor::construct(const Managed *m, Scope &scope, CallData *callData)
+ReturnedValue ArrayBufferCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- ExecutionEngine *v4 = static_cast<const Object *>(m)->engine();
+ ExecutionEngine *v4 = f->engine();
+ Scope scope(v4);
- ScopedValue l(scope, callData->argument(0));
+ ScopedValue l(scope, argc ? argv[0] : Primitive::undefinedValue());
double dl = l->toInteger();
- if (v4->hasException) {
- scope.result = Encode::undefined();
- return;
- }
+ if (v4->hasException)
+ return Encode::undefined();
uint len = (uint)qBound(0., dl, (double)UINT_MAX);
- if (len != dl) {
- scope.result = v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length"));
- return;
- }
+ if (len != dl)
+ return v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length"));
Scoped<ArrayBuffer> a(scope, v4->newArrayBuffer(len));
- if (scope.engine->hasException) {
- scope.result = Encode::undefined();
- } else {
- scope.result = a->asReturnedValue();
- }
+ if (scope.engine->hasException)
+ return Encode::undefined();
+
+ return a->asReturnedValue();
}
-void ArrayBufferCtor::call(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue ArrayBufferCtor::call(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
- construct(that, scope, callData);
+ return callAsConstructor(f, argv, argc);
}
-void ArrayBufferCtor::method_isView(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayBufferCtor::method_isView(const BuiltinFunction *, CallData *callData)
{
- QV4::Scoped<TypedArray> a(scope, callData->argument(0));
- if (!!a) {
- scope.result = Encode(true);
- return;
- }
- QV4::Scoped<DataView> v(scope, callData->argument(0));
- if (!!v) {
- scope.result = Encode(true);
- return;
- }
- scope.result = Encode(false);
+ if (callData->argc() < 1)
+ return Encode(false);
+
+ if (callData->args[0].as<TypedArray>() ||
+ callData->args[0].as<DataView>())
+ return Encode(true);
+
+ return Encode(false);
}
@@ -163,48 +157,52 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("toString"), method_toString, 0);
}
-void ArrayBufferPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayBufferPrototype::method_get_byteLength(const BuiltinFunction *b, CallData *callData)
{
- Scoped<ArrayBuffer> v(scope, callData->thisObject);
- if (!v)
- THROW_TYPE_ERROR();
+ ArrayBuffer *a = callData->thisObject.as<ArrayBuffer>();
+ if (!a)
+ return b->engine()->throwTypeError();
- scope.result = Encode(v->d()->data->size);
+ return Encode(a->d()->data->size);
}
-void ArrayBufferPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayBufferPrototype::method_slice(const BuiltinFunction *b, CallData *callData)
{
- Scoped<ArrayBuffer> a(scope, callData->thisObject);
+ ExecutionEngine *v4 = b->engine();
+ ArrayBuffer *a = callData->thisObject.as<ArrayBuffer>();
if (!a)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
- double start = callData->argc > 0 ? callData->args[0].toInteger() : 0;
- double end = (callData->argc < 2 || callData->args[1].isUndefined()) ?
+ double start = callData->argc() > 0 ? callData->args[0].toInteger() : 0;
+ double end = (callData->argc() < 2 || callData->args[1].isUndefined()) ?
a->d()->data->size : callData->args[1].toInteger();
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size);
double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size);
+ Scope scope(v4);
ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor()));
if (!constructor)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
- ScopedCallData cData(scope, 1);
+ JSCallData jsCallData(scope, 1);
double newLen = qMax(final - first, 0.);
- cData->args[0] = QV4::Encode(newLen);
- constructor->construct(scope, cData);
- QV4::Scoped<ArrayBuffer> newBuffer(scope, scope.result);
+ jsCallData->args[0] = QV4::Encode(newLen);
+ QV4::Scoped<ArrayBuffer> newBuffer(scope, constructor->callAsConstructor(jsCallData));
if (!newBuffer || newBuffer->d()->data->size < (int)newLen)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
memcpy(newBuffer->d()->data->data(), a->d()->data->data() + (uint)first, newLen);
+ return Encode::undefined();
}
-void ArrayBufferPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayBufferPrototype::method_toString(const BuiltinFunction *b, CallData *callData)
{
- Scoped<ArrayBuffer> a(scope, callData->thisObject);
+ ExecutionEngine *v4 = b->engine();
+ ArrayBuffer *a = callData->thisObject.as<ArrayBuffer>();
if (!a)
RETURN_UNDEFINED();
- scope.result = scope.engine->newString(QString::fromUtf8(a->asByteArray()));
+ return Encode(v4->newString(QString::fromUtf8(a->asByteArray())));
}
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index 4f7926d3dc..e144faa47f 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -78,10 +78,10 @@ struct ArrayBufferCtor: FunctionObject
{
V4_OBJECT2(ArrayBufferCtor, FunctionObject)
- static void construct(const Managed *m, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
- static void method_isView(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_isView(const BuiltinFunction *, CallData *callData);
};
@@ -104,9 +104,9 @@ struct ArrayBufferPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_get_byteLength(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_slice(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index df9884d84a..b77fab3305 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -43,6 +43,7 @@
#include "qv4runtime_p.h"
#include "qv4argumentsobject_p.h"
#include "qv4string_p.h"
+#include "qv4jscall_p.h"
using namespace QV4;
@@ -672,15 +673,14 @@ bool ArrayElementLessThan::operator()(Value v1, Value v2) const
return false;
if (v2.isUndefined() || v2.isEmpty())
return true;
- ScopedObject o(scope, m_comparefn);
+ ScopedFunctionObject o(scope, m_comparefn);
if (o) {
Scope scope(o->engine());
ScopedValue result(scope);
- ScopedCallData callData(scope, 2);
- callData->thisObject = Primitive::undefinedValue();
- callData->args[0] = v1;
- callData->args[1] = v2;
- result = QV4::Runtime::method_callValue(scope.engine, m_comparefn, callData);
+ JSCallData jsCallData(scope, 2);
+ jsCallData->args[0] = v1;
+ jsCallData->args[1] = v2;
+ result = o->call(jsCallData);
return result->toNumber() < 0;
}
@@ -754,7 +754,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
if (!arrayData || !arrayData->length())
return;
- if (!(comparefn.isUndefined() || comparefn.as<Object>())) {
+ if (!comparefn.isUndefined() && !comparefn.isFunctionObject()) {
engine->throwTypeError();
return;
}
@@ -833,7 +833,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
}
- ArrayElementLessThan lessThan(engine, thisObject, comparefn);
+ ArrayElementLessThan lessThan(engine, thisObject, static_cast<const FunctionObject &>(comparefn));
Value *begin = thisObject->arrayData()->values.values;
sortHelper(begin, begin + len, *begin, lessThan);
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index e1de2e82e6..6e41c756a8 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -144,7 +144,7 @@ DECLARE_HEAP_OBJECT(ArrayData, Base) {
V4_ASSERT_IS_TRIVIAL(ArrayData)
struct SimpleArrayData : public ArrayData {
- uint mappedIndex(uint index) const { return (index + offset) % values.alloc; }
+ uint mappedIndex(uint index) const { index += offset; if (index >= values.alloc) index -= values.alloc; return index; }
const Value &data(uint index) const { return values[mappedIndex(index)]; }
void setData(EngineBase *e, uint index, Value newVal) {
values.set(e, mappedIndex(index), newVal);
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index a2c19e1f2d..dede423b73 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -40,7 +40,7 @@
#include "qv4arrayobject_p.h"
#include "qv4sparsearray_p.h"
#include "qv4objectproto_p.h"
-#include "qv4scopedvalue_p.h"
+#include "qv4jscall_p.h"
#include "qv4argumentsobject_p.h"
#include "qv4runtime_p.h"
#include "qv4string_p.h"
@@ -55,35 +55,34 @@ void Heap::ArrayCtor::init(QV4::ExecutionContext *scope)
Heap::FunctionObject::init(scope, QStringLiteral("Array"));
}
-void ArrayCtor::construct(const Managed *m, Scope &scope, CallData *callData)
+ReturnedValue ArrayCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- ExecutionEngine *v4 = static_cast<const ArrayCtor *>(m)->engine();
+ ExecutionEngine *v4 = static_cast<const ArrayCtor *>(f)->engine();
+ Scope scope(v4);
ScopedArrayObject a(scope, v4->newArrayObject());
uint len;
- if (callData->argc == 1 && callData->args[0].isNumber()) {
+ if (argc == 1 && argv[0].isNumber()) {
bool ok;
- len = callData->args[0].asArrayLength(&ok);
+ len = argv[0].asArrayLength(&ok);
- if (!ok) {
- scope.result = v4->throwRangeError(callData->args[0]);
- return;
- }
+ if (!ok)
+ return v4->throwRangeError(argv[0]);
if (len < 0x1000)
a->arrayReserve(len);
} else {
- len = callData->argc;
+ len = argc;
a->arrayReserve(len);
- a->arrayPut(0, callData->args, len);
+ a->arrayPut(0, argv, len);
}
a->setArrayLengthUnchecked(len);
- scope.result = a.asReturnedValue();
+ return a.asReturnedValue();
}
-void ArrayCtor::call(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue ArrayCtor::call(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
- construct(that, scope, callData);
+ return callAsConstructor(f, argv, argc);
}
void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -119,34 +118,36 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("reduceRight"), method_reduceRight, 1);
}
-void ArrayPrototype::method_isArray(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_isArray(const BuiltinFunction *, CallData *callData)
{
- bool isArray = callData->argc && callData->args[0].as<ArrayObject>();
- scope.result = Encode(isArray);
+ bool isArray = callData->argc() && callData->args[0].as<ArrayObject>();
+ return Encode(isArray);
}
-void ArrayPrototype::method_toString(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_toString(const BuiltinFunction *builtin, CallData *callData)
{
- 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 = callData->thisObject;
- f->call(scope, d);
- return;
+ ExecutionEngine *v4 = builtin->engine();
+ if (!callData->thisObject.isObject()) {
+ callData->thisObject = callData->thisObject.toObject(v4);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
}
- ObjectPrototype::method_toString(builtin, scope, callData);
+
+ callData->accumulator = v4->newString(QStringLiteral("join"));
+ callData->function = static_cast<Object &>(callData->thisObject).get(static_cast<String *>(&callData->accumulator));
+ if (callData->function.isFunctionObject())
+ return static_cast<FunctionObject &>(callData->function).call(&callData->thisObject, callData->args, callData->argc());
+ return ObjectPrototype::method_toString(builtin, callData);
}
-void ArrayPrototype::method_toLocaleString(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_toLocaleString(const BuiltinFunction *builtin, CallData *callData)
{
- return method_toString(builtin, scope, callData);
+ return method_toString(builtin, callData);
}
-void ArrayPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_concat(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject thisObject(scope, callData->thisObject.toObject(scope.engine));
if (!thisObject)
RETURN_UNDEFINED();
@@ -162,7 +163,7 @@ void ArrayPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallDa
ScopedArrayObject elt(scope);
ScopedObject eltAsObj(scope);
ScopedValue entry(scope);
- for (int i = 0; i < callData->argc; ++i) {
+ for (int i = 0, ei = callData->argc(); i < ei; ++i) {
eltAsObj = callData->args[i];
elt = callData->args[i];
if (elt) {
@@ -173,6 +174,7 @@ void ArrayPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallDa
const uint startIndex = result->getLength();
for (int i = 0, len = eltAsObj->getLength(); i < len; ++i) {
entry = eltAsObj->getIndexed(i);
+ // spec says not to throw if this fails
result->putIndexed(startIndex + i, entry);
}
} else {
@@ -180,11 +182,12 @@ void ArrayPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallDa
}
}
- scope.result = result;
+ return result.asReturnedValue();
}
-void ArrayPrototype::method_find(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_find(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -195,30 +198,32 @@ void ArrayPrototype::method_find(const BuiltinFunction *, Scope &scope, CallData
if (!callback)
THROW_TYPE_ERROR();
- ScopedCallData cData(scope, 3);
- cData->thisObject = callData->argument(1);
- cData->args[2] = instance;
+ JSCallData jsCallData(scope, 3);
+ *jsCallData->thisObject = callData->argument(1);
ScopedValue v(scope);
+ ScopedValue result(scope);
for (uint k = 0; k < len; ++k) {
v = instance->getIndexed(k);
CHECK_EXCEPTION();
- cData->args[0] = v;
- cData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, cData);
+ jsCallData->args[0] = v;
+ jsCallData->args[1] = Primitive::fromDouble(k);
+ jsCallData->args[2] = instance;
+ result = callback->call(jsCallData);
CHECK_EXCEPTION();
- if (scope.result.toBoolean())
- RETURN_RESULT(v);
+ if (result->toBoolean())
+ return v->asReturnedValue();
}
RETURN_UNDEFINED();
}
-void ArrayPrototype::method_findIndex(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_findIndex(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -229,37 +234,37 @@ void ArrayPrototype::method_findIndex(const BuiltinFunction *, Scope &scope, Cal
if (!callback)
THROW_TYPE_ERROR();
- ScopedCallData cData(scope, 3);
- cData->thisObject = callData->argument(1);
- cData->args[2] = instance;
+ JSCallData jsCallData(scope, 3);
+ *jsCallData->thisObject = callData->argument(1);
ScopedValue v(scope);
+ ScopedValue result(scope);
for (uint k = 0; k < len; ++k) {
v = instance->getIndexed(k);
CHECK_EXCEPTION();
- cData->args[0] = v;
- cData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, cData);
+ jsCallData->args[0] = v;
+ jsCallData->args[1] = Primitive::fromDouble(k);
+ jsCallData->args[2] = instance;
+ result = callback->call(jsCallData);
CHECK_EXCEPTION();
- if (scope.result.toBoolean())
- RETURN_RESULT(Encode(k));
+ if (result->toBoolean())
+ return Encode(k);
}
- RETURN_RESULT(Encode(-1));
+ return Encode(-1);
}
-void ArrayPrototype::method_join(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_join(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedValue arg(scope, callData->argument(0));
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
- if (!instance) {
- scope.result = scope.engine->newString();
- return;
- }
+ if (!instance)
+ return Encode(scope.engine->newString());
QString r4;
if (arg->isUndefined())
@@ -270,10 +275,8 @@ void ArrayPrototype::method_join(const BuiltinFunction *, Scope &scope, CallData
ScopedValue length(scope, instance->get(scope.engine->id_length()));
const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32();
- if (!r2) {
- scope.result = scope.engine->newString();
- return;
- }
+ if (!r2)
+ return Encode(scope.engine->newString());
QString R;
@@ -311,11 +314,12 @@ void ArrayPrototype::method_join(const BuiltinFunction *, Scope &scope, CallData
}
}
- scope.result = scope.engine->newString(R);
+ return Encode(scope.engine->newString(R));
}
-void ArrayPrototype::method_pop(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_pop(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -331,18 +335,21 @@ void ArrayPrototype::method_pop(const BuiltinFunction *, Scope &scope, CallData
ScopedValue result(scope, instance->getIndexed(len - 1));
CHECK_EXCEPTION();
- instance->deleteIndexedProperty(len - 1);
- CHECK_EXCEPTION();
+ if (!instance->deleteIndexedProperty(len - 1))
+ return scope.engine->throwTypeError();
if (instance->isArrayObject())
instance->setArrayLength(len - 1);
- else
- instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
- scope.result = result;
+ else {
+ if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))))
+ return scope.engine->throwTypeError();
+ }
+ return result->asReturnedValue();
}
-void ArrayPrototype::method_push(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_push(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -352,46 +359,51 @@ void ArrayPrototype::method_push(const BuiltinFunction *, Scope &scope, CallData
uint len = instance->getLength();
- if (len + callData->argc < len) {
- // ughh...
+ if (len + callData->argc() < len) {
+ // ughh... this goes beyond UINT_MAX
double l = len;
ScopedString s(scope);
- for (int i = 0; i < callData->argc; ++i) {
+ for (int i = 0, ei = callData->argc(); i < ei; ++i) {
s = Primitive::fromDouble(l + i).toString(scope.engine);
- instance->put(s, callData->args[i]);
+ if (!instance->put(s, callData->args[i]))
+ return scope.engine->throwTypeError();
}
- double newLen = l + callData->argc;
- if (!instance->isArrayObject())
- instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen)));
- else {
+ double newLen = l + callData->argc();
+ if (!instance->isArrayObject()) {
+ if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))))
+ return scope.engine->throwTypeError();
+ } else {
ScopedString str(scope, scope.engine->newString(QStringLiteral("Array.prototype.push: Overflow")));
- scope.result = scope.engine->throwRangeError(str);
- return;
+ return scope.engine->throwRangeError(str);
}
- scope.result = Encode(newLen);
- return;
+ return Encode(newLen);
}
- if (!callData->argc)
+ if (!callData->argc())
;
else if (!instance->protoHasArray() && instance->arrayData()->length() <= len && instance->arrayData()->type == Heap::ArrayData::Simple) {
- instance->arrayData()->vtable()->putArray(instance, len, callData->args, callData->argc);
+ instance->arrayData()->vtable()->putArray(instance, len, callData->args, callData->argc());
len = instance->arrayData()->length();
} else {
- for (int i = 0; i < callData->argc; ++i)
- instance->putIndexed(len + i, callData->args[i]);
- len += callData->argc;
+ for (int i = 0, ei = callData->argc(); i < ei; ++i) {
+ if (!instance->putIndexed(len + i, callData->args[i]))
+ return scope.engine->throwTypeError();
+ }
+ len += callData->argc();
}
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(len);
- else
- instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len)));
+ else {
+ if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len))))
+ return scope.engine->throwTypeError();
+ }
- scope.result = Encode(len);
+ return Encode(len);
}
-void ArrayPrototype::method_reverse(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_reverse(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -407,21 +419,26 @@ void ArrayPrototype::method_reverse(const BuiltinFunction *, Scope &scope, CallD
lval = instance->getIndexed(lo, &loExists);
hval = instance->getIndexed(hi, &hiExists);
CHECK_EXCEPTION();
+ bool ok;
if (hiExists)
- instance->putIndexed(lo, hval);
- else
- instance->deleteIndexedProperty(lo);
- CHECK_EXCEPTION();
- if (loExists)
- instance->putIndexed(hi, lval);
+ ok = instance->putIndexed(lo, hval);
else
- instance->deleteIndexedProperty(hi);
+ ok = instance->deleteIndexedProperty(lo);
+ if (ok) {
+ if (loExists)
+ ok = instance->putIndexed(hi, lval);
+ else
+ ok = instance->deleteIndexedProperty(hi);
+ }
+ if (!ok)
+ return scope.engine->throwTypeError();
}
- scope.result = instance;
+ return instance->asReturnedValue();
}
-void ArrayPrototype::method_shift(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_shift(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -433,14 +450,16 @@ void ArrayPrototype::method_shift(const BuiltinFunction *, Scope &scope, CallDat
if (!len) {
if (!instance->isArrayObject())
- instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0)));
+ if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))))
+ return scope.engine->throwTypeError();
RETURN_UNDEFINED();
}
+ ScopedValue result(scope);
if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len && instance->arrayData()->type != Heap::ArrayData::Custom) {
- scope.result = instance->arrayData()->vtable()->pop_front(instance);
+ result = instance->arrayData()->vtable()->pop_front(instance);
} else {
- scope.result = instance->getIndexed(0);
+ result = instance->getIndexed(0);
CHECK_EXCEPTION();
ScopedValue v(scope);
// do it the slow way
@@ -448,24 +467,33 @@ void ArrayPrototype::method_shift(const BuiltinFunction *, Scope &scope, CallDat
bool exists;
v = instance->getIndexed(k, &exists);
CHECK_EXCEPTION();
+ bool ok;
if (exists)
- instance->putIndexed(k - 1, v);
+ ok = instance->putIndexed(k - 1, v);
else
- instance->deleteIndexedProperty(k - 1);
- CHECK_EXCEPTION();
+ ok = instance->deleteIndexedProperty(k - 1);
+ if (!ok)
+ return scope.engine->throwTypeError();
}
- instance->deleteIndexedProperty(len - 1);
- CHECK_EXCEPTION();
+ bool ok = instance->deleteIndexedProperty(len - 1);
+ if (!ok)
+ return scope.engine->throwTypeError();
}
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(len - 1);
- else
- instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
+ else {
+ bool ok = instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
+ if (!ok)
+ return scope.engine->throwTypeError();
+ }
+
+ return result->asReturnedValue();
}
-void ArrayPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_slice(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->thisObject.toObject(scope.engine));
if (!o)
RETURN_UNDEFINED();
@@ -481,7 +509,7 @@ void ArrayPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallDat
else
start = (uint) s;
uint end = len;
- if (callData->argc > 1 && !callData->args[1].isUndefined()) {
+ if (callData->argc() > 1 && !callData->args[1].isUndefined()) {
double e = callData->args[1].toInteger();
if (e < 0)
end = (uint)qMax(len + e, 0.);
@@ -501,11 +529,12 @@ void ArrayPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallDat
result->arraySet(n, v);
++n;
}
- scope.result = result;
+ return result->asReturnedValue();
}
-void ArrayPrototype::method_sort(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_sort(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -514,11 +543,12 @@ void ArrayPrototype::method_sort(const BuiltinFunction *, Scope &scope, CallData
ScopedValue comparefn(scope, callData->argument(0));
ArrayData::sort(scope.engine, instance, comparefn, len);
- scope.result = callData->thisObject;
+ return callData->thisObject.asReturnedValue();
}
-void ArrayPrototype::method_splice(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_splice(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -547,22 +577,24 @@ void ArrayPrototype::method_splice(const BuiltinFunction *, Scope &scope, CallDa
}
newArray->setArrayLengthUnchecked(deleteCount);
- uint itemCount = callData->argc < 2 ? 0 : callData->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);
CHECK_EXCEPTION();
+ bool ok;
if (exists)
- instance->putIndexed(k + itemCount, v);
+ ok = instance->putIndexed(k + itemCount, v);
else
- instance->deleteIndexedProperty(k + itemCount);
- CHECK_EXCEPTION();
+ ok = instance->deleteIndexedProperty(k + itemCount);
+ if (!ok)
+ return scope.engine->throwTypeError();
}
for (uint k = len; k > len - deleteCount + itemCount; --k) {
- instance->deleteIndexedProperty(k - 1);
- CHECK_EXCEPTION();
+ if (!instance->deleteIndexedProperty(k - 1))
+ return scope.engine->throwTypeError();
}
} else if (itemCount > deleteCount) {
uint k = len - deleteCount;
@@ -570,30 +602,29 @@ void ArrayPrototype::method_splice(const BuiltinFunction *, Scope &scope, CallDa
bool exists;
v = instance->getIndexed(k + deleteCount - 1, &exists);
CHECK_EXCEPTION();
+ bool ok;
if (exists)
- instance->putIndexed(k + itemCount - 1, v);
+ ok = instance->putIndexed(k + itemCount - 1, v);
else
- instance->deleteIndexedProperty(k + itemCount - 1);
- CHECK_EXCEPTION();
+ ok = instance->deleteIndexedProperty(k + itemCount - 1);
+ if (!ok)
+ return scope.engine->throwTypeError();
--k;
}
}
- for (uint i = 0; i < itemCount; ++i) {
+ for (uint i = 0; i < itemCount; ++i)
instance->putIndexed(start + i, callData->args[i + 2]);
- CHECK_EXCEPTION();
- }
- bool wasStrict = scope.engine->current->strictMode;
- scope.engine->current->strictMode = true;
- instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount)));
+ if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))))
+ return scope.engine->throwTypeError();
- scope.result = newArray;
- scope.engine->current->strictMode = wasStrict;
+ return newArray->asReturnedValue();
}
-void ArrayPrototype::method_unshift(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_unshift(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -605,52 +636,57 @@ void ArrayPrototype::method_unshift(const BuiltinFunction *, Scope &scope, CallD
if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len &&
instance->arrayData()->type != Heap::ArrayData::Custom) {
- instance->arrayData()->vtable()->push_front(instance, callData->args, callData->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);
+ bool ok;
if (exists)
- instance->putIndexed(k + callData->argc - 1, v);
+ ok = instance->putIndexed(k + callData->argc() - 1, v);
else
- instance->deleteIndexedProperty(k + callData->argc - 1);
+ ok = instance->deleteIndexedProperty(k + callData->argc() - 1);
+ if (!ok)
+ return scope.engine->throwTypeError();
+ }
+ for (int i = 0, ei = callData->argc(); i < ei; ++i) {
+ bool ok = instance->putIndexed(i, callData->args[i]);
+ if (!ok)
+ return scope.engine->throwTypeError();
}
- for (int i = 0; i < callData->argc; ++i)
- instance->putIndexed(i, callData->args[i]);
}
- uint newLen = len + callData->argc;
+ uint newLen = len + callData->argc();
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(newLen);
- else
- instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen)));
+ else {
+ if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))))
+ return scope.engine->throwTypeError();
+ }
- scope.result = Encode(newLen);
+ return Encode(newLen);
}
-void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_indexOf(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
uint len = instance->getLength();
- if (!len) {
- scope.result = Encode(-1);
- return;
- }
+ if (!len)
+ return Encode(-1);
ScopedValue searchValue(scope, callData->argument(0));
uint fromIndex = 0;
- if (callData->argc >= 2) {
+ if (callData->argc() >= 2) {
double f = callData->args[1].toInteger();
CHECK_EXCEPTION();
- if (f >= len) {
- scope.result = Encode(-1);
- return;
- }
+ if (f >= len)
+ return Encode(-1);
if (f < 0)
f = qMax(len + f, 0.);
fromIndex = (uint) f;
@@ -661,13 +697,10 @@ void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallD
for (uint k = fromIndex; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
- if (exists && RuntimeHelpers::strictEqual(v, searchValue)) {
- scope.result = Encode(k);
- return;
- }
+ if (exists && RuntimeHelpers::strictEqual(v, searchValue))
+ return Encode(k);
}
- scope.result = Encode(-1);
- return;
+ return Encode(-1);
}
ScopedValue value(scope);
@@ -679,14 +712,11 @@ void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallD
bool exists;
value = instance->getIndexed(i, &exists);
CHECK_EXCEPTION();
- if (exists && RuntimeHelpers::strictEqual(value, searchValue)) {
- scope.result = Encode(i);
- return;
- }
+ if (exists && RuntimeHelpers::strictEqual(value, searchValue))
+ return Encode(i);
}
} else if (!instance->arrayData()) {
- scope.result = Encode(-1);
- return;
+ return Encode(-1);
} else {
Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex);
Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>();
@@ -696,47 +726,42 @@ void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallD
while (idx < len) {
value = sa->data(idx);
CHECK_EXCEPTION();
- if (RuntimeHelpers::strictEqual(value, searchValue)) {
- scope.result = Encode(idx);
- return;
- }
+ if (RuntimeHelpers::strictEqual(value, searchValue))
+ return Encode(idx);
++idx;
}
}
- scope.result = Encode(-1);
+ return Encode(-1);
}
-void ArrayPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_lastIndexOf(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
uint len = instance->getLength();
- if (!len) {
- scope.result = Encode(-1);
- return;
- }
+ if (!len)
+ return Encode(-1);
ScopedValue searchValue(scope);
uint fromIndex = len;
- if (callData->argc >= 1)
+ if (callData->argc() >= 1)
searchValue = callData->argument(0);
else
searchValue = Primitive::undefinedValue();
- if (callData->argc >= 2) {
+ 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) {
- scope.result = Encode(-1);
- return;
- }
+ if (f < 0)
+ return Encode(-1);
}
fromIndex = (uint) f + 1;
}
@@ -747,16 +772,15 @@ void ArrayPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope, C
bool exists;
v = instance->getIndexed(k, &exists);
CHECK_EXCEPTION();
- if (exists && RuntimeHelpers::strictEqual(v, searchValue)) {
- scope.result = Encode(k);
- return;
- }
+ if (exists && RuntimeHelpers::strictEqual(v, searchValue))
+ return Encode(k);
}
- scope.result = Encode(-1);
+ return Encode(-1);
}
-void ArrayPrototype::method_every(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_every(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -767,10 +791,10 @@ void ArrayPrototype::method_every(const BuiltinFunction *, Scope &scope, CallDat
if (!callback)
THROW_TYPE_ERROR();
- ScopedCallData cData(scope, 3);
- cData->args[2] = instance;
- cData->thisObject = callData->argument(1);
+ ScopedValue r(scope);
ScopedValue v(scope);
+ JSCallData jsCallData(scope, 3);
+ *jsCallData->thisObject = callData->argument(1);
bool ok = true;
for (uint k = 0; ok && k < len; ++k) {
@@ -779,16 +803,18 @@ void ArrayPrototype::method_every(const BuiltinFunction *, Scope &scope, CallDat
if (!exists)
continue;
- cData->args[0] = v;
- cData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, cData);
- ok = scope.result.toBoolean();
+ jsCallData->args[0] = v;
+ jsCallData->args[1] = Primitive::fromDouble(k);
+ jsCallData->args[2] = instance;
+ r = callback->call(jsCallData);
+ ok = r->toBoolean();
}
- scope.result = Encode(ok);
+ return Encode(ok);
}
-void ArrayPrototype::method_some(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_some(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -799,10 +825,10 @@ void ArrayPrototype::method_some(const BuiltinFunction *, Scope &scope, CallData
if (!callback)
THROW_TYPE_ERROR();
- ScopedCallData cData(scope, 3);
- cData->thisObject = callData->argument(1);
- cData->args[2] = instance;
ScopedValue v(scope);
+ ScopedValue result(scope);
+ JSCallData jsCallData(scope, 3);
+ *jsCallData->thisObject = callData->argument(1);
for (uint k = 0; k < len; ++k) {
bool exists;
@@ -810,19 +836,19 @@ void ArrayPrototype::method_some(const BuiltinFunction *, Scope &scope, CallData
if (!exists)
continue;
- cData->args[0] = v;
- cData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, cData);
- if (scope.result.toBoolean()) {
- scope.result = Encode(true);
- return;
- }
+ jsCallData->args[0] = v;
+ jsCallData->args[1] = Primitive::fromDouble(k);
+ jsCallData->args[2] = instance;
+ result = callback->call(jsCallData);
+ if (result->toBoolean())
+ return Encode(true);
}
- scope.result = Encode(false);
+ return Encode(false);
}
-void ArrayPrototype::method_forEach(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_forEach(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -833,26 +859,27 @@ void ArrayPrototype::method_forEach(const BuiltinFunction *, Scope &scope, CallD
if (!callback)
THROW_TYPE_ERROR();
- ScopedCallData cData(scope, 3);
- cData->thisObject = callData->argument(1);
- cData->args[2] = instance;
-
ScopedValue v(scope);
+ JSCallData jsCallData(scope, 3);
+ *jsCallData->thisObject = callData->argument(1);
+
for (uint k = 0; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
if (!exists)
continue;
- cData->args[0] = v;
- cData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, cData);
+ jsCallData->args[0] = v;
+ jsCallData->args[1] = Primitive::fromDouble(k);
+ jsCallData->args[2] = instance;
+ callback->call(jsCallData);
}
RETURN_UNDEFINED();
}
-void ArrayPrototype::method_map(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_map(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -867,27 +894,29 @@ void ArrayPrototype::method_map(const BuiltinFunction *, Scope &scope, CallData
a->arrayReserve(len);
a->setArrayLengthUnchecked(len);
- ScopedCallData cData(scope, 3);
- cData->thisObject = callData->argument(1);
- cData->args[2] = instance;
-
ScopedValue v(scope);
+ ScopedValue mapped(scope);
+ JSCallData jsCallData(scope, 3);
+ *jsCallData->thisObject = callData->argument(1);
+
for (uint k = 0; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
if (!exists)
continue;
- cData->args[0] = v;
- cData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, cData);
- a->arraySet(k, scope.result);
+ jsCallData->args[0] = v;
+ jsCallData->args[1] = Primitive::fromDouble(k);
+ jsCallData->args[2] = instance;
+ mapped = callback->call(jsCallData);
+ a->arraySet(k, mapped);
}
- scope.result = a.asReturnedValue();
+ return a.asReturnedValue();
}
-void ArrayPrototype::method_filter(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_filter(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -901,11 +930,10 @@ void ArrayPrototype::method_filter(const BuiltinFunction *, Scope &scope, CallDa
ScopedArrayObject a(scope, scope.engine->newArrayObject());
a->arrayReserve(len);
- ScopedCallData cData(scope, 3);
- cData->thisObject = callData->argument(1);
- cData->args[2] = instance;
-
+ ScopedValue selected(scope);
ScopedValue v(scope);
+ JSCallData jsCallData(scope, 3);
+ *jsCallData->thisObject = callData->argument(1);
uint to = 0;
for (uint k = 0; k < len; ++k) {
@@ -914,19 +942,21 @@ void ArrayPrototype::method_filter(const BuiltinFunction *, Scope &scope, CallDa
if (!exists)
continue;
- cData->args[0] = v;
- cData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, cData);
- if (scope.result.toBoolean()) {
+ jsCallData->args[0] = v;
+ jsCallData->args[1] = Primitive::fromDouble(k);
+ jsCallData->args[2] = instance;
+ selected = callback->call(jsCallData);
+ if (selected->toBoolean()) {
a->arraySet(to, v);
++to;
}
}
- scope.result = a.asReturnedValue();
+ return a.asReturnedValue();
}
-void ArrayPrototype::method_reduce(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_reduce(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -938,42 +968,43 @@ void ArrayPrototype::method_reduce(const BuiltinFunction *, Scope &scope, CallDa
THROW_TYPE_ERROR();
uint k = 0;
+ ScopedValue acc(scope);
ScopedValue v(scope);
- if (callData->argc > 1) {
- scope.result = callData->argument(1);
+ if (callData->argc() > 1) {
+ acc = callData->argument(1);
} else {
bool kPresent = false;
while (k < len && !kPresent) {
v = instance->getIndexed(k, &kPresent);
if (kPresent)
- scope.result = v;
+ acc = v;
++k;
}
if (!kPresent)
THROW_TYPE_ERROR();
}
- ScopedCallData cData(scope, 4);
- cData->thisObject = Primitive::undefinedValue();
- cData->args[0] = scope.result;
- cData->args[3] = instance;
+ JSCallData jsCallData(scope, 4);
while (k < len) {
bool kPresent;
v = instance->getIndexed(k, &kPresent);
if (kPresent) {
- cData->args[0] = scope.result;
- cData->args[1] = v;
- cData->args[2] = Primitive::fromDouble(k);
- callback->call(scope, cData);
+ jsCallData->args[0] = acc;
+ jsCallData->args[1] = v;
+ jsCallData->args[2] = Primitive::fromDouble(k);
+ jsCallData->args[3] = instance;
+ acc = callback->call(jsCallData);
}
++k;
}
+ return acc->asReturnedValue();
}
-void ArrayPrototype::method_reduceRight(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ArrayPrototype::method_reduceRight(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
@@ -985,43 +1016,43 @@ void ArrayPrototype::method_reduceRight(const BuiltinFunction *, Scope &scope, C
THROW_TYPE_ERROR();
if (len == 0) {
- if (callData->argc == 1)
+ if (callData->argc() == 1)
THROW_TYPE_ERROR();
- scope.result = callData->argument(1);
- return;
+ return callData->argument(1);
}
uint k = len;
+ ScopedValue acc(scope);
ScopedValue v(scope);
- if (callData->argc > 1) {
- scope.result = callData->argument(1);
+ if (callData->argc() > 1) {
+ acc = callData->argument(1);
} else {
bool kPresent = false;
while (k > 0 && !kPresent) {
v = instance->getIndexed(k - 1, &kPresent);
if (kPresent)
- scope.result = v;
+ acc = v;
--k;
}
if (!kPresent)
THROW_TYPE_ERROR();
}
- ScopedCallData cData(scope, 4);
- cData->thisObject = Primitive::undefinedValue();
- cData->args[3] = instance;
+ JSCallData jsCallData(scope, 4);
+ *jsCallData->thisObject = Primitive::undefinedValue();
while (k > 0) {
bool kPresent;
v = instance->getIndexed(k - 1, &kPresent);
if (kPresent) {
- cData->args[0] = scope.result;
- cData->args[1] = v;
- cData->args[2] = Primitive::fromDouble(k - 1);
- callback->call(scope, cData);
+ jsCallData->args[0] = acc;
+ jsCallData->args[1] = v;
+ jsCallData->args[2] = Primitive::fromDouble(k - 1);
+ jsCallData->args[3] = instance;
+ acc = callback->call(jsCallData);
}
--k;
}
- scope.result = scope.result.asReturnedValue();
+ return acc->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index 689752433b..db12811cd7 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -70,38 +70,38 @@ struct ArrayCtor: FunctionObject
{
V4_OBJECT2(ArrayCtor, FunctionObject)
- static void construct(const Managed *m, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
struct ArrayPrototype: ArrayObject
{
void init(ExecutionEngine *engine, Object *ctor);
- 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);
+ static ReturnedValue method_isArray(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toLocaleString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_concat(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_find(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_findIndex(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_join(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_pop(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_push(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_reverse(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_shift(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_slice(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_sort(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_splice(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_unshift(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_indexOf(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_lastIndexOf(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_every(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_some(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_forEach(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_map(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_filter(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_reduce(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_reduceRight(const BuiltinFunction *, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index c8e9ebb2dd..2d89366e74 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -50,16 +50,16 @@ void Heap::BooleanCtor::init(QV4::ExecutionContext *scope)
Heap::FunctionObject::init(scope, QStringLiteral("Boolean"));
}
-void BooleanCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue BooleanCtor::callAsConstructor(const FunctionObject *that, const Value *argv, int argc)
{
- bool n = callData->argc ? callData->args[0].toBoolean() : false;
- scope.result = Encode(scope.engine->newBooleanObject(n));
+ bool n = argc ? argv[0].toBoolean() : false;
+ return Encode(that->engine()->newBooleanObject(n));
}
-void BooleanCtor::call(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue BooleanCtor::call(const FunctionObject *, const Value *, const Value *argv, int argc)
{
- bool value = callData->argc ? callData->args[0].toBoolean() : 0;
- scope.result = Encode(value);
+ bool value = argc ? argv[0].toBoolean() : 0;
+ return Encode(value);
}
void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -73,31 +73,30 @@ void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(engine->id_valueOf(), method_valueOf);
}
-void BooleanPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue BooleanPrototype::method_toString(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
bool result;
if (callData->thisObject.isBoolean()) {
result = callData->thisObject.booleanValue();
} else {
const BooleanObject *thisObject = callData->thisObject.as<BooleanObject>();
if (!thisObject)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
result = thisObject->value();
}
- scope.result = result ? scope.engine->id_true() : scope.engine->id_false();
+ return Encode(result ? v4->id_true() : v4->id_false());
}
-void BooleanPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue BooleanPrototype::method_valueOf(const BuiltinFunction *b, CallData *callData)
{
- if (callData->thisObject.isBoolean()) {
- scope.result = callData->thisObject.asReturnedValue();
- return;
- }
+ if (callData->thisObject.isBoolean())
+ return callData->thisObject.asReturnedValue();
const BooleanObject *thisObject = callData->thisObject.as<BooleanObject>();
if (!thisObject)
- THROW_TYPE_ERROR();
+ return b->engine()->throwTypeError();
- scope.result = Encode(thisObject->value());
+ return Encode(thisObject->value());
}
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index ca2cf7d17a..7a686e0d53 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 void construct(const Managed *, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
struct BooleanPrototype: BooleanObject
@@ -79,8 +79,8 @@ struct BooleanPrototype: BooleanObject
V4_PROTOTYPE(objectPrototype)
void init(ExecutionEngine *engine, Object *ctor);
- static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_valueOf(const BuiltinFunction *, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 6807c835b0..9d7cafabc8 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -48,59 +48,50 @@
#include "qv4errorobject_p.h"
#include "qv4string_p.h"
#include "qv4qmlcontext_p.h"
-#include "qv4profiling_p.h"
-#include <private/qqmljavascriptexpression_p.h>
using namespace QV4;
DEFINE_MANAGED_VTABLE(ExecutionContext);
-DEFINE_MANAGED_VTABLE(SimpleCallContext);
DEFINE_MANAGED_VTABLE(CallContext);
-DEFINE_MANAGED_VTABLE(WithContext);
DEFINE_MANAGED_VTABLE(CatchContext);
-DEFINE_MANAGED_VTABLE(GlobalContext);
-Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData)
+Heap::CallContext *ExecutionContext::newCallContext(Heap::ExecutionContext *outer, Function *function, CallData *callData)
{
- uint localsAndFormals = function->compiledFunction->nLocals + sizeof(CallData)/sizeof(Value) - 1 + qMax(static_cast<uint>(callData->argc), function->nFormals);
+ uint nFormals = qMax(static_cast<uint>(callData->argc()), function->nFormals);
+ uint localsAndFormals = function->compiledFunction->nLocals + nFormals;
size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * (localsAndFormals);
- ExecutionEngine *v4 = engine();
- Heap::CallContext *c = v4->memoryManager->allocManaged<CallContext>(requiredMemory);
- c->init(Heap::ExecutionContext::Type_CallContext);
+ ExecutionEngine *v4 = outer->internalClass->engine;
+ Heap::CallContext *c = v4->memoryManager->allocManaged<CallContext>(requiredMemory, function->internalClass);
+ c->init();
c->v4Function = function;
- c->strictMode = function->isStrict();
- c->outer.set(v4, this->d());
-
- c->compilationUnit = function->compilationUnit;
- c->lookups = function->compilationUnit->runtimeLookups;
- c->constantTable = function->compilationUnit->constants;
+ c->outer.set(v4, outer);
+ c->function.set(v4, static_cast<Heap::FunctionObject *>(callData->function.m()));
const CompiledData::Function *compiledFunction = function->compiledFunction;
uint nLocals = compiledFunction->nLocals;
c->locals.size = nLocals;
c->locals.alloc = localsAndFormals;
-#if QT_POINTER_SIZE == 8
- // memory allocated from the JS heap is 0 initialized, so skip the std::fill() below
+ // memory allocated from the JS heap is 0 initialized, so check if undefined is 0
Q_ASSERT(Primitive::undefinedValue().asReturnedValue() == 0);
-#else
- if (nLocals)
- std::fill(c->locals.values, c->locals.values + nLocals, Primitive::undefinedValue());
-#endif
- c->callData = reinterpret_cast<CallData *>(c->locals.values + nLocals);
- ::memcpy(c->callData, callData, sizeof(CallData) - sizeof(Value) + static_cast<uint>(callData->argc) * sizeof(Value));
- if (callData->argc < static_cast<int>(compiledFunction->nFormals))
- std::fill(c->callData->args + c->callData->argc, c->callData->args + compiledFunction->nFormals, Primitive::undefinedValue());
+ ::memcpy(c->locals.values + nLocals, &callData->args[0], nFormals * sizeof(Value));
+ c->nArgs = callData->argc();
return c;
}
-Heap::WithContext *ExecutionContext::newWithContext(Heap::Object *with)
+Heap::ExecutionContext *ExecutionContext::newWithContext(Heap::Object *with)
{
- return engine()->memoryManager->alloc<WithContext>(d(), with);
+ Heap::ExecutionContext *c = engine()->memoryManager->alloc<ExecutionContext>(Heap::ExecutionContext::Type_WithContext);
+ c->outer.set(engine(), d());
+ c->activation.set(engine(), with);
+
+ c->v4Function = d()->v4Function;
+
+ return c;
}
Heap::CatchContext *ExecutionContext::newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue)
@@ -120,25 +111,23 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
while (ctx) {
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CallContext:
- case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
if (!activation) {
+ Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
if (!c->activation)
c->activation.set(scope.engine, scope.engine->newObject());
activation = c->activation;
}
break;
- }
case Heap::ExecutionContext::Type_QmlContext: {
// this is ugly, as it overrides the inner callcontext, but has to stay as long
// as bindings still get their own callcontext
- Heap::QmlContext *qml = static_cast<Heap::QmlContext *>(ctx->d());
- activation = qml->qml;
+ activation = ctx->d()->activation;
break;
}
case Heap::ExecutionContext::Type_GlobalContext: {
+ Q_ASSERT(scope.engine->globalObject->d() == ctx->d()->activation);
if (!activation)
- activation = scope.engine->globalObject;
+ activation = ctx->d()->activation;
break;
}
default:
@@ -155,99 +144,47 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
activation->__defineOwnProperty__(scope.engine, name, desc, attrs);
}
-void Heap::GlobalContext::init(ExecutionEngine *eng)
-{
- Heap::ExecutionContext::init(Heap::ExecutionContext::Type_GlobalContext);
- global.set(eng, eng->globalObject->d());
-}
-
void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName,
const Value &exceptionValue)
{
Heap::ExecutionContext::init(Heap::ExecutionContext::Type_CatchContext);
outer.set(internalClass->engine, outerContext);
- strictMode = outer->strictMode;
- callData = outer->callData;
- lookups = outer->lookups;
- constantTable = outer->constantTable;
- compilationUnit = outer->compilationUnit;
+ v4Function = outer->v4Function;
this->exceptionVarName.set(internalClass->engine, exceptionVarName);
this->exceptionValue.set(internalClass->engine, exceptionValue);
}
-void Heap::WithContext::init(ExecutionContext *outerContext, Object *with)
-{
- Heap::ExecutionContext::init(Heap::ExecutionContext::Type_WithContext);
- outer.set(internalClass->engine, outerContext);
- callData = outer->callData;
- lookups = outer->lookups;
- constantTable = outer->constantTable;
- compilationUnit = outer->compilationUnit;
-
- withObject.set(internalClass->engine, with);
-}
-
-Identifier * const *SimpleCallContext::formals() const
-{
- return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() : 0;
-}
-
-unsigned int SimpleCallContext::formalCount() const
-{
- return d()->v4Function ? d()->v4Function->nFormals : 0;
-}
-
-Identifier * const *SimpleCallContext::variables() const
-{
- return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() + d()->v4Function->nFormals : 0;
-}
-
-unsigned int SimpleCallContext::variableCount() const
-{
- return d()->v4Function ? d()->v4Function->compiledFunction->nLocals : 0;
-}
-
-
-
bool ExecutionContext::deleteProperty(String *name)
{
name->makeIdentifier();
Identifier *id = name->identifier();
- Scope scope(this);
- ScopedContext ctx(scope, this);
- for (; ctx; ctx = ctx->d()->outer) {
- switch (ctx->d()->type) {
+ Heap::ExecutionContext *ctx = d();
+ for (; ctx; ctx = ctx->outer) {
+ switch (ctx->type) {
case Heap::ExecutionContext::Type_CatchContext: {
- Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
+ Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx);
if (c->exceptionVarName->isEqualTo(name->d()))
return false;
break;
}
- case Heap::ExecutionContext::Type_WithContext: {
- ScopedObject withObject(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
- if (withObject->hasProperty(name))
- return withObject->deleteProperty(name);
- break;
- }
- case Heap::ExecutionContext::Type_GlobalContext: {
- ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global);
- if (global->hasProperty(name))
- return global->deleteProperty(name);
- break;
- }
- case Heap::ExecutionContext::Type_CallContext:
- Q_FALLTHROUGH();
- case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
- uint index = c->v4Function->internalClass->find(id);
+ case Heap::ExecutionContext::Type_CallContext: {
+ Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
+ uint index = c->internalClass->find(id);
if (index < UINT_MAX)
// ### throw in strict mode?
return false;
- ScopedObject qml(scope, c->activation);
- if (qml && qml->hasProperty(name))
- return qml->deleteProperty(name);
+ Q_FALLTHROUGH();
+ }
+ case Heap::ExecutionContext::Type_WithContext:
+ case Heap::ExecutionContext::Type_GlobalContext: {
+ if (ctx->activation) {
+ Scope scope(this);
+ ScopedObject object(scope, ctx->activation);
+ if (object && object->hasProperty(name))
+ return object->deleteProperty(name);
+ }
break;
}
case Heap::ExecutionContext::Type_QmlContext:
@@ -256,291 +193,164 @@ bool ExecutionContext::deleteProperty(String *name)
}
}
- if (d()->strictMode)
- engine()->throwSyntaxError(QStringLiteral("Can't delete property %1").arg(name->toQString()));
- return true;
+ return !d()->v4Function->isStrict();
}
-// Do a standard call with this execution context as the outer scope
-void ExecutionContext::call(Scope &scope, CallData *callData, Function *function, const FunctionObject *f)
-{
- ExecutionContextSaver ctxSaver(scope);
-
- Scoped<CallContext> ctx(scope, newCallContext(function, callData));
- if (f)
- ctx->d()->function.set(scope.engine, f->d());
- scope.engine->pushContext(ctx);
-
- scope.result = Q_V4_PROFILE(scope.engine, function);
-
- if (function->hasQmlDependencies)
- QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope);
-}
-
-// Do a simple, fast call with this execution context as the outer scope
-void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Function *function)
-{
- Q_ASSERT(function->canUseSimpleFunction());
-
- ExecutionContextSaver ctxSaver(scope);
-
- SimpleCallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext();
-
- ctx->strictMode = function->isStrict();
- ctx->callData = callData;
- ctx->v4Function = function;
- ctx->compilationUnit = function->compilationUnit;
- ctx->lookups = function->compilationUnit->runtimeLookups;
- ctx->constantTable = function->compilationUnit->constants;
- ctx->outer.set(scope.engine, this->d());
- for (int i = callData->argc; i < (int)function->nFormals; ++i)
- callData->args[i] = Encode::undefined();
-
- scope.engine->pushContext(ctx);
- Q_ASSERT(scope.engine->current == ctx);
-
- scope.result = Q_V4_PROFILE(scope.engine, function);
-
- if (function->hasQmlDependencies)
- QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope);
- scope.engine->memoryManager->freeSimpleCallContext();
-}
-
-void ExecutionContext::setProperty(String *name, const Value &value)
+ExecutionContext::Error ExecutionContext::setProperty(String *name, const Value &value)
{
name->makeIdentifier();
Identifier *id = name->identifier();
- Scope scope(this);
- ScopedContext ctx(scope, this);
- ScopedObject activation(scope);
+ QV4::ExecutionEngine *v4 = engine();
+ Heap::ExecutionContext *ctx = d();
- for (; ctx; ctx = ctx->d()->outer) {
- activation = (Object *)0;
- switch (ctx->d()->type) {
+ for (; ctx; ctx = ctx->outer) {
+ switch (ctx->type) {
case Heap::ExecutionContext::Type_CatchContext: {
- Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
+ Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx);
if (c->exceptionVarName->isEqualTo(name->d())) {
- c->exceptionValue.set(scope.engine, value);
- return;
+ c->exceptionValue.set(v4, value);
+ return NoError;
}
break;
}
case Heap::ExecutionContext::Type_WithContext: {
- ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
+ Scope scope(v4);
+ ScopedObject w(scope, ctx->activation);
if (w->hasProperty(name)) {
- w->put(name, value);
- return;
+ if (!w->put(name, value))
+ return TypeError;
+ return NoError;
}
break;
}
- case Heap::ExecutionContext::Type_GlobalContext: {
- activation = static_cast<Heap::GlobalContext *>(ctx->d())->global;
- break;
- }
- case Heap::ExecutionContext::Type_CallContext:
- case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
+ case Heap::ExecutionContext::Type_CallContext: {
+ Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
if (c->v4Function) {
- uint index = c->v4Function->internalClass->find(id);
+ uint index = c->internalClass->find(id);
if (index < UINT_MAX) {
- if (index < c->v4Function->nFormals) {
- c->callData->args[c->v4Function->nFormals - index - 1] = value;
- } else {
- Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext);
- index -= c->v4Function->nFormals;
- static_cast<Heap::CallContext *>(c)->locals.set(scope.engine, index, value);
- }
- return;
+ static_cast<Heap::CallContext *>(c)->locals.set(v4, index, value);
+ return NoError;
}
}
- activation = c->activation;
- break;
}
+ Q_FALLTHROUGH();
+ case Heap::ExecutionContext::Type_GlobalContext:
+ if (ctx->activation) {
+ uint member = ctx->activation->internalClass->find(id);
+ if (member < UINT_MAX) {
+ Scope scope(v4);
+ ScopedObject a(scope, ctx->activation);
+ if (!a->putValue(member, value))
+ return TypeError;
+ return NoError;
+ }
+ }
+ break;
case Heap::ExecutionContext::Type_QmlContext: {
- activation = static_cast<Heap::QmlContext *>(ctx->d())->qml;
- activation->put(name, value);
- return;
+ Scope scope(v4);
+ ScopedObject activation(scope, ctx->activation);
+ if (!activation->put(name, value))
+ return TypeError;
+ return NoError;
}
}
- if (activation) {
- uint member = activation->internalClass()->find(id);
- if (member < UINT_MAX) {
- activation->putValue(member, value);
- return;
- }
- }
}
- if (d()->strictMode || name->equals(engine()->id_this())) {
- ScopedValue n(scope, name->asReturnedValue());
- engine()->throwReferenceError(n);
- return;
- }
- engine()->globalObject->put(name, value);
+ return RangeError;
}
ReturnedValue ExecutionContext::getProperty(String *name)
{
- Scope scope(this);
- ScopedValue v(scope);
name->makeIdentifier();
- if (name->equals(engine()->id_this()))
- return thisObject().asReturnedValue();
-
- ScopedContext ctx(scope, this);
- for (; ctx; ctx = ctx->d()->outer) {
- switch (ctx->d()->type) {
+ Heap::ExecutionContext *ctx = d();
+ for (; ctx; ctx = ctx->outer) {
+ switch (ctx->type) {
case Heap::ExecutionContext::Type_CatchContext: {
- Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
+ Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx);
if (c->exceptionVarName->isEqualTo(name->d()))
return c->exceptionValue.asReturnedValue();
break;
}
- case Heap::ExecutionContext::Type_WithContext: {
- ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
- bool hasProperty = false;
- v = w->get(name, &hasProperty);
- if (hasProperty) {
- return v->asReturnedValue();
- }
- break;
- }
- case Heap::ExecutionContext::Type_GlobalContext: {
- ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global);
- bool hasProperty = false;
- v = global->get(name, &hasProperty);
- if (hasProperty)
- return v->asReturnedValue();
- break;
- }
- case Heap::ExecutionContext::Type_CallContext:
- Q_FALLTHROUGH();
- case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
-
- name->makeIdentifier();
+ case Heap::ExecutionContext::Type_CallContext: {
+ Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
Identifier *id = name->identifier();
- uint index = c->v4Function->internalClass->find(id);
- if (index < UINT_MAX) {
- if (index < c->v4Function->nFormals)
- return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
- if (c->type == Heap::ExecutionContext::Type_CallContext)
- return static_cast<Heap::CallContext *>(c)->locals[index - c->v4Function->nFormals].asReturnedValue();
- }
- ScopedObject activation(scope, c->activation);
- if (activation) {
+ uint index = c->internalClass->find(id);
+ if (index < UINT_MAX)
+ return c->locals[index].asReturnedValue();
+ Q_FALLTHROUGH();
+ }
+ case Heap::ExecutionContext::Type_WithContext:
+ case Heap::ExecutionContext::Type_GlobalContext:
+ case Heap::ExecutionContext::Type_QmlContext: {
+ if (ctx->activation) {
+ Scope scope(this);
+ ScopedObject activation(scope, ctx->activation);
bool hasProperty = false;
- v = activation->get(name, &hasProperty);
+ ReturnedValue v = activation->get(name, &hasProperty);
if (hasProperty)
- return v->asReturnedValue();
- }
-
- if (c->v4Function->isNamedExpression() && c->type == Heap::ExecutionContext::Type_CallContext) {
- if (name->equals(ScopedString(scope, c->v4Function->name())))
- if (auto func = static_cast<Heap::CallContext *>(c)->function)
- return func->asReturnedValue();
+ return v;
}
break;
}
- case Heap::ExecutionContext::Type_QmlContext: {
- ScopedObject qml(scope, static_cast<Heap::QmlContext *>(ctx->d())->qml);
- bool hasProperty = false;
- v = qml->get(name, &hasProperty);
- if (hasProperty)
- return v->asReturnedValue();
- break;
- }
}
}
- ScopedValue n(scope, name);
- return engine()->throwReferenceError(n);
+ return engine()->throwReferenceError(*name);
}
ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
{
- Scope scope(this);
- ScopedValue v(scope);
base->setM(0);
name->makeIdentifier();
- if (name->equals(engine()->id_this()))
- return thisObject().asReturnedValue();
-
- ScopedContext ctx(scope, this);
- for (; ctx; ctx = ctx->d()->outer) {
- switch (ctx->d()->type) {
+ Heap::ExecutionContext *ctx = d();
+ for (; ctx; ctx = ctx->outer) {
+ switch (ctx->type) {
case Heap::ExecutionContext::Type_CatchContext: {
- Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
+ Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx);
if (c->exceptionVarName->isEqualTo(name->d()))
return c->exceptionValue.asReturnedValue();
break;
}
- case Heap::ExecutionContext::Type_WithContext: {
- ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
- bool hasProperty = false;
- v = w->get(name, &hasProperty);
- if (hasProperty) {
- base->setM(w->d());
- return v->asReturnedValue();
- }
- break;
- }
- case Heap::ExecutionContext::Type_GlobalContext: {
- ScopedObject global(scope, static_cast<Heap::GlobalContext *>(ctx->d())->global);
- bool hasProperty = false;
- v = global->get(name, &hasProperty);
- if (hasProperty)
- return v->asReturnedValue();
- break;
- }
- case Heap::ExecutionContext::Type_CallContext:
- Q_FALLTHROUGH();
- case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
-
+ case Heap::ExecutionContext::Type_CallContext: {
+ Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
name->makeIdentifier();
Identifier *id = name->identifier();
- uint index = c->v4Function->internalClass->find(id);
- if (index < UINT_MAX) {
- if (index < c->v4Function->nFormals)
- return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
- if (c->type == Heap::ExecutionContext::Type_CallContext)
- return static_cast<Heap::CallContext *>(c)->locals[index - c->v4Function->nFormals].asReturnedValue();
- }
- ScopedObject activation(scope, c->activation);
- if (activation) {
+ uint index = c->internalClass->find(id);
+ if (index < UINT_MAX)
+ return c->locals[index].asReturnedValue();
+ Q_FALLTHROUGH();
+ }
+ case Heap::ExecutionContext::Type_GlobalContext: {
+ if (ctx->activation) {
+ Scope scope(this);
+ ScopedObject activation(scope, ctx->activation);
bool hasProperty = false;
- v = activation->get(name, &hasProperty);
+ ReturnedValue v = activation->get(name, &hasProperty);
if (hasProperty)
- return v->asReturnedValue();
- }
-
- if (c->v4Function->isNamedExpression() && c->type == Heap::ExecutionContext::Type_CallContext) {
- if (name->equals(ScopedString(scope, c->v4Function->name())))
- if (auto func = static_cast<Heap::CallContext *>(c)->function)
- return func->asReturnedValue();
+ return v;
}
break;
}
+ case Heap::ExecutionContext::Type_WithContext:
case Heap::ExecutionContext::Type_QmlContext: {
- ScopedObject qml(scope, static_cast<Heap::QmlContext *>(ctx->d())->qml);
+ Scope scope(this);
+ ScopedObject o(scope, ctx->activation);
bool hasProperty = false;
- v = qml->get(name, &hasProperty);
+ ReturnedValue v = o->get(name, &hasProperty);
if (hasProperty) {
- base->setM(qml->d());
- return v->asReturnedValue();
+ base->setM(o->d());
+ return v;
}
break;
}
}
}
- ScopedValue n(scope, name);
- return engine()->throwReferenceError(n);
+ return engine()->throwReferenceError(*name);
}
Function *ExecutionContext::getFunction() const
@@ -548,9 +358,10 @@ Function *ExecutionContext::getFunction() const
Scope scope(engine());
ScopedContext it(scope, this->d());
for (; it; it = it->d()->outer) {
- if (const SimpleCallContext *callCtx = it->asSimpleCallContext())
+ if (const CallContext *callCtx = it->asCallContext())
return callCtx->d()->v4Function;
- else if (it->asCatchContext() || it->asWithContext())
+ else if (it->d()->type == Heap::ExecutionContext::Type_CatchContext ||
+ it->d()->type == Heap::ExecutionContext::Type_WithContext)
continue; // look in the parent context for a FunctionObject
else
break;
@@ -558,3 +369,9 @@ Function *ExecutionContext::getFunction() const
return 0;
}
+
+
+void Heap::CallContext::setArg(uint index, Value v)
+{
+ locals.set(internalClass->engine, locals.size + index, v);
+}
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index a854c324d0..7ed3320f8a 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -68,48 +68,57 @@ struct Function;
struct Function;
struct Identifier;
struct CallContext;
-struct SimpleCallContext;
struct CatchContext;
-struct WithContext;
struct QmlContext;
struct QQmlContextWrapper;
-// Attention: Make sure that this structure is the same size on 32-bit and 64-bit
-// architecture or you'll have to change the JIT code.
struct CallData
{
- // below is to be compatible with Value. Initialize tag to 0
-#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN
- uint tag;
-#endif
- int argc;
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- uint tag;
-#endif
+ enum Offsets {
+ Function = 0,
+ Context = 1,
+ Accumulator = 2,
+ This = 3,
+ Argc = 4
+ };
+
+ Value function;
+ Value context;
+ Value accumulator;
+ Value thisObject;
+ Value _argc;
+
+ int argc() const {
+ Q_ASSERT(_argc.isInteger());
+ return _argc.int_32();
+ }
+
+ void setArgc(int argc) {
+ Q_ASSERT(argc >= 0);
+ _argc.setInt_32(argc);
+ }
+
inline ReturnedValue argument(int i) const {
- return i < argc ? args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
+ return i < argc() ? args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
}
- Value thisObject;
Value args[1];
+
+ static Q_DECL_CONSTEXPR int HeaderSize() { return offsetof(CallData, args) / sizeof(QV4::Value); }
};
Q_STATIC_ASSERT(std::is_standard_layout<CallData>::value);
-Q_STATIC_ASSERT(offsetof(CallData, thisObject) == 8);
-Q_STATIC_ASSERT(offsetof(CallData, args) == 16);
+Q_STATIC_ASSERT(offsetof(CallData, thisObject) == CallData::This*sizeof(Value));
+Q_STATIC_ASSERT(offsetof(CallData, args) == 5*sizeof(Value));
namespace Heap {
struct QmlContext;
#define ExecutionContextMembers(class, Member) \
- Member(class, NoMark, CallData *, callData) \
Member(class, Pointer, ExecutionContext *, outer) \
- Member(class, NoMark, Lookup *, lookups) \
- Member(class, NoMark, const QV4::Value *, constantTable) \
- Member(class, NoMark, CompiledData::CompilationUnitBase *, compilationUnit) \
- Member(class, NoMark, int, lineNumber) // as member of non-pointer size this has to come last to preserve the ability to
- // translate offsetof of it between 64-bit and 32-bit.
+ Member(class, Pointer, Object *, activation) \
+ Member(class, NoMark, QV4::Function *, v4Function) \
DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
DECLARE_MARK_TABLE(ExecutionContext);
@@ -119,8 +128,7 @@ DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
Type_CatchContext = 0x2,
Type_WithContext = 0x3,
Type_QmlContext = 0x4,
- Type_SimpleCallContext = 0x5,
- Type_CallContext = 0x6
+ Type_CallContext = 0x5
};
void init(ContextType t)
@@ -128,83 +136,54 @@ DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
Base::init();
type = t;
- lineNumber = -1;
}
- quint8 type;
- bool strictMode : 8;
+ quint32 type : 8;
+ quint32 nArgs : 24;
#if QT_POINTER_SIZE == 8
- quint8 padding_[6];
-#else
- quint8 padding_[2];
+ quint8 padding_[4];
#endif
};
V4_ASSERT_IS_TRIVIAL(ExecutionContext)
Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionContextData) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, callData) == 0);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, lookups) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, constantTable) == offsetof(ExecutionContextData, lookups) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, compilationUnit) == offsetof(ExecutionContextData, constantTable) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, lineNumber) == offsetof(ExecutionContextData, compilationUnit) + QT_POINTER_SIZE);
-
-#define SimpleCallContextMembers(class, Member) \
- Member(class, Pointer, Object *, activation) \
- Member(class, NoMark, QV4::Function *, v4Function)
-
-DECLARE_HEAP_OBJECT(SimpleCallContext, ExecutionContext) {
- DECLARE_MARK_TABLE(SimpleCallContext);
-
- void init(ContextType t = Type_SimpleCallContext)
- {
- ExecutionContext::init(t);
- }
-
- inline unsigned int formalParameterCount() const;
-
-};
-V4_ASSERT_IS_TRIVIAL(SimpleCallContext)
-Q_STATIC_ASSERT(std::is_standard_layout<SimpleCallContextData>::value);
-Q_STATIC_ASSERT(offsetof(SimpleCallContextData, activation) == 0);
-Q_STATIC_ASSERT(offsetof(SimpleCallContextData, v4Function) == offsetof(SimpleCallContextData, activation) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(sizeof(SimpleCallContextData) == 2 * QT_POINTER_SIZE);
-Q_STATIC_ASSERT(sizeof(SimpleCallContext) == sizeof(ExecutionContext) + sizeof(SimpleCallContextData));
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == 0);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, activation) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, v4Function) == offsetof(ExecutionContextData, activation) + QT_POINTER_SIZE);
-#if QT_POINTER_SIZE == 8
-#define CallContextMembers(class, Member) \
- Member(class, Pointer, FunctionObject *, function) \
- Member(class, ValueArray, ValueArray, locals)
-#else
#define CallContextMembers(class, Member) \
Member(class, Pointer, FunctionObject *, function) \
- Member(class, NoMark, void *, padding) \
Member(class, ValueArray, ValueArray, locals)
-#endif
-DECLARE_HEAP_OBJECT(CallContext, SimpleCallContext) {
+DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) {
DECLARE_MARK_TABLE(CallContext);
- using SimpleCallContext::formalParameterCount;
-};
-
-Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value);
-Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0);
-// IMPORTANT: we cannot do offsetof(CallContextData, locals) in the JIT as the offset does not scale with
-// the pointer size. On 32-bit ARM the offset of the ValueArray is aligned to 8 bytes, on 32-bit x86 for
-// example it is not. Therefore we have a padding in place and always have a distance of 8 bytes.
-Q_STATIC_ASSERT(offsetof(CallContextData, locals) == offsetof(CallContextData, function) + 8);
-
-#define GlobalContextMembers(class, Member) \
- Member(class, Pointer, Object *, global)
+ void init()
+ {
+ ExecutionContext::init(Type_CallContext);
+ }
-DECLARE_HEAP_OBJECT(GlobalContext, ExecutionContext) {
- DECLARE_MARK_TABLE(GlobalContext);
+ int argc() const {
+ return static_cast<int>(nArgs);
+ }
+ const Value *args() const {
+ return locals.data() + locals.size;
+ }
+ void setArg(uint index, Value v);
- void init(ExecutionEngine *engine);
+ inline unsigned int formalParameterCount() const;
};
-V4_ASSERT_IS_TRIVIAL(GlobalContext)
+V4_ASSERT_IS_TRIVIAL(CallContext)
+Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value);
+Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0);
+//### The following size check fails on Win8. With the ValueArray at the end of the
+// CallContextMembers, it doesn't look very useful.
+//#if defined(Q_PROCESSOR_ARM_32) && !defined(Q_OS_IOS)
+//Q_STATIC_ASSERT(sizeof(CallContext) == sizeof(ExecutionContext) + sizeof(CallContextData) + QT_POINTER_SIZE);
+//#else
+//Q_STATIC_ASSERT(sizeof(CallContext) == sizeof(ExecutionContext) + sizeof(CallContextData));
+//#endif
#define CatchContextMembers(class, Member) \
Member(class, Pointer, String *, exceptionVarName) \
@@ -217,16 +196,6 @@ DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) {
};
V4_ASSERT_IS_TRIVIAL(CatchContext)
-#define WithContextMembers(class, Member) \
- Member(class, Pointer, Object *, withObject)
-
-DECLARE_HEAP_OBJECT(WithContext, ExecutionContext) {
- DECLARE_MARK_TABLE(WithContext);
-
- void init(ExecutionContext *outerContext, Object *with);
-};
-V4_ASSERT_IS_TRIVIAL(WithContext)
-
}
struct Q_QML_EXPORT ExecutionContext : public Managed
@@ -239,68 +208,42 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
Q_MANAGED_TYPE(ExecutionContext)
V4_INTERNALCLASS(ExecutionContext)
- Heap::CallContext *newCallContext(Function *f, CallData *callData);
- Heap::WithContext *newWithContext(Heap::Object *with);
+ static Heap::CallContext *newCallContext(Heap::ExecutionContext *outer, Function *function, CallData *callData);
+ Heap::ExecutionContext *newWithContext(Heap::Object *with);
Heap::CatchContext *newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue);
void createMutableBinding(String *name, bool deletable);
- void setProperty(String *name, const Value &value);
+ enum Error {
+ NoError,
+ TypeError,
+ RangeError
+ };
+
+ Error setProperty(String *name, const Value &value);
+
ReturnedValue getProperty(String *name);
ReturnedValue getPropertyAndBase(String *name, Value *base);
bool deleteProperty(String *name);
- inline SimpleCallContext *asSimpleCallContext();
- inline const SimpleCallContext *asSimpleCallContext() const;
- inline const CatchContext *asCatchContext() const;
- inline const WithContext *asWithContext() const;
+ inline CallContext *asCallContext();
+ inline const CallContext *asCallContext() const;
Function *getFunction() const;
- Value &thisObject() const {
- return d()->callData->thisObject;
- }
- int argc() const {
- return d()->callData->argc;
- }
- const Value *args() const {
- return d()->callData->args;
- }
- ReturnedValue argument(int i) const {
- return d()->callData->argument(i);
- }
-
- void call(Scope &scope, CallData *callData, QV4::Function *function, const QV4::FunctionObject *f = 0);
- void simpleCall(Scope &scope, CallData *callData, QV4::Function *function);
};
-struct Q_QML_EXPORT SimpleCallContext : public ExecutionContext
+struct Q_QML_EXPORT CallContext : public ExecutionContext
{
- V4_MANAGED(SimpleCallContext, ExecutionContext)
- V4_INTERNALCLASS(SimpleCallContext)
-
- // formals are in reverse order
- Identifier * const *formals() const;
- unsigned int formalCount() const;
- Identifier * const *variables() const;
- unsigned int variableCount() const;
-
- inline ReturnedValue argument(int i) const;
-};
-
-inline ReturnedValue SimpleCallContext::argument(int i) const {
- return i < argc() ? args()[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
-}
-
-struct Q_QML_EXPORT CallContext : public SimpleCallContext
-{
- V4_MANAGED(CallContext, SimpleCallContext)
-};
-
-struct GlobalContext : public ExecutionContext
-{
- V4_MANAGED(GlobalContext, ExecutionContext)
+ V4_MANAGED(CallContext, ExecutionContext)
+ V4_INTERNALCLASS(CallContext)
+ int argc() const {
+ return d()->argc();
+ }
+ const Value *args() const {
+ return d()->args();
+ }
};
struct CatchContext : public ExecutionContext
@@ -308,29 +251,14 @@ struct CatchContext : public ExecutionContext
V4_MANAGED(CatchContext, ExecutionContext)
};
-struct WithContext : public ExecutionContext
-{
- V4_MANAGED(WithContext, ExecutionContext)
-};
-
-inline SimpleCallContext *ExecutionContext::asSimpleCallContext()
-{
- return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<SimpleCallContext *>(this) : 0;
-}
-
-inline const SimpleCallContext *ExecutionContext::asSimpleCallContext() const
-{
- return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<const SimpleCallContext *>(this) : 0;
-}
-
-inline const CatchContext *ExecutionContext::asCatchContext() const
+inline CallContext *ExecutionContext::asCallContext()
{
- return d()->type == Heap::ExecutionContext::Type_CatchContext ? static_cast<const CatchContext *>(this) : 0;
+ return d()->type == Heap::ExecutionContext::Type_CallContext ? static_cast<CallContext *>(this) : 0;
}
-inline const WithContext *ExecutionContext::asWithContext() const
+inline const CallContext *ExecutionContext::asCallContext() const
{
- return d()->type == Heap::ExecutionContext::Type_WithContext ? static_cast<const WithContext *>(this) : 0;
+ return d()->type == Heap::ExecutionContext::Type_CallContext ? static_cast<const CallContext *>(this) : 0;
}
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index f1405e08ee..815f6ed991 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -54,34 +54,31 @@ void Heap::DataViewCtor::init(QV4::ExecutionContext *scope)
Heap::FunctionObject::init(scope, QStringLiteral("DataView"));
}
-void DataViewCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue DataViewCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- Scoped<ArrayBuffer> buffer(scope, callData->argument(0));
- if (!buffer) {
- scope.result = scope.engine->throwTypeError();
- return;
- }
+ Scope scope(f->engine());
+ Scoped<ArrayBuffer> buffer(scope, argc ? argv[0] : Primitive::undefinedValue());
+ if (!buffer)
+ return scope.engine->throwTypeError();
- double bo = callData->argc > 1 ? callData->args[1].toNumber() : 0;
+ double bo = argc > 1 ? argv[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();
+ double bl = argc < 3 || argv[2].isUndefined() ? (bufferLength - bo) : argv[2].toNumber();
uint byteLength = (uint)bl;
- if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength) {
- scope.result = scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
- return;
- }
+ if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength)
+ return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>());
a->d()->buffer.set(scope.engine, buffer->d());
a->d()->byteLength = byteLength;
a->d()->byteOffset = byteOffset;
- scope.result = a.asReturnedValue();
+ return a.asReturnedValue();
}
-void DataViewCtor::call(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue DataViewCtor::call(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
- construct(that, scope, callData);
+ return callAsConstructor(f, argv, argc);
}
void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -122,84 +119,84 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0);
}
-void DataViewPrototype::method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DataViewPrototype::method_get_buffer(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DataView> v(scope, callData->thisObject);
+ DataView *v = callData->thisObject.as<DataView>();
if (!v)
- THROW_TYPE_ERROR();
+ return b->engine()->throwTypeError();
- scope.result = v->d()->buffer;
+ return v->d()->buffer->asReturnedValue();
}
-void DataViewPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DataViewPrototype::method_get_byteLength(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DataView> v(scope, callData->thisObject);
+ DataView *v = callData->thisObject.as<DataView>();
if (!v)
- THROW_TYPE_ERROR();
+ return b->engine()->throwTypeError();
- scope.result = Encode(v->d()->byteLength);
+ return Encode(v->d()->byteLength);
}
-void DataViewPrototype::method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DataViewPrototype::method_get_byteOffset(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DataView> v(scope, callData->thisObject);
+ DataView *v = callData->thisObject.as<DataView>();
if (!v)
- THROW_TYPE_ERROR();
+ return b->engine()->throwTypeError();
- scope.result = Encode(v->d()->byteOffset);
+ return Encode(v->d()->byteOffset);
}
template <typename T>
-void DataViewPrototype::method_getChar(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DataViewPrototype::method_getChar(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DataView> v(scope, callData->thisObject);
- if (!v || callData->argc < 1)
- THROW_TYPE_ERROR();
+ DataView *v = callData->thisObject.as<DataView>();
+ if (!v || callData->argc() < 1)
+ return b->engine()->throwTypeError();
double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- THROW_TYPE_ERROR();
+ return b->engine()->throwTypeError();
idx += v->d()->byteOffset;
T t = T(v->d()->buffer->data->data()[idx]);
- scope.result = Encode((int)t);
+ return Encode((int)t);
}
template <typename T>
-void DataViewPrototype::method_get(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DataViewPrototype::method_get(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DataView> v(scope, callData->thisObject);
- if (!v || callData->argc < 1)
- THROW_TYPE_ERROR();
+ DataView *v = callData->thisObject.as<DataView>();
+ if (!v || callData->argc() < 1)
+ return b->engine()->throwTypeError();
double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- THROW_TYPE_ERROR();
+ return b->engine()->throwTypeError();
idx += v->d()->byteOffset;
- bool littleEndian = callData->argc < 2 ? false : callData->args[1].toBoolean();
+ bool littleEndian = callData->argc() < 2 ? false : callData->args[1].toBoolean();
T t = littleEndian
? qFromLittleEndian<T>((uchar *)v->d()->buffer->data->data() + idx)
: qFromBigEndian<T>((uchar *)v->d()->buffer->data->data() + idx);
- scope.result = Encode(t);
+ return Encode(t);
}
template <typename T>
-void DataViewPrototype::method_getFloat(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DataViewPrototype::method_getFloat(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DataView> v(scope, callData->thisObject);
- if (!v || callData->argc < 1)
- THROW_TYPE_ERROR();
+ DataView *v = callData->thisObject.as<DataView>();
+ if (!v || callData->argc() < 1)
+ return b->engine()->throwTypeError();
double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- THROW_TYPE_ERROR();
+ return b->engine()->throwTypeError();
idx += v->d()->byteOffset;
- bool littleEndian = callData->argc < 2 ? false : callData->args[1].toBoolean();
+ bool littleEndian = callData->argc() < 2 ? false : callData->args[1].toBoolean();
if (sizeof(T) == 4) {
// float
@@ -210,7 +207,7 @@ void DataViewPrototype::method_getFloat(const BuiltinFunction *, Scope &scope, C
u.i = littleEndian
? qFromLittleEndian<uint>((uchar *)v->d()->buffer->data->data() + idx)
: qFromBigEndian<uint>((uchar *)v->d()->buffer->data->data() + idx);
- scope.result = Encode(u.f);
+ return Encode(u.f);
} else {
Q_ASSERT(sizeof(T) == 8);
union {
@@ -220,43 +217,43 @@ void DataViewPrototype::method_getFloat(const BuiltinFunction *, Scope &scope, C
u.i = littleEndian
? qFromLittleEndian<quint64>((uchar *)v->d()->buffer->data->data() + idx)
: qFromBigEndian<quint64>((uchar *)v->d()->buffer->data->data() + idx);
- scope.result = Encode(u.d);
+ return Encode(u.d);
}
}
template <typename T>
-void DataViewPrototype::method_setChar(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DataViewPrototype::method_setChar(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DataView> v(scope, callData->thisObject);
- if (!v || callData->argc < 1)
- THROW_TYPE_ERROR();
+ DataView *v = callData->thisObject.as<DataView>();
+ if (!v || callData->argc() < 1)
+ return b->engine()->throwTypeError();
double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- THROW_TYPE_ERROR();
+ return b->engine()->throwTypeError();
idx += v->d()->byteOffset;
- int val = callData->argc >= 2 ? callData->args[1].toInt32() : 0;
+ int val = callData->argc() >= 2 ? callData->args[1].toInt32() : 0;
v->d()->buffer->data->data()[idx] = (char)val;
RETURN_UNDEFINED();
}
template <typename T>
-void DataViewPrototype::method_set(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DataViewPrototype::method_set(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DataView> v(scope, callData->thisObject);
- if (!v || callData->argc < 1)
- THROW_TYPE_ERROR();
+ DataView *v = callData->thisObject.as<DataView>();
+ if (!v || callData->argc() < 1)
+ return b->engine()->throwTypeError();
double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- THROW_TYPE_ERROR();
+ return b->engine()->throwTypeError();
idx += v->d()->byteOffset;
- int val = callData->argc >= 2 ? callData->args[1].toInt32() : 0;
+ int val = callData->argc() >= 2 ? callData->args[1].toInt32() : 0;
- bool littleEndian = callData->argc < 3 ? false : callData->args[2].toBoolean();
+ bool littleEndian = callData->argc() < 3 ? false : callData->args[2].toBoolean();
if (littleEndian)
qToLittleEndian<T>(val, (uchar *)v->d()->buffer->data->data() + idx);
@@ -267,19 +264,19 @@ void DataViewPrototype::method_set(const BuiltinFunction *, Scope &scope, CallDa
}
template <typename T>
-void DataViewPrototype::method_setFloat(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DataViewPrototype::method_setFloat(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DataView> v(scope, callData->thisObject);
- if (!v || callData->argc < 1)
- THROW_TYPE_ERROR();
+ DataView *v = callData->thisObject.as<DataView>();
+ if (!v || callData->argc() < 1)
+ return b->engine()->throwTypeError();
double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- THROW_TYPE_ERROR();
+ return b->engine()->throwTypeError();
idx += v->d()->byteOffset;
- double val = callData->argc >= 2 ? callData->args[1].toNumber() : qt_qnan();
- bool littleEndian = callData->argc < 3 ? false : callData->args[2].toBoolean();
+ double val = callData->argc() >= 2 ? callData->args[1].toNumber() : qt_qnan();
+ bool littleEndian = callData->argc() < 3 ? false : callData->args[2].toBoolean();
if (sizeof(T) == 4) {
// float
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 5c50df4655..30fc7e993b 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -79,8 +79,8 @@ struct DataViewCtor: FunctionObject
{
V4_OBJECT2(DataViewCtor, FunctionObject)
- static void construct(const Managed *m, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
struct DataView : Object
@@ -93,21 +93,21 @@ struct DataViewPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static void method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_get_buffer(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_get_byteLength(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_get_byteOffset(const BuiltinFunction *, CallData *callData);
template <typename T>
- static void method_getChar(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_getChar(const BuiltinFunction *, CallData *callData);
template <typename T>
- static void method_get(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_get(const BuiltinFunction *, CallData *callData);
template <typename T>
- static void method_getFloat(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_getFloat(const BuiltinFunction *, CallData *callData);
template <typename T>
- static void method_setChar(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_setChar(const BuiltinFunction *, CallData *callData);
template <typename T>
- static void method_set(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_set(const BuiltinFunction *, CallData *callData);
template <typename T>
- static void method_setFloat(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_setFloat(const BuiltinFunction *, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index c56d007028..8b6325badd 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -43,6 +43,7 @@
#include "qv4scopedvalue_p.h"
#include "qv4runtime_p.h"
#include "qv4string_p.h"
+#include "qv4jscall_p.h"
#include <QtCore/QDebug>
#include <QtCore/QDateTime>
@@ -677,15 +678,16 @@ void Heap::DateCtor::init(QV4::ExecutionContext *scope)
Heap::FunctionObject::init(scope, QStringLiteral("Date"));
}
-void DateCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue DateCtor::callAsConstructor(const FunctionObject *that, const Value *argv, int argc)
{
double t = 0;
- if (callData->argc == 0)
+ if (argc == 0)
t = currentTime();
- else if (callData->argc == 1) {
- ScopedValue arg(scope, callData->args[0]);
+ else if (argc == 1) {
+ Scope scope(that->engine());
+ ScopedValue arg(scope, argv[0]);
if (DateObject *d = arg->as<DateObject>()) {
t = d->date();
} else {
@@ -699,26 +701,26 @@ void DateCtor::construct(const Managed *, Scope &scope, CallData *callData)
}
else { // d.argc > 1
- double year = callData->args[0].toNumber();
- double month = callData->args[1].toNumber();
- double day = callData->argc >= 3 ? callData->args[2].toNumber() : 1;
- double hours = callData->argc >= 4 ? callData->args[3].toNumber() : 0;
- double mins = callData->argc >= 5 ? callData->args[4].toNumber() : 0;
- double secs = callData->argc >= 6 ? callData->args[5].toNumber() : 0;
- double ms = callData->argc >= 7 ? callData->args[6].toNumber() : 0;
+ double year = argv[0].toNumber();
+ double month = argv[1].toNumber();
+ double day = argc >= 3 ? argv[2].toNumber() : 1;
+ double hours = argc >= 4 ? argv[3].toNumber() : 0;
+ double mins = argc >= 5 ? argv[4].toNumber() : 0;
+ double secs = argc >= 6 ? argv[5].toNumber() : 0;
+ double ms = argc >= 7 ? argv[6].toNumber() : 0;
if (year >= 0 && year <= 99)
year += 1900;
t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms));
t = TimeClip(UTC(t));
}
- scope.result = Encode(scope.engine->newDateObject(Primitive::fromDouble(t)));
+ return Encode(that->engine()->newDateObject(Primitive::fromDouble(t)));
}
-void DateCtor::call(const Managed *m, Scope &scope, CallData *)
+ReturnedValue DateCtor::call(const FunctionObject *m, const Value *, const Value *, int)
{
double t = currentTime();
- scope.result = static_cast<const DateCtor *>(m)->engine()->newString(ToString(t));
+ return m->engine()->newString(ToString(t))->asReturnedValue();
}
void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -795,27 +797,27 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1);
}
-double DatePrototype::getThisDate(Scope &scope, CallData *callData)
+double DatePrototype::getThisDate(ExecutionEngine *v4, CallData *callData)
{
if (DateObject *thisObject = callData->thisObject.as<DateObject>())
return thisObject->date();
else {
- scope.engine->throwTypeError();
+ v4->throwTypeError();
return 0;
}
}
-void DatePrototype::method_parse(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_parse(const BuiltinFunction *, CallData *callData)
{
- if (!callData->argc)
- scope.result = Encode(qt_qnan());
+ if (!callData->argc())
+ return Encode(qt_qnan());
else
- scope.result = Encode(ParseString(callData->args[0].toQString()));
+ return Encode(ParseString(callData->args[0].toQString()));
}
-void DatePrototype::method_UTC(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_UTC(const BuiltinFunction *, CallData *callData)
{
- const int numArgs = callData->argc;
+ const int numArgs = callData->argc();
if (numArgs >= 2) {
double year = callData->args[0].toNumber();
double month = callData->args[1].toNumber();
@@ -828,426 +830,488 @@ void DatePrototype::method_UTC(const BuiltinFunction *, Scope &scope, CallData *
year += 1900;
double t = MakeDate(MakeDay(year, month, day),
MakeTime(hours, mins, secs, ms));
- scope.result = Encode(TimeClip(t));
- return;
+ return Encode(TimeClip(t));
}
RETURN_UNDEFINED();
}
-void DatePrototype::method_now(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_now(const BuiltinFunction *, CallData *callData)
{
Q_UNUSED(callData);
- double t = currentTime();
- scope.result = Encode(t);
+ return Encode(currentTime());
}
-void DatePrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_toString(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
- scope.result = scope.engine->newString(ToString(t));
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
+ return Encode(v4->newString(ToString(t)));
}
-void DatePrototype::method_toDateString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_toDateString(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
- scope.result = scope.engine->newString(ToDateString(t));
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
+ return Encode(v4->newString(ToDateString(t)));
}
-void DatePrototype::method_toTimeString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_toTimeString(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
- scope.result = scope.engine->newString(ToTimeString(t));
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
+ return Encode(v4->newString(ToTimeString(t)));
}
-void DatePrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_toLocaleString(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
- scope.result = scope.engine->newString(ToLocaleString(t));
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
+ return Encode(v4->newString(ToLocaleString(t)));
}
-void DatePrototype::method_toLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_toLocaleDateString(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
- scope.result = scope.engine->newString(ToLocaleDateString(t));
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
+ return Encode(v4->newString(ToLocaleDateString(t)));
}
-void DatePrototype::method_toLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_toLocaleTimeString(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
- scope.result = scope.engine->newString(ToLocaleTimeString(t));
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
+ return Encode(v4->newString(ToLocaleTimeString(t)));
}
-void DatePrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_valueOf(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
- scope.result = Encode(t);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
+ return Encode(t);
}
-void DatePrototype::method_getTime(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getTime(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
- scope.result = Encode(t);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
+ return Encode(t);
}
-void DatePrototype::method_getYear(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getYear(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = YearFromTime(LocalTime(t)) - 1900;
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getFullYear(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = YearFromTime(LocalTime(t));
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getUTCFullYear(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = YearFromTime(t);
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getMonth(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = MonthFromTime(LocalTime(t));
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getUTCMonth(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = MonthFromTime(t);
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getDate(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getDate(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = DateFromTime(LocalTime(t));
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getUTCDate(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = DateFromTime(t);
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getDay(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getDay(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = WeekDay(LocalTime(t));
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getUTCDay(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getUTCDay(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = WeekDay(t);
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getHours(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getHours(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = HourFromTime(LocalTime(t));
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getUTCHours(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = HourFromTime(t);
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getMinutes(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = MinFromTime(LocalTime(t));
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getUTCMinutes(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = MinFromTime(t);
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getSeconds(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = SecFromTime(LocalTime(t));
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getUTCSeconds(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = SecFromTime(t);
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getMilliseconds(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = msFromTime(LocalTime(t));
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getUTCMilliseconds(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = msFromTime(t);
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_getTimezoneOffset(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_getTimezoneOffset(const BuiltinFunction *b, CallData *callData)
{
- double t = getThisDate(scope, callData);
+ ExecutionEngine *v4 = b->engine();
+ double t = getThisDate(v4, callData);
if (!std::isnan(t))
t = (t - LocalTime(t)) / msPerMinute;
- scope.result = Encode(t);
+ return Encode(t);
}
-void DatePrototype::method_setTime(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setTime(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DateObject> self(scope, callData->thisObject);
+ ExecutionEngine *v4 = b->engine();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
- double t = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- CHECK_EXCEPTION();
+ double t = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
self->setDate(TimeClip(t));
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setMilliseconds(const BuiltinFunction *b, CallData *callData)
{
- Scoped<DateObject> self(scope, callData->thisObject);
+ ExecutionEngine *v4 = b->engine();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = LocalTime(self->date());
- CHECK_EXCEPTION();
- double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double ms = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setUTCMilliseconds(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = self->date();
- CHECK_EXCEPTION();
- double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double ms = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setSeconds(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = LocalTime(self->date());
- CHECK_EXCEPTION();
- double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- CHECK_EXCEPTION();
- double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber();
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double sec = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double ms = (callData->argc() < 2) ? msFromTime(t) : callData->args[1].toNumber();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setUTCSeconds(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = self->date();
- double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber();
+ double sec = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ double ms = (callData->argc() < 2) ? msFromTime(t) : callData->args[1].toNumber();
t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setMinutes(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = LocalTime(self->date());
- CHECK_EXCEPTION();
- double min = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- CHECK_EXCEPTION();
- double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber();
- CHECK_EXCEPTION();
- double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber();
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double min = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double sec = (callData->argc() < 2) ? SecFromTime(t) : callData->args[1].toNumber();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double ms = (callData->argc() < 3) ? msFromTime(t) : callData->args[2].toNumber();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setUTCMinutes(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = self->date();
- double min = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber();
- double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber();
+ double min = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ double sec = (callData->argc() < 2) ? SecFromTime(t) : callData->args[1].toNumber();
+ double ms = (callData->argc() < 3) ? msFromTime(t) : callData->args[2].toNumber();
t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setHours(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setHours(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = LocalTime(self->date());
- CHECK_EXCEPTION();
- double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- CHECK_EXCEPTION();
- double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber();
- CHECK_EXCEPTION();
- double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber();
- CHECK_EXCEPTION();
- double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber();
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double hour = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double min = (callData->argc() < 2) ? MinFromTime(t) : callData->args[1].toNumber();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double sec = (callData->argc() < 3) ? SecFromTime(t) : callData->args[2].toNumber();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double ms = (callData->argc() < 4) ? msFromTime(t) : callData->args[3].toNumber();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setUTCHours(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = self->date();
- double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber();
- double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber();
- double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber();
+ double hour = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ double min = (callData->argc() < 2) ? MinFromTime(t) : callData->args[1].toNumber();
+ double sec = (callData->argc() < 3) ? SecFromTime(t) : callData->args[2].toNumber();
+ double ms = (callData->argc() < 4) ? msFromTime(t) : callData->args[3].toNumber();
t = TimeClip(MakeDate(Day(t), MakeTime(hour, min, sec, ms)));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setDate(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setDate(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = LocalTime(self->date());
- CHECK_EXCEPTION();
- double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double date = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setUTCDate(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = self->date();
- CHECK_EXCEPTION();
- double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double date = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setMonth(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = LocalTime(self->date());
- CHECK_EXCEPTION();
- double month = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- CHECK_EXCEPTION();
- double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber();
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double month = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double date = (callData->argc() < 2) ? DateFromTime(t) : callData->args[1].toNumber();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setUTCMonth(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = self->date();
- double month = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber();
+ double month = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ double date = (callData->argc() < 2) ? DateFromTime(t) : callData->args[1].toNumber();
t = TimeClip(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setYear(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setYear(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = self->date();
if (std::isnan(t))
t = 0;
else
t = LocalTime(t);
- double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double year = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
double r;
if (std::isnan(year)) {
r = qt_qnan();
@@ -1259,53 +1323,60 @@ void DatePrototype::method_setYear(const BuiltinFunction *, Scope &scope, CallDa
r = TimeClip(r);
}
self->setDate(r);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setUTCFullYear(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = self->date();
- double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
- double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber();
+ double year = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ double month = (callData->argc() < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
+ double date = (callData->argc() < 3) ? DateFromTime(t) : callData->args[2].toNumber();
t = TimeClip(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_setFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_setFullYear(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = LocalTime(self->date());
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
if (std::isnan(t))
t = 0;
- double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- CHECK_EXCEPTION();
- double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
- CHECK_EXCEPTION();
- double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber();
- CHECK_EXCEPTION();
+ double year = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double month = (callData->argc() < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ double date = (callData->argc() < 3) ? DateFromTime(t) : callData->args[2].toNumber();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
self->setDate(t);
- scope.result = Encode(self->date());
+ return Encode(self->date());
}
-void DatePrototype::method_toUTCString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_toUTCString(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = self->date();
- scope.result = scope.engine->newString(ToUTCString(t));
+ return Encode(v4->newString(ToUTCString(t)));
}
static void addZeroPrefixedInt(QString &str, int num, int nDigits)
@@ -1321,21 +1392,22 @@ static void addZeroPrefixedInt(QString &str, int num, int nDigits)
}
}
-void DatePrototype::method_toISOString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_toISOString(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
double t = self->date();
if (!std::isfinite(t))
- RETURN_RESULT(scope.engine->throwRangeError(callData->thisObject));
+ RETURN_RESULT(v4->throwRangeError(callData->thisObject));
QString result;
int year = (int)YearFromTime(t);
if (year < 0 || year > 9999) {
if (qAbs(year) >= 1000000)
- RETURN_RESULT(scope.engine->newString(QStringLiteral("Invalid Date")));
+ RETURN_RESULT(v4->newString(QStringLiteral("Invalid Date")));
result += year < 0 ? QLatin1Char('-') : QLatin1Char('+');
year = qAbs(year);
addZeroPrefixedInt(result, year, 6);
@@ -1356,29 +1428,32 @@ void DatePrototype::method_toISOString(const BuiltinFunction *, Scope &scope, Ca
addZeroPrefixedInt(result, msFromTime(t), 3);
result += QLatin1Char('Z');
- scope.result = scope.engine->newString(result);
+ return Encode(v4->newString(result));
}
-void DatePrototype::method_toJSON(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue DatePrototype::method_toJSON(const BuiltinFunction *b, CallData *callData)
{
- ScopedObject O(scope, callData->thisObject.toObject(scope.engine));
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+ ScopedObject O(scope, callData->thisObject.toObject(v4));
+ if (v4->hasException)
+ return QV4::Encode::undefined();
ScopedValue tv(scope, RuntimeHelpers::toPrimitive(O, NUMBER_HINT));
if (tv->isNumber() && !std::isfinite(tv->toNumber()))
RETURN_RESULT(Encode::null());
- ScopedString s(scope, scope.engine->newString(QStringLiteral("toISOString")));
+ ScopedString s(scope, v4->newString(QStringLiteral("toISOString")));
ScopedValue v(scope, O->get(s));
FunctionObject *toIso = v->as<FunctionObject>();
if (!toIso)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
- ScopedCallData cData(scope);
- cData->thisObject = callData->thisObject;
- toIso->call(scope, cData);
+ JSCallData jsCallData(scope);
+ *jsCallData->thisObject = callData->thisObject;
+ return toIso->call(jsCallData);
}
void DatePrototype::timezoneUpdated()
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index b0373884dd..776822d312 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -108,8 +108,8 @@ struct DateCtor: FunctionObject
{
V4_OBJECT2(DateCtor, FunctionObject)
- static void construct(const Managed *, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *);
+ static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int);
};
struct DatePrototype: Object
@@ -118,57 +118,57 @@ struct DatePrototype: Object
void init(ExecutionEngine *engine, Object *ctor);
- static double getThisDate(Scope &scope, CallData *callData);
-
- static void method_parse(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_UTC(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_now(const BuiltinFunction *, Scope &scope, CallData *callData);
-
- static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toDateString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toTimeString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getTime(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getYear(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getDate(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getDay(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getUTCDay(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getHours(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_getTimezoneOffset(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setTime(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setHours(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setDate(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setYear(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_setUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toUTCString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toISOString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toJSON(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static double getThisDate(ExecutionEngine *v4, CallData *callData);
+
+ static ReturnedValue method_parse(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_UTC(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_now(const BuiltinFunction *, CallData *callData);
+
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toDateString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toTimeString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toLocaleString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toLocaleDateString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toLocaleTimeString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_valueOf(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getTime(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getYear(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getFullYear(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getUTCFullYear(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getMonth(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getUTCMonth(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getDate(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getUTCDate(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getDay(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getUTCDay(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getHours(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getUTCHours(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getMinutes(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getUTCMinutes(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getSeconds(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getUTCSeconds(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getMilliseconds(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getUTCMilliseconds(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getTimezoneOffset(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setTime(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setMilliseconds(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setUTCMilliseconds(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setSeconds(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setUTCSeconds(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setMinutes(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setUTCMinutes(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setHours(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setUTCHours(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setDate(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setUTCDate(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setMonth(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setUTCMonth(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setYear(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setFullYear(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_setUTCFullYear(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toUTCString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toISOString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toJSON(const BuiltinFunction *, CallData *callData);
static void timezoneUpdated();
};
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 7b298a302c..049e4a117d 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -81,14 +81,6 @@
#include <QtCore/QTextStream>
#include <QDateTime>
-#ifdef V4_ENABLE_JIT
-#include "qv4isel_masm_p.h"
-#endif // V4_ENABLE_JIT
-
-#if QT_CONFIG(qml_interpreter)
-#include "qv4isel_moth_p.h"
-#endif
-
#if USE(PTHREADS)
# include <pthread.h>
#if !defined(Q_OS_INTEGRITY)
@@ -109,9 +101,9 @@ using namespace QV4;
static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
-void throwTypeError(const BuiltinFunction *, Scope &scope, CallData *)
+ReturnedValue throwTypeError(const BuiltinFunction *b, CallData *)
{
- scope.result = scope.engine->throwTypeError();
+ return b->engine()->throwTypeError();
}
@@ -129,7 +121,7 @@ QQmlEngine *ExecutionEngine::qmlEngine() const
qint32 ExecutionEngine::maxCallDepth = -1;
-ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
+ExecutionEngine::ExecutionEngine()
: executableAllocator(new QV4::ExecutableAllocator)
, regExpAllocator(new QV4::ExecutableAllocator)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
@@ -149,38 +141,15 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
bool ok = false;
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
if (!ok || maxCallDepth <= 0) {
+#ifdef QT_NO_DEBUG
maxCallDepth = 1234;
- }
- }
- Q_ASSERT(maxCallDepth > 0);
-
- if (!factory) {
-#if QT_CONFIG(qml_interpreter)
- bool jitDisabled = true;
-
-#ifdef V4_ENABLE_JIT
- static const bool forceMoth = !qEnvironmentVariableIsEmpty("QV4_FORCE_INTERPRETER") ||
- !OSAllocator::canAllocateExecutableMemory();
- if (forceMoth) {
- factory = new Moth::ISelFactory;
- } else {
- factory = new JIT::ISelFactory<>;
- jitDisabled = false;
- }
-#else // !V4_ENABLE_JIT
- factory = new Moth::ISelFactory;
-#endif // V4_ENABLE_JIT
-
- if (jitDisabled) {
- qWarning("JIT is disabled for QML. Property bindings and animations will be "
- "very slow. Visit https://wiki.qt.io/V4 to learn about possible "
- "solutions for your platform.");
- }
#else
- factory = new JIT::ISelFactory<>;
+ // no (tail call) optimization is done, so there'll be a lot mare stack frames active
+ maxCallDepth = 200;
#endif
+ }
}
- iselFactory.reset(factory);
+ Q_ASSERT(maxCallDepth > 0);
// reserve space for the JS stack
// we allow it to grow to a bit more than JSStackLimit, as we can overshoot due to ScopedValues
@@ -219,7 +188,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable());
internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
- internalClasses[Class_SimpleCallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
+ internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
jsStrings[String_Empty] = newIdentifier(QString());
jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
@@ -425,8 +394,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
//
// set up the global object
//
- rootContext()->d()->global.set(scope.engine, globalObject->d());
- rootContext()->d()->callData->thisObject = globalObject;
+ rootContext()->d()->activation.set(scope.engine, globalObject->d());
Q_ASSERT(globalObject->d()->vtable());
globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
@@ -535,19 +503,11 @@ void ExecutionEngine::setProfiler(Profiling::Profiler *profiler)
void ExecutionEngine::initRootContext()
{
Scope scope(this);
- Scoped<GlobalContext> r(scope, memoryManager->allocManaged<GlobalContext>(
- sizeof(GlobalContext::Data) + sizeof(CallData)));
- r->d_unchecked()->init(this);
- r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1);
- r->d()->callData->tag = quint32(Value::ValueTypeInternal::Integer);
- r->d()->callData->argc = 0;
- r->d()->callData->thisObject = globalObject;
- r->d()->callData->args[0] = Encode::undefined();
+ Scoped<ExecutionContext> r(scope, memoryManager->allocManaged<ExecutionContext>(sizeof(ExecutionContext::Data)));
+ r->d_unchecked()->init(Heap::ExecutionContext::Type_GlobalContext);
+ r->d()->activation.set(this, globalObject->d());
jsObjects[RootContext] = r;
jsObjects[IntegerNull] = Encode((int)0);
-
- currentContext = static_cast<ExecutionContext *>(jsObjects + RootContext);
- current = currentContext->d();
}
InternalClass *ExecutionEngine::newClass(const InternalClass &other)
@@ -555,14 +515,6 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other)
return new (classPool) InternalClass(other);
}
-ExecutionContext *ExecutionEngine::pushGlobalContext()
-{
- pushContext(rootContext()->d());
-
- Q_ASSERT(current == rootContext()->d());
- return currentContext;
-}
-
InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype)
{
return internalClasses[EngineBase::Class_Empty]->changeVTable(vtable)->changePrototype(prototype ? prototype->d() : 0);
@@ -685,9 +637,9 @@ Heap::DateObject *ExecutionEngine::newDateObjectFromTime(const QTime &t)
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
{
- bool global = (flags & IR::RegExp::RegExp_Global);
- bool ignoreCase = (flags & IR::RegExp::RegExp_IgnoreCase);
- bool multiline = (flags & IR::RegExp::RegExp_Multiline);
+ bool global = (flags & QV4::CompiledData::RegExp::RegExp_Global);
+ bool ignoreCase = (flags & QV4::CompiledData::RegExp::RegExp_IgnoreCase);
+ bool multiline = (flags & QV4::CompiledData::RegExp::RegExp_Multiline);
Scope scope(this);
Scoped<RegExp> re(scope, RegExp::create(this, pattern, ignoreCase, multiline, global));
@@ -760,11 +712,9 @@ Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o)
Heap::QmlContext *ExecutionEngine::qmlContext() const
{
- Heap::ExecutionContext *ctx = current;
-
- // get the correct context when we're within a builtin function
- if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer)
- ctx = parentContext(currentContext)->d();
+ if (!currentStackFrame)
+ return 0;
+ Heap::ExecutionContext *ctx = currentContext()->d();
if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer)
return 0;
@@ -785,7 +735,7 @@ QObject *ExecutionEngine::qmlScopeObject() const
if (!ctx)
return 0;
- return ctx->qml->scopeObject;
+ return ctx->qml()->scopeObject;
}
ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name)
@@ -815,57 +765,56 @@ QQmlContextData *ExecutionEngine::callingQmlContext() const
if (!ctx)
return 0;
- return ctx->qml->context->contextData();
+ return ctx->qml()->context->contextData();
}
-QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
+QString CppStackFrame::source() const
{
- Scope scope(const_cast<ExecutionEngine *>(this));
- ScopedString name(scope);
- QVector<StackFrame> stack;
-
- ExecutionContext *c = currentContext;
- while (c && frameLimit) {
- QV4::Function *function = c->getFunction();
- if (function) {
- StackFrame frame;
- frame.source = function->sourceFile();
- name = function->name();
- frame.function = name->toQString();
-
- // line numbers can be negative for places where you can't set a real breakpoint
- frame.line = qAbs(c->d()->lineNumber);
- frame.column = -1;
-
- stack.append(frame);
- --frameLimit;
- }
- c = parentContext(c);
- }
-
- if (frameLimit && globalCode) {
- StackFrame frame;
- frame.source = globalCode->sourceFile();
- frame.function = globalCode->name()->toQString();
- frame.line = rootContext()->d()->lineNumber;
- frame.column = -1;
+ return v4Function->sourceFile();
+}
- stack.append(frame);
- }
- return stack;
+QString CppStackFrame::function() const
+{
+ return v4Function->name()->toQString();
}
-StackFrame ExecutionEngine::currentStackFrame() const
+int CppStackFrame::lineNumber() const
{
- StackFrame frame;
- frame.line = -1;
- frame.column = -1;
+ auto findLine = [](const CompiledData::CodeOffsetToLine &entry, uint offset) {
+ return entry.codeOffset < offset;
+ };
+
+ const QV4::CompiledData::Function *cf = v4Function->compiledFunction;
+ uint offset = static_cast<uint>(instructionPointer - v4Function->codeData);
+ const CompiledData::CodeOffsetToLine *lineNumbers = cf->lineNumberTable();
+ uint nLineNumbers = cf->nLineNumbers;
+ const CompiledData::CodeOffsetToLine *line = std::lower_bound(lineNumbers, lineNumbers + nLineNumbers, offset, findLine) - 1;
+ return line->line;
+}
+
+ReturnedValue CppStackFrame::thisObject() const {
+ return jsFrame->thisObject.asReturnedValue();
+}
- QVector<StackFrame> trace = stackTrace(/*limit*/ 1);
- if (!trace.isEmpty())
- frame = trace.first();
+StackTrace ExecutionEngine::stackTrace(int frameLimit) const
+{
+ Scope scope(const_cast<ExecutionEngine *>(this));
+ ScopedString name(scope);
+ StackTrace stack;
+
+ CppStackFrame *f = currentStackFrame;
+ while (f && frameLimit) {
+ QV4::StackFrame frame;
+ frame.source = f->source();
+ frame.function = f->function();
+ frame.line = qAbs(f->lineNumber());
+ frame.column = -1;
+ stack.append(frame);
+ --frameLimit;
+ f = f->parent;
+ }
- return frame;
+ return stack;
}
/* Helper and "C" linkage exported function to format a GDBMI stacktrace for
@@ -908,14 +857,13 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
return src;
QUrl base;
- ExecutionContext *c = currentContext;
- while (c) {
- SimpleCallContext *callCtx = c->asSimpleCallContext();
- if (callCtx && callCtx->d()->v4Function) {
- base.setUrl(callCtx->d()->v4Function->sourceFile());
+ CppStackFrame *f = currentStackFrame;
+ while (f) {
+ if (f->v4Function) {
+ base.setUrl(f->v4Function->sourceFile());
break;
}
- c = parentContext(c);
+ f = f->parent;
}
if (base.isEmpty() && globalCode)
@@ -1589,11 +1537,6 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
return 0;
}
-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 4549cda5b9..db002035da 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -51,7 +51,6 @@
//
#include "qv4global_p.h"
-#include "private/qv4isel_p.h"
#include "qv4managed_p.h"
#include "qv4context_p.h"
#include <private/qintrusivelist_p.h>
@@ -89,6 +88,30 @@ struct CompilationUnit;
struct InternalClass;
struct InternalClassPool;
+struct Q_QML_EXPORT CppStackFrame {
+ CppStackFrame *parent;
+ Function *v4Function;
+ CallData *jsFrame;
+ const uchar *instructionPointer;
+
+ QString source() const;
+ QString function() const;
+ inline QV4::ExecutionContext *context() const {
+ return static_cast<ExecutionContext *>(&jsFrame->context);
+ }
+ int lineNumber() const;
+
+ inline QV4::Heap::CallContext *callContext() const {
+ Heap::ExecutionContext *ctx = static_cast<ExecutionContext &>(jsFrame->context).d();\
+ while (ctx->type != Heap::ExecutionContext::Type_CallContext)
+ ctx = ctx->outer;
+ return static_cast<Heap::CallContext *>(ctx);
+ }
+ ReturnedValue thisObject() const;
+};
+
+
+
struct Q_QML_EXPORT ExecutionEngine : public EngineBase
{
private:
@@ -100,7 +123,6 @@ private:
public:
ExecutableAllocator *executableAllocator;
ExecutableAllocator *regExpAllocator;
- QScopedPointer<EvalISelFactory> iselFactory;
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
@@ -183,7 +205,7 @@ public:
Value *jsObjects;
enum { NTypedArrayTypes = 9 }; // == TypedArray::NValues, avoid header dependency
- GlobalContext *rootContext() const { return reinterpret_cast<GlobalContext *>(jsObjects + RootContext); }
+ ExecutionContext *rootContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + RootContext); }
FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); }
FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); }
FunctionObject *numberCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Number_Ctor); }
@@ -342,7 +364,7 @@ public:
// bookkeeping.
MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects;
- ExecutionEngine(EvalISelFactory *iselFactory = 0);
+ ExecutionEngine();
~ExecutionEngine();
#ifdef QT_NO_QML_DEBUGGER
@@ -359,11 +381,10 @@ public:
void setProfiler(Profiling::Profiler *profiler);
#endif // QT_NO_QML_DEBUGGER
- ExecutionContext *pushGlobalContext();
- void pushContext(Heap::ExecutionContext *context);
- void pushContext(ExecutionContext *context);
- void popContext();
- ExecutionContext *parentContext(ExecutionContext *context) const;
+ void setCurrentContext(Heap::ExecutionContext *context);
+ ExecutionContext *currentContext() const {
+ return static_cast<ExecutionContext *>(&currentStackFrame->jsFrame->context);
+ }
InternalClass *newInternalClass(const VTable *vtable, Object *prototype);
@@ -413,7 +434,6 @@ public:
StackTrace stackTrace(int frameLimit = -1) const;
- StackFrame currentStackFrame() const;
QUrl resolvedUrl(const QString &file);
void requireArgumentsAccessors(int n);
@@ -424,8 +444,6 @@ public:
InternalClass *newClass(const InternalClass &other);
- // Exception handling
- Value *exceptionValue;
StackTrace exceptionStackTrace;
ReturnedValue throwError(const Value &value);
@@ -455,11 +473,9 @@ public:
bool metaTypeFromJS(const Value *value, int type, void *data);
QV4::ReturnedValue metaTypeToJS(int type, const void *data);
- bool checkStackLimits(Scope &scope);
+ bool checkStackLimits();
private:
- void failStackLimitCheck(Scope &scope);
-
#ifndef QT_NO_QML_DEBUGGER
QScopedPointer<QV4::Debugging::Debugger> m_debugger;
QScopedPointer<QV4::Profiling::Profiler> m_profiler;
@@ -477,39 +493,9 @@ struct NoThrowEngine;
#endif
-inline void ExecutionEngine::pushContext(Heap::ExecutionContext *context)
-{
- Q_ASSERT(currentContext && context);
- Value *v = jsAlloca(2);
- v[0] = Encode(context);
- v[1] = Encode((int)(v - static_cast<Value *>(currentContext)));
- currentContext = static_cast<ExecutionContext *>(v);
- current = currentContext->d();
-}
-
-inline void ExecutionEngine::pushContext(ExecutionContext *context)
-{
- pushContext(context->d());
-}
-
-
-inline void ExecutionEngine::popContext()
-{
- Q_ASSERT(jsStackTop > currentContext);
- QV4::Value *offset = (currentContext + 1);
- Q_ASSERT(offset->isInteger());
- int o = offset->integerValue();
- Q_ASSERT(o);
- currentContext -= o;
- current = currentContext->d();
-}
-
-inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *context) const
+inline void ExecutionEngine::setCurrentContext(Heap::ExecutionContext *context)
{
- Value *offset = static_cast<Value *>(context) + 1;
- Q_ASSERT(offset->isInteger());
- int o = offset->integerValue();
- return o ? context - o : 0;
+ currentStackFrame->jsFrame->context = context;
}
inline
@@ -541,7 +527,7 @@ inline void Managed::mark(MarkStack *markStack)
m()->mark(markStack);
}
-#define CHECK_STACK_LIMITS(v4, scope) if ((v4)->checkStackLimits(scope)) return; \
+#define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \
ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
struct ExecutionEngineCallDepthRecorder
@@ -552,10 +538,10 @@ struct ExecutionEngineCallDepthRecorder
~ExecutionEngineCallDepthRecorder() { --ee->callDepth; }
};
-inline bool ExecutionEngine::checkStackLimits(Scope &scope)
+inline bool ExecutionEngine::checkStackLimits()
{
if (Q_UNLIKELY((jsStackTop > jsStackLimit) || (callDepth >= maxCallDepth))) {
- failStackLimitCheck(scope);
+ throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
return true;
}
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index 88f9dfd85c..e0f5f3ffb1 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -57,31 +57,36 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct CppStackFrame;
+
// Base class for the execution engine
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
#pragma pack(push, 1)
#endif
-struct EngineBase {
- Heap::ExecutionContext *current = 0;
+struct Q_QML_EXPORT EngineBase {
+
+ CppStackFrame *currentStackFrame = nullptr;
- Value *jsStackTop = 0;
+ Value *jsStackTop = nullptr;
quint8 hasException = false;
quint8 writeBarrierActive = false;
quint16 unused = 0;
#if QT_POINTER_SIZE == 8
quint8 padding[4];
#endif
- MemoryManager *memoryManager = 0;
+ MemoryManager *memoryManager = nullptr;
Runtime runtime;
qint32 callDepth = 0;
- Value *jsStackLimit = 0;
- Value *jsStackBase = 0;
+ Value *jsStackLimit = nullptr;
+ Value *jsStackBase = nullptr;
+
+ IdentifierTable *identifierTable = nullptr;
+ Object *globalObject = nullptr;
- ExecutionContext *currentContext = 0;
- IdentifierTable *identifierTable = 0;
- Object *globalObject = 0;
+ // Exception handling
+ Value *exceptionValue = nullptr;
enum {
Class_Empty,
@@ -90,7 +95,7 @@ struct EngineBase {
Class_SimpleArrayData,
Class_SparseArrayData,
Class_ExecutionContext,
- Class_SimpleCallContext,
+ Class_CallContext,
Class_Object,
Class_ArrayObject,
Class_FunctionObject,
@@ -115,8 +120,8 @@ struct EngineBase {
#endif
Q_STATIC_ASSERT(std::is_standard_layout<EngineBase>::value);
-Q_STATIC_ASSERT(offsetof(EngineBase, current) == 0);
-Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(EngineBase, currentStackFrame) == 0);
+Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, currentStackFrame) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE);
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index b3bd28e18b..01c59dbcbe 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -51,7 +51,6 @@
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
-#include <qv4jsir_p.h>
#include <qv4codegen_p.h>
#ifndef Q_OS_WIN
@@ -107,6 +106,7 @@ void Heap::ErrorObject::init(const Value &message, ErrorType t)
void Heap::ErrorObject::init(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t)
{
+ Q_UNUSED(fileName); // ####
Object::init();
errorType = t;
@@ -123,10 +123,9 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int
frame.column = column;
e->d()->stackTrace->prepend(frame);
- if (!e->d()->stackTrace->isEmpty()) {
- setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
- setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line));
- }
+ Q_ASSERT(!e->d()->stackTrace->isEmpty());
+ setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line));
if (!message.isUndefined())
setProperty(scope.engine, QV4::ErrorObject::Index_Message, message);
@@ -153,11 +152,12 @@ const char *ErrorObject::className(Heap::ErrorObject::ErrorType t)
Q_UNREACHABLE();
}
-void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ErrorObject::method_get_stack(const BuiltinFunction *b, CallData *callData)
{
- Scoped<ErrorObject> This(scope, callData->thisObject);
+ ExecutionEngine *v4 = b->engine();
+ ErrorObject *This = callData->thisObject.as<ErrorObject>();
if (!This)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
if (!This->d()->stack) {
QString trace;
for (int i = 0; i < This->d()->stackTrace->count(); ++i) {
@@ -168,9 +168,9 @@ void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallDa
if (frame.line >= 0)
trace += QLatin1Char(':') + QString::number(frame.line);
}
- This->d()->stack.set(scope.engine, scope.engine->newString(trace));
+ This->d()->stack.set(v4, v4->newString(trace));
}
- scope.result = This->d()->stack;
+ return This->d()->stack->asReturnedValue();
}
DEFINE_OBJECT_VTABLE(ErrorObject);
@@ -233,15 +233,15 @@ void Heap::ErrorCtor::init(QV4::ExecutionContext *scope, const QString &name)
Heap::FunctionObject::init(scope, name);
}
-void ErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue ErrorCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- ScopedValue v(scope, callData->argument(0));
- scope.result = ErrorObject::create<ErrorObject>(scope.engine, v);
+ Value v = argc ? *argv : Primitive::undefinedValue();
+ return ErrorObject::create<ErrorObject>(f->engine(), v)->asReturnedValue();
}
-void ErrorCtor::call(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue ErrorCtor::call(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
- static_cast<const Object *>(that)->construct(scope, callData);
+ return f->callAsConstructor(argv, argc);
}
void Heap::EvalErrorCtor::init(QV4::ExecutionContext *scope)
@@ -249,10 +249,10 @@ void Heap::EvalErrorCtor::init(QV4::ExecutionContext *scope)
Heap::ErrorCtor::init(scope, QStringLiteral("EvalError"));
}
-void EvalErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue EvalErrorCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- ScopedValue v(scope, callData->argument(0));
- scope.result = ErrorObject::create<EvalErrorObject>(scope.engine, v);
+ Value v = argc ? *argv : Primitive::undefinedValue();
+ return ErrorObject::create<EvalErrorObject>(f->engine(), v)->asReturnedValue();
}
void Heap::RangeErrorCtor::init(QV4::ExecutionContext *scope)
@@ -260,10 +260,10 @@ void Heap::RangeErrorCtor::init(QV4::ExecutionContext *scope)
Heap::ErrorCtor::init(scope, QStringLiteral("RangeError"));
}
-void RangeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue RangeErrorCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- ScopedValue v(scope, callData->argument(0));
- scope.result = ErrorObject::create<RangeErrorObject>(scope.engine, v);
+ Value v = argc ? *argv : Primitive::undefinedValue();
+ return ErrorObject::create<RangeErrorObject>(f->engine(), v)->asReturnedValue();
}
void Heap::ReferenceErrorCtor::init(QV4::ExecutionContext *scope)
@@ -271,10 +271,10 @@ void Heap::ReferenceErrorCtor::init(QV4::ExecutionContext *scope)
Heap::ErrorCtor::init(scope, QStringLiteral("ReferenceError"));
}
-void ReferenceErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue ReferenceErrorCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- ScopedValue v(scope, callData->argument(0));
- scope.result = ErrorObject::create<ReferenceErrorObject>(scope.engine, v);
+ Value v = argc ? *argv : Primitive::undefinedValue();
+ return ErrorObject::create<ReferenceErrorObject>(f->engine(), v)->asReturnedValue();
}
void Heap::SyntaxErrorCtor::init(QV4::ExecutionContext *scope)
@@ -282,10 +282,10 @@ void Heap::SyntaxErrorCtor::init(QV4::ExecutionContext *scope)
Heap::ErrorCtor::init(scope, QStringLiteral("SyntaxError"));
}
-void SyntaxErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue SyntaxErrorCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- ScopedValue v(scope, callData->argument(0));
- scope.result = ErrorObject::create<SyntaxErrorObject>(scope.engine, v);
+ Value v = argc ? *argv : Primitive::undefinedValue();
+ return ErrorObject::create<SyntaxErrorObject>(f->engine(), v)->asReturnedValue();
}
void Heap::TypeErrorCtor::init(QV4::ExecutionContext *scope)
@@ -293,10 +293,10 @@ void Heap::TypeErrorCtor::init(QV4::ExecutionContext *scope)
Heap::ErrorCtor::init(scope, QStringLiteral("TypeError"));
}
-void TypeErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue TypeErrorCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- ScopedValue v(scope, callData->argument(0));
- scope.result = ErrorObject::create<TypeErrorObject>(scope.engine, v);
+ Value v = argc ? *argv : Primitive::undefinedValue();
+ return ErrorObject::create<TypeErrorObject>(f->engine(), v)->asReturnedValue();
}
void Heap::URIErrorCtor::init(QV4::ExecutionContext *scope)
@@ -304,10 +304,10 @@ void Heap::URIErrorCtor::init(QV4::ExecutionContext *scope)
Heap::ErrorCtor::init(scope, QStringLiteral("URIError"));
}
-void URIErrorCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue URIErrorCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- ScopedValue v(scope, callData->argument(0));
- scope.result = ErrorObject::create<URIErrorObject>(scope.engine, v);
+ Value v = argc ? *argv : Primitive::undefinedValue();
+ return ErrorObject::create<URIErrorObject>(f->engine(), v)->asReturnedValue();
}
void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t)
@@ -323,12 +323,14 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He
obj->defineDefaultProperty(engine->id_toString(), method_toString, 0);
}
-void ErrorPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ErrorPrototype::method_toString(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
Object *o = callData->thisObject.as<Object>();
if (!o)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
+ Scope scope(v4);
ScopedValue name(scope, o->get(scope.engine->id_name()));
QString qname;
if (name->isUndefined())
@@ -351,5 +353,5 @@ void ErrorPrototype::method_toString(const BuiltinFunction *, Scope &scope, Call
str = qname + QLatin1String(": ") + qmessage;
}
- scope.result = scope.engine->newString(str)->asReturnedValue();
+ return scope.engine->newString(str)->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index d556617b48..9942ee1ad6 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -175,7 +175,7 @@ struct ErrorObject: Object {
static const char *className(Heap::ErrorObject::ErrorType t);
- static void method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_get_stack(const BuiltinFunction *, CallData *callData);
};
template<>
@@ -229,50 +229,50 @@ struct ErrorCtor: FunctionObject
{
V4_OBJECT2(ErrorCtor, FunctionObject)
- static void construct(const Managed *, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
struct EvalErrorCtor: ErrorCtor
{
V4_OBJECT2(EvalErrorCtor, ErrorCtor)
- static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
};
struct RangeErrorCtor: ErrorCtor
{
V4_OBJECT2(RangeErrorCtor, ErrorCtor)
- static void construct(const Managed *, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
};
struct ReferenceErrorCtor: ErrorCtor
{
V4_OBJECT2(ReferenceErrorCtor, ErrorCtor)
- static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
};
struct SyntaxErrorCtor: ErrorCtor
{
V4_OBJECT2(SyntaxErrorCtor, ErrorCtor)
- static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
};
struct TypeErrorCtor: ErrorCtor
{
V4_OBJECT2(TypeErrorCtor, ErrorCtor)
- static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
};
struct URIErrorCtor: ErrorCtor
{
V4_OBJECT2(URIErrorCtor, ErrorCtor)
- static void construct(const Managed *m, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
};
@@ -286,7 +286,7 @@ struct ErrorPrototype : ErrorObject
void init(ExecutionEngine *engine, Object *ctor) { init(engine, ctor, this, Heap::ErrorObject::Error); }
static void init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t);
- static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
};
struct EvalErrorPrototype : ErrorObject
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 4b88d85e68..32a72fda3f 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qv4function_p.h"
+#include "qv4functionobject_p.h"
#include "qv4managed_p.h"
#include "qv4string_p.h"
#include "qv4value_p.h"
@@ -50,39 +51,27 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function,
- ReturnedValue (*codePtr)(ExecutionEngine *, const uchar *))
+Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, Code codePtr)
: compiledFunction(function)
, compilationUnit(unit)
, code(codePtr)
- , codeData(0)
+ , codeData(function->code())
, hasQmlDependencies(function->hasQmlDependencies())
{
- internalClass = engine->internalClasses[EngineBase::Class_Empty];
- const quint32_le *formalsIndices = compiledFunction->formalsTable();
- // iterate backwards, so we get the right ordering for duplicate names
- Scope scope(engine);
- ScopedString arg(scope);
- for (int i = static_cast<int>(compiledFunction->nFormals - 1); i >= 0; --i) {
- arg = compilationUnit->runtimeStrings[formalsIndices[i]];
- while (1) {
- InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable);
- if (newClass != internalClass) {
- internalClass = newClass;
- break;
- }
- // duplicate arguments, need some trick to store them
- MemoryManager *mm = engine->memoryManager;
- arg = mm->alloc<String>(arg->d(), engine->newString(QString(0xfffe)));
- }
- }
- nFormals = compiledFunction->nFormals;
+ Q_UNUSED(engine);
+
+ internalClass = engine->internalClasses[EngineBase::Class_CallContext];
+ // first locals
const quint32_le *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
- canUseSimpleCall = compiledFunction->flags & CompiledData::Function::CanUseSimpleCall;
+ const quint32_le *formalsIndices = compiledFunction->formalsTable();
+ for (quint32 i = 0; i < compiledFunction->nFormals; ++i)
+ internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[formalsIndices[i]]), Attr_NotConfigurable);
+
+ nFormals = compiledFunction->nFormals;
}
Function::~Function()
@@ -91,30 +80,45 @@ Function::~Function()
void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters)
{
- internalClass = engine->internalClasses[EngineBase::Class_Empty];
+ QStringList parameterNames;
- // iterate backwards, so we get the right ordering for duplicate names
- Scope scope(engine);
- ScopedString arg(scope);
- for (int i = parameters.size() - 1; i >= 0; --i) {
- arg = engine->newString(QString::fromUtf8(parameters.at(i)));
- while (1) {
- InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable);
- if (newClass != internalClass) {
- internalClass = newClass;
+ // Resolve duplicate parameter names:
+ for (int i = 0, ei = parameters.count(); i != ei; ++i) {
+ const QByteArray &param = parameters.at(i);
+ int duplicate = -1;
+
+ for (int j = i - 1; j >= 0; --j) {
+ const QByteArray &prevParam = parameters.at(j);
+ if (param == prevParam) {
+ duplicate = j;
break;
}
- // duplicate arguments, need some trick to store them
- arg = engine->memoryManager->alloc<String>(arg->d(), engine->newString(QString(0xfffe)));
}
+
+ if (duplicate == -1) {
+ parameterNames.append(QString::fromUtf8(param));
+ } else {
+ const QString &dup = parameterNames[duplicate];
+ parameterNames.append(dup);
+ parameterNames[duplicate] =
+ QString(0xfffe) + QString::number(duplicate) + dup;
+ }
+
+ }
+
+ internalClass = engine->internalClasses[EngineBase::Class_CallContext];
+
+ Scope scope(engine);
+ ScopedString arg(scope);
+ for (const QString &parameterName : parameterNames) {
+ arg = engine->newString(parameterName);
+ internalClass = internalClass->addMember(arg, Attr_NotConfigurable);
}
nFormals = parameters.size();
const quint32_le *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
-
- canUseSimpleCall = false;
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index b11c8af94a..5ecbd0a359 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -63,17 +63,21 @@ struct Q_QML_EXPORT Function {
const CompiledData::Function *compiledFunction;
CompiledData::CompilationUnit *compilationUnit;
- ReturnedValue (*code)(ExecutionEngine *, const uchar *);
+ ReturnedValue call(CallData *callData) {
+ return code(callData, this);
+ }
+
+
+ typedef ReturnedValue (*Code)(CallData *, Function *);
+ Code code;
const uchar *codeData;
// first nArguments names in internalClass are the actual arguments
InternalClass *internalClass;
uint nFormals;
bool hasQmlDependencies;
- bool canUseSimpleCall;
- Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function,
- ReturnedValue (*codePtr)(ExecutionEngine *, const uchar *));
+ Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, Code codePtr);
~Function();
// used when dynamically assigning signal handlers (QQmlConnection)
@@ -86,21 +90,18 @@ struct Q_QML_EXPORT Function {
inline bool usesArgumentsObject() const { return compiledFunction->flags & CompiledData::Function::UsesArgumentsObject; }
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
- inline bool isNamedExpression() const { return compiledFunction->flags & CompiledData::Function::IsNamedExpression; }
-
- inline bool canUseSimpleFunction() const { return canUseSimpleCall; }
QQmlSourceLocation sourceLocation() const
{
return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
}
-
};
-inline unsigned int Heap::SimpleCallContext::formalParameterCount() const
+inline unsigned int Heap::CallContext::formalParameterCount() const
{
- return v4Function ? v4Function->nFormals : 0;
+ Q_ASSERT(v4Function);
+ return v4Function->nFormals;
}
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 45fdde98f7..bd8bb9c8fb 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -38,8 +38,6 @@
****************************************************************************/
#include "qv4object_p.h"
-#include "qv4jsir_p.h"
-#include "qv4isel_p.h"
#include "qv4objectproto_p.h"
#include "qv4stringobject_p.h"
#include "qv4function_p.h"
@@ -55,9 +53,10 @@
#include <private/qqmljsast_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include <private/qqmlengine_p.h>
-#include <qv4codegen_p.h>
+#include <qv4runtimecodegen_p.h>
#include "private/qlocale_tools_p.h"
#include "private/qqmlbuiltinfunctions_p.h"
+#include <private/qv4jscall_p.h>
#include <QtCore/QDebug>
#include <algorithm>
@@ -73,6 +72,9 @@ Q_STATIC_ASSERT((Heap::FunctionObject::markTable & Heap::Object::markTable) == H
void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto)
{
+ jsCall = reinterpret_cast<const ObjectVTable *>(vtable())->call;
+ jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor;
+
Object::init();
function = nullptr;
this->scope.set(scope->engine(), scope->d());
@@ -83,6 +85,9 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, bool createProto)
{
+ jsCall = reinterpret_cast<const ObjectVTable *>(vtable())->call;
+ jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor;
+
Object::init();
this->function = function;
function->compilationUnit->addref();
@@ -102,6 +107,9 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &nam
void Heap::FunctionObject::init()
{
+ jsCall = reinterpret_cast<const ObjectVTable *>(vtable())->call;
+ jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor;
+
Object::init();
function = nullptr;
this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
@@ -141,14 +149,14 @@ ReturnedValue FunctionObject::name() const
return get(scope()->internalClass->engine->id_name());
}
-void FunctionObject::construct(const Managed *that, Scope &scope, CallData *)
+ReturnedValue FunctionObject::callAsConstructor(const FunctionObject *f, const Value *, int)
{
- scope.result = static_cast<const FunctionObject *>(that)->engine()->throwTypeError();
+ return f->engine()->throwTypeError();
}
-void FunctionObject::call(const Managed *, Scope &scope, CallData *)
+ReturnedValue FunctionObject::call(const FunctionObject *, const Value *, const Value *, int)
{
- scope.result = Encode::undefined();
+ return Encode::undefined();
}
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
@@ -179,24 +187,22 @@ void Heap::FunctionCtor::init(QV4::ExecutionContext *scope)
}
// 15.3.2
-void FunctionCtor::construct(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue FunctionCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that));
+ Scope scope(f->engine());
QString arguments;
QString body;
- if (callData->argc > 0) {
- for (int i = 0; i < callData->argc - 1; ++i) {
+ if (argc > 0) {
+ for (int i = 0, ei = argc - 1; i < ei; ++i) {
if (i)
arguments += QLatin1String(", ");
- arguments += callData->args[i].toQString();
+ arguments += argv[i].toQString();
}
- body = callData->args[callData->argc - 1].toQString();
- }
- if (scope.engine->hasException) {
- scope.result = Encode::undefined();
- return;
+ body = argv[argc - 1].toQString();
}
+ if (scope.engine->hasException)
+ return Encode::undefined();
QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1Char('}');
@@ -207,36 +213,30 @@ void FunctionCtor::construct(const Managed *that, Scope &scope, CallData *callDa
const bool parsed = parser.parseExpression();
- if (!parsed) {
- scope.result = scope.engine->throwSyntaxError(QLatin1String("Parse error"));
- return;
- }
+ if (!parsed)
+ return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
- using namespace QQmlJS::AST;
- FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
- if (!fe) {
- scope.result = scope.engine->throwSyntaxError(QLatin1String("Parse error"));
- return;
- }
+ QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression *>(parser.rootNode());
+ if (!fe)
+ return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
- IR::Module module(scope.engine->debugger() != 0);
+ Compiler::Module module(scope.engine->debugger() != 0);
- QQmlJS::RuntimeCodegen cg(scope.engine, f->strictMode());
+ Compiler::JSUnitGenerator jsGenerator(&module);
+ RuntimeCodegen cg(scope.engine, &jsGenerator, false);
cg.generateFromFunctionExpression(QString(), function, fe, &module);
- Compiler::JSUnitGenerator jsGenerator(&module);
- QScopedPointer<EvalInstructionSelection> isel(scope.engine->iselFactory->create(QQmlEnginePrivate::get(scope.engine), scope.engine->executableAllocator, &module, &jsGenerator));
- QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = isel->compile();
+ QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = cg.generateCompilationUnit();
Function *vmf = compilationUnit->linkToEngine(scope.engine);
ExecutionContext *global = scope.engine->rootContext();
- scope.result = FunctionObject::createScriptFunction(global, vmf);
+ return Encode(FunctionObject::createScriptFunction(global, vmf));
}
// 15.3.1: This is equivalent to new Function(...)
-void FunctionCtor::call(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue FunctionCtor::call(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
- construct(that, scope, callData);
+ return callAsConstructor(f, argv, argc);
}
DEFINE_OBJECT_VTABLE(FunctionPrototype);
@@ -263,152 +263,139 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
}
-void FunctionPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue FunctionPrototype::method_toString(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
FunctionObject *fun = callData->thisObject.as<FunctionObject>();
if (!fun)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
- scope.result = scope.engine->newString(QStringLiteral("function() { [code] }"));
+ return Encode(v4->newString(QStringLiteral("function() { [code] }")));
}
-void FunctionPrototype::method_apply(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue FunctionPrototype::method_apply(const BuiltinFunction *b, CallData *callData)
{
- FunctionObject *o = callData->thisObject.as<FunctionObject>();
+ ExecutionEngine *v4 = b->engine();
+ callData->function = callData->thisObject;
+ FunctionObject *o = callData->function.as<FunctionObject>();
if (!o)
- THROW_TYPE_ERROR();
-
- ScopedValue arg(scope, callData->argument(1));
-
- ScopedObject arr(scope, arg);
-
- quint32 len;
- if (!arr) {
- len = 0;
- if (!arg->isNullOrUndefined())
- THROW_TYPE_ERROR();
- } else {
- len = arr->getLength();
- }
-
- ScopedCallData cData(scope, len);
-
- if (len) {
- if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
- QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>();
- int l = qMin(len, (uint)a->d()->context->callData->argc);
- memcpy(cData->args, a->d()->context->callData->args, l*sizeof(Value));
- for (quint32 i = l; i < len; ++i)
- cData->args[i] = Primitive::undefinedValue();
- } else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
- auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
- uint alen = sad ? sad->values.size : 0;
- if (alen > len)
- alen = len;
- for (uint i = 0; i < alen; ++i)
- cData->args[i] = sad->data(i);
- for (quint32 i = alen; i < len; ++i)
- cData->args[i] = Primitive::undefinedValue();
- } else {
- for (quint32 i = 0; i < len; ++i)
- cData->args[i] = arr->getIndexed(i);
+ return v4->throwTypeError();
+ callData->thisObject = callData->argument(0);
+ callData->accumulator = callData->argument(1);
+
+ if (callData->accumulator.isObject()) {
+ Object *arr = static_cast<Object *>(&callData->accumulator);
+ uint len = arr->getLength();
+ callData->setArgc(len);
+
+ v4->jsStackTop = callData->args + len;
+ if (len) {
+ if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
+ QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>();
+ int l = qMin(len, (uint)a->d()->context->argc());
+ memcpy(callData->args, a->d()->context->args(), l*sizeof(Value));
+ for (quint32 i = l; i < len; ++i)
+ callData->args[i] = Primitive::undefinedValue();
+ } else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
+ auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
+ uint alen = sad ? sad->values.size : 0;
+ if (alen > len)
+ alen = len;
+ for (uint i = 0; i < alen; ++i)
+ callData->args[i] = sad->data(i);
+ for (quint32 i = alen; i < len; ++i)
+ callData->args[i] = Primitive::undefinedValue();
+ } else {
+ for (quint32 i = 0; i < len; ++i)
+ callData->args[i] = arr->getIndexed(i);
+ }
}
+ } else if (!callData->accumulator.isNullOrUndefined()) {
+ return v4->throwTypeError();
+ } else {
+ callData->setArgc(0);
+ v4->jsStackTop = callData->args;
}
- cData->thisObject = callData->argument(0);
- o->call(scope, cData);
+ return o->call(&callData->thisObject, callData->args, callData->argc());
}
-void FunctionPrototype::method_call(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue FunctionPrototype::method_call(const BuiltinFunction *b, CallData *callData)
{
- FunctionObject *o = callData->thisObject.as<FunctionObject>();
- if (!o)
- THROW_TYPE_ERROR();
+ ExecutionEngine *engine = b->engine();
+ if (!callData->thisObject.isFunctionObject())
+ return engine->throwTypeError();
- ScopedCallData cData(scope, callData->argc ? callData->argc - 1 : 0);
- if (callData->argc) {
- for (int i = 1; i < callData->argc; ++i)
- cData->args[i - 1] = callData->args[i];
- }
- cData->thisObject = callData->argument(0);
+ Q_ASSERT(engine->jsStackTop == callData->args + callData->argc());
- o->call(scope, cData);
+ callData->function = callData->thisObject;
+ callData->thisObject = callData->argc() ? callData->args[0] : Primitive::undefinedValue();
+ if (callData->argc()) {
+ callData->setArgc(callData->argc() - 1);
+ for (int i = 0, ei = callData->argc(); i < ei; ++i)
+ callData->args[i] = callData->args[i + 1];
+ --engine->jsStackTop;
+ }
+ return static_cast<FunctionObject &>(callData->function).call(&callData->thisObject, callData->args, callData->argc());
}
-void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue FunctionPrototype::method_bind(const BuiltinFunction *b, CallData *callData)
{
+ QV4::Scope scope(b);
FunctionObject *target = callData->thisObject.as<FunctionObject>();
if (!target)
- THROW_TYPE_ERROR();
+ return scope.engine->throwTypeError();
ScopedValue boundThis(scope, callData->argument(0));
Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0);
- if (callData->argc > 1) {
- boundArgs = MemberData::allocate(scope.engine, callData->argc - 1);
- boundArgs->d()->values.size = callData->argc - 1;
- for (uint i = 0; i < static_cast<uint>(callData->argc - 1); ++i)
+ if (callData->argc() > 1) {
+ boundArgs = MemberData::allocate(scope.engine, callData->argc() - 1);
+ boundArgs->d()->values.size = callData->argc() - 1;
+ for (uint i = 0, ei = static_cast<uint>(callData->argc() - 1); i < ei; ++i)
boundArgs->set(scope.engine, i, callData->args[i + 1]);
}
ExecutionContext *global = scope.engine->rootContext();
- scope.result = BoundFunction::create(global, target, boundThis, boundArgs);
+ return BoundFunction::create(global, target, boundThis, boundArgs)->asReturnedValue();
}
DEFINE_OBJECT_VTABLE(ScriptFunction);
-void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue ScriptFunction::callAsConstructor(const FunctionObject *fo, const Value *argv, int argc)
{
- ExecutionEngine *v4 = scope.engine;
- if (Q_UNLIKELY(v4->hasException)) {
- scope.result = Encode::undefined();
- return;
- }
- CHECK_STACK_LIMITS(v4, scope);
-
- ExecutionContextSaver ctxSaver(scope);
-
- Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that));
+ ExecutionEngine *v4 = fo->engine();
+ const ScriptFunction *f = static_cast<const ScriptFunction *>(fo);
+ Scope scope(v4);
+ JSCallData callData(scope, argc, argv);
+ CallData *cData = callData.callData(f);
InternalClass *ic = f->classForConstructor();
- ScopedObject proto(scope, ic->prototype);
- ScopedObject obj(scope, v4->newObject(ic, proto));
- callData->thisObject = obj.asReturnedValue();
+ cData->context = f->scope();
+ cData->thisObject = v4->memoryManager->allocObject<Object>(ic);
QV4::Function *v4Function = f->function();
Q_ASSERT(v4Function);
- ScopedContext c(scope, f->scope());
- if (v4Function->canUseSimpleCall)
- c->simpleCall(scope, callData, v4Function);
- else
- c->call(scope, callData, v4Function, f);
+ ReturnedValue result = v4Function->call(cData);
- if (Q_UNLIKELY(v4->hasException)) {
- scope.result = Encode::undefined();
- } else if (!scope.result.isObject()) {
- scope.result = obj.asReturnedValue();
- }
+ if (Q_UNLIKELY(v4->hasException))
+ return Encode::undefined();
+ else if (!Value::fromReturnedValue(result).isObject())
+ return cData->thisObject.asReturnedValue();
+ return result;
}
-void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue ScriptFunction::call(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc)
{
- ExecutionEngine *v4 = scope.engine;
- if (Q_UNLIKELY(v4->hasException)) {
- scope.result = Encode::undefined();
- return;
- }
- CHECK_STACK_LIMITS(v4, scope);
-
- Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that));
+ const ScriptFunction *f = static_cast<const ScriptFunction *>(fo);
+ Scope scope(f->engine());
+ JSCallData callData(scope, argc, argv, thisObject);
+ CallData *cData = callData.callData(f);
+ cData->context = f->scope();
QV4::Function *v4Function = f->function();
Q_ASSERT(v4Function);
-
- ScopedContext c(scope, f->scope());
- if (v4Function->canUseSimpleCall)
- c->simpleCall(scope, callData, v4Function);
- else
- c->call(scope, callData, v4Function, f);
+ return v4Function->call(cData);
}
void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function)
@@ -429,7 +416,7 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length);
setProperty(s.engine, Index_Length, Primitive::fromInt32(f->formalParameterCount()));
- if (scope->d()->strictMode) {
+ if (function->isStrict()) {
ScopedProperty pd(s);
pd->value = s.engine->thrower();
pd->set = s.engine->thrower();
@@ -455,49 +442,23 @@ InternalClass *ScriptFunction::classForConstructor() const
DEFINE_OBJECT_VTABLE(BuiltinFunction);
-void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *))
+void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(const QV4::BuiltinFunction *, CallData *))
{
Heap::FunctionObject::init(scope, name);
this->code = code;
}
-void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *)
+ReturnedValue BuiltinFunction::callAsConstructor(const QV4::FunctionObject *f, const Value *, int)
{
- scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
+ return f->engine()->throwTypeError();
}
-void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue BuiltinFunction::call(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc)
{
- 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);
- ExecutionEngine *v4 = scope.engine;
- if (v4->hasException) {
- scope.result = Encode::undefined();
- return;
- }
- CHECK_STACK_LIMITS(v4, scope);
-
- ExecutionContextSaver ctxSaver(scope);
-
- SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext();
- ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
- ctx->callData = callData;
- v4->pushContext(ctx);
- Q_ASSERT(v4->current == ctx);
-
- scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index);
- v4->memoryManager->freeSimpleCallContext();
+ const BuiltinFunction *f = static_cast<const BuiltinFunction *>(fo);
+ Scope scope(f->engine());
+ JSCallData callData(scope, argc, argv, thisObject);
+ return f->d()->code(f, callData.callData());
}
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
@@ -530,43 +491,43 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject
f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
-void BoundFunction::call(const Managed *that, Scope &scope, CallData *dd)
+ReturnedValue BoundFunction::call(const FunctionObject *fo, const Value *, const Value *argv, int argc)
{
- const BoundFunction *f = static_cast<const BoundFunction *>(that);
- if (scope.hasException()) {
- scope.result = Encode::undefined();
- return;
- }
+ const BoundFunction *f = static_cast<const BoundFunction *>(fo);
+ Scope scope(f->engine());
+
+ if (scope.hasException())
+ return Encode::undefined();
Scoped<MemberData> boundArgs(scope, f->boundArgs());
- ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc);
- callData->thisObject = f->boundThis();
- Value *argp = callData->args;
+ ScopedFunctionObject target(scope, f->target());
+ JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc);
+ *jsCallData->thisObject = f->boundThis();
+ Value *argp = jsCallData->args;
if (boundArgs) {
memcpy(argp, boundArgs->data(), boundArgs->size()*sizeof(Value));
argp += boundArgs->size();
}
- memcpy(argp, dd->args, dd->argc*sizeof(Value));
- ScopedFunctionObject t(scope, f->target());
- t->call(scope, callData);
+ memcpy(argp, argv, argc*sizeof(Value));
+ return target->call(jsCallData);
}
-void BoundFunction::construct(const Managed *that, Scope &scope, CallData *dd)
+ReturnedValue BoundFunction::callAsConstructor(const FunctionObject *fo, const Value *argv, int argc)
{
- const BoundFunction *f = static_cast<const BoundFunction *>(that);
- if (scope.hasException()) {
- scope.result = Encode::undefined();
- return;
- }
+ const BoundFunction *f = static_cast<const BoundFunction *>(fo);
+ Scope scope(f->engine());
+
+ if (scope.hasException())
+ return Encode::undefined();
Scoped<MemberData> boundArgs(scope, f->boundArgs());
- ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc);
- Value *argp = callData->args;
+ ScopedFunctionObject target(scope, f->target());
+ JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc);
+ Value *argp = jsCallData->args;
if (boundArgs) {
memcpy(argp, boundArgs->data(), boundArgs->size()*sizeof(Value));
argp += boundArgs->size();
}
- memcpy(argp, dd->args, dd->argc*sizeof(Value));
- ScopedFunctionObject t(scope, f->target());
- t->construct(scope, callData);
+ memcpy(argp, argv, argc*sizeof(Value));
+ return target->callAsConstructor(jsCallData);
}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 6ce5734b6d..3fd0fbeec8 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -62,12 +62,20 @@ struct QQmlSourceLocation;
namespace QV4 {
struct BuiltinFunction;
+struct IndexedBuiltinFunction;
+struct JSCallData;
+
+typedef ReturnedValue (*jsCallFunction)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+typedef ReturnedValue (*jsConstructFunction)(const FunctionObject *, const Value *argv, int argc);
namespace Heap {
+
#define FunctionObjectMembers(class, Member) \
Member(class, Pointer, ExecutionContext *, scope) \
- Member(class, NoMark, Function *, function)
+ Member(class, NoMark, Function *, function) \
+ Member(class, NoMark, jsCallFunction, jsCall) \
+ Member(class, NoMark, jsConstructFunction, jsConstruct)
DECLARE_HEAP_OBJECT(FunctionObject, Object) {
DECLARE_MARK_TABLE(FunctionObject);
@@ -96,19 +104,13 @@ struct FunctionPrototype : FunctionObject {
void init();
};
-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 *);
+ void init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(const QV4::BuiltinFunction *, CallData *));
+ ReturnedValue (*code)(const QV4::BuiltinFunction *, 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);
+struct IndexedBuiltinFunction : BuiltinFunction {
+ inline void init(QV4::ExecutionContext *scope, uint index, ReturnedValue (*code)(const QV4::BuiltinFunction *, CallData *));
uint index;
};
@@ -154,10 +156,16 @@ struct Q_QML_EXPORT FunctionObject: Object {
void init(String *name, bool createProto);
- using Object::construct;
- using Object::call;
- static void construct(const Managed *that, Scope &scope, CallData *);
- static void call(const Managed *that, Scope &scope, CallData *d);
+ inline ReturnedValue callAsConstructor(const JSCallData &data) const;
+ ReturnedValue callAsConstructor(const Value *argv, int argc) const {
+ return d()->jsConstruct(this, argv, argc);
+ }
+ inline ReturnedValue call(const JSCallData &data) const;
+ ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const {
+ return d()->jsCall(this, thisObject, argv, argc);
+ }
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
@@ -178,8 +186,8 @@ struct FunctionCtor: FunctionObject
{
V4_OBJECT2(FunctionCtor, FunctionObject)
- static void construct(const Managed *that, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
struct FunctionPrototype: FunctionObject
@@ -188,43 +196,36 @@ struct FunctionPrototype: FunctionObject
void init(ExecutionEngine *engine, Object *ctor);
- static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_apply(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_call(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_bind(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_apply(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_call(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_bind(const BuiltinFunction *, CallData *callData);
};
struct Q_QML_EXPORT BuiltinFunction : FunctionObject {
V4_OBJECT2(BuiltinFunction, FunctionObject)
V4_INTERNALCLASS(BuiltinFunction)
- static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *))
+ static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(const BuiltinFunction *, CallData *))
{
return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code);
}
- static void construct(const Managed *, Scope &scope, CallData *);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
-struct IndexedBuiltinFunction: FunctionObject
+struct IndexedBuiltinFunction: BuiltinFunction
{
- V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
-
- static void construct(const Managed *m, Scope &scope, CallData *)
- {
- scope.result = static_cast<const IndexedBuiltinFunction *>(m)->engine()->throwTypeError();
- }
-
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ V4_OBJECT2(IndexedBuiltinFunction, BuiltinFunction)
};
void Heap::IndexedBuiltinFunction::init(QV4::ExecutionContext *scope, uint index,
- ReturnedValue (*code)(QV4::CallContext *ctx, uint index))
+ ReturnedValue (*code)(const QV4::BuiltinFunction *, CallData *))
{
Heap::FunctionObject::init(scope);
- this->index = index;
this->code = code;
+ this->index = index;
}
@@ -232,8 +233,8 @@ struct ScriptFunction : FunctionObject {
V4_OBJECT2(ScriptFunction, FunctionObject)
V4_INTERNALCLASS(ScriptFunction)
- static void construct(const Managed *, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
InternalClass *classForConstructor() const;
};
@@ -251,8 +252,8 @@ struct BoundFunction: FunctionObject {
Value boundThis() const { return d()->boundThis; }
Heap::MemberData *boundArgs() const { return d()->boundArgs; }
- static void construct(const Managed *, Scope &scope, CallData *d);
- static void call(const Managed *that, Scope &scope, CallData *dd);
+ static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 8769519a59..6bdeda3313 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -147,6 +147,12 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+namespace Compiler {
+ struct Module;
+ struct Context;
+ struct JSUnitGenerator;
+}
+
namespace Heap {
struct Base;
struct MemberData;
@@ -157,7 +163,6 @@ namespace Heap {
struct ObjectPrototype;
struct ExecutionContext;
- struct GlobalContext;
struct CallContext;
struct ScriptFunction;
@@ -182,12 +187,12 @@ namespace Heap {
}
class MemoryManager;
+class ExecutableAllocator;
struct String;
struct Object;
struct ObjectPrototype;
struct ObjectIterator;
struct ExecutionContext;
-struct GlobalContext;
struct CallContext;
struct ScriptFunction;
struct InternalClass;
@@ -243,12 +248,6 @@ struct IdentifierTable;
class RegExpCache;
class MultiplyWrappedQObjectMap;
-namespace Global {
- enum {
- ReservedArgumentCount = 6
- };
-}
-
enum PropertyFlag {
Attr_Data = 0,
Attr_Accessor = 0x1,
@@ -349,11 +348,11 @@ struct PropertyAttributes
}
};
-struct StackFrame {
+struct Q_QML_EXPORT StackFrame {
QString source;
QString function;
- int line;
- int column;
+ int line = -1;
+ int column = -1;
};
typedef QVector<StackFrame> StackTrace;
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 0916e8e110..a015461c47 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -47,12 +47,12 @@
#include "qv4script_p.h"
#include "qv4scopedvalue_p.h"
#include "qv4string_p.h"
+#include "qv4jscall_p.h"
#include <private/qqmljsengine_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
-#include <qv4jsir_p.h>
#include <qv4codegen_p.h>
#include "private/qlocale_tools_p.h"
#include "private/qtools_p.h"
@@ -338,72 +338,68 @@ void Heap::EvalFunction::init(QV4::ExecutionContext *scope)
f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(1));
}
-void EvalFunction::evalCall(Scope &scope, CallData *callData, bool directCall) const
+ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc, bool directCall) const
{
- if (callData->argc < 1) {
- scope.result = Encode::undefined();
- return;
- }
+ if (argc < 1)
+ return Encode::undefined();
ExecutionEngine *v4 = engine();
- ExecutionContextSaver ctxSaver(scope);
+ bool isStrict = v4->currentStackFrame->v4Function->isStrict();
- ExecutionContext *currentContext = v4->currentContext;
- ExecutionContext *ctx = currentContext;
+ Scope scope(v4);
+ ScopedContext ctx(scope, v4->currentContext());
if (!directCall) {
- // the context for eval should be the global scope, so we fake a root
- // context
- ctx = v4->pushGlobalContext();
+ // the context for eval should be the global scope
+ ctx = v4->rootContext();
}
- String *scode = callData->args[0].stringValue();
- if (!scode) {
- scope.result = callData->args[0].asReturnedValue();
- return;
- }
+ String *scode = argv[0].stringValue();
+ if (!scode)
+ return argv[0].asReturnedValue();
const QString code = scode->toQString();
- bool inheritContext = !ctx->d()->strictMode;
+ bool inheritContext = !ctx->d()->v4Function->isStrict();
- Script script(ctx, code, QStringLiteral("eval code"));
- script.strictMode = (directCall && currentContext->d()->strictMode);
+ Script script(ctx, QV4::Compiler::EvalCode, code, QStringLiteral("eval code"));
+ script.strictMode = (directCall && isStrict);
script.inheritContext = inheritContext;
script.parse();
- if (v4->hasException) {
- scope.result = Encode::undefined();
- return;
- }
+ if (v4->hasException)
+ return Encode::undefined();
Function *function = script.function();
- if (!function) {
- scope.result = Encode::undefined();
- return;
- }
+ if (!function)
+ return Encode::undefined();
- if (function->isStrict() || (ctx->d()->strictMode)) {
+ if (function->isStrict() || (ctx->d()->v4Function->isStrict())) {
ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function));
- ScopedCallData callData(scope, 0);
- callData->thisObject = ctx->thisObject();
- e->call(scope, callData);
- return;
+ JSCallData jsCallData(scope, 0);
+ if (directCall)
+ *jsCallData->thisObject = scope.engine->currentStackFrame->thisObject();
+ else
+ *jsCallData->thisObject = scope.engine->globalObject;
+ return e->call(jsCallData);
}
ContextStateSaver stateSaver(scope, ctx);
- // set the correct strict mode flag on the context
- ctx->d()->strictMode = false;
- ctx->d()->compilationUnit = function->compilationUnit;
- ctx->d()->constantTable = function->compilationUnit->constants;
+ // set the correct v4 function for the context
+ ctx->d()->v4Function = function;
+
+ JSCallData jsCallData(scope);
+ *jsCallData->thisObject = scope.engine->currentStackFrame->thisObject();
+ CallData *cData = jsCallData.callData();
+ cData->context = *ctx;
- scope.result = Q_V4_PROFILE(ctx->engine(), function);
+ return function->call(cData);
}
-void EvalFunction::call(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue EvalFunction::call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
{
// indirect call
- static_cast<const EvalFunction *>(that)->evalCall(scope, callData, false);
+ return static_cast<const EvalFunction *>(f)->evalCall(thisObject, argv, argc, false);
}
@@ -424,8 +420,9 @@ static inline int toInt(const QChar &qc, int R)
}
// parseInt [15.1.2.2]
-void GlobalFunctions::method_parseInt(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue GlobalFunctions::method_parseInt(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedValue inputString(scope, callData->argument(0));
ScopedValue radix(scope, callData->argument(1));
int R = radix->isUndefined() ? 0 : radix->toInt32();
@@ -504,8 +501,9 @@ void GlobalFunctions::method_parseInt(const BuiltinFunction *, Scope &scope, Cal
}
// parseFloat [15.1.2.3]
-void GlobalFunctions::method_parseFloat(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue GlobalFunctions::method_parseFloat(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
// [15.1.2.3] step by step:
ScopedString inputString(scope, callData->argument(0), ScopedString::Convert);
CHECK_EXCEPTION();
@@ -530,9 +528,9 @@ void GlobalFunctions::method_parseFloat(const BuiltinFunction *, Scope &scope, C
}
/// isNaN [15.1.2.4]
-void GlobalFunctions::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue GlobalFunctions::method_isNaN(const BuiltinFunction *, CallData *callData)
{
- if (!callData->argc)
+ if (!callData->argc())
// undefined gets converted to NaN
RETURN_RESULT(Encode(true));
@@ -544,9 +542,9 @@ void GlobalFunctions::method_isNaN(const BuiltinFunction *, Scope &scope, CallDa
}
/// isFinite [15.1.2.5]
-void GlobalFunctions::method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue GlobalFunctions::method_isFinite(const BuiltinFunction *, CallData *callData)
{
- if (!callData->argc)
+ if (!callData->argc())
// undefined gets converted to NaN
RETURN_RESULT(Encode(false));
@@ -558,87 +556,97 @@ void GlobalFunctions::method_isFinite(const BuiltinFunction *, Scope &scope, Cal
}
/// decodeURI [15.1.3.1]
-void GlobalFunctions::method_decodeURI(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue GlobalFunctions::method_decodeURI(const BuiltinFunction *b, CallData *callData)
{
- if (callData->argc == 0)
+ if (callData->argc() == 0)
RETURN_UNDEFINED();
+ ExecutionEngine *v4 = b->engine();
QString uriString = callData->args[0].toQString();
bool ok;
QString out = decode(uriString, DecodeNonReserved, &ok);
if (!ok) {
+ Scope scope(v4);
ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
RETURN_RESULT(scope.engine->throwURIError(s));
}
- RETURN_RESULT(scope.engine->newString(out));
+ RETURN_RESULT(v4->newString(out));
}
/// decodeURIComponent [15.1.3.2]
-void GlobalFunctions::method_decodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue GlobalFunctions::method_decodeURIComponent(const BuiltinFunction *b, CallData *callData)
{
- if (callData->argc == 0)
+ if (callData->argc() == 0)
RETURN_UNDEFINED();
+ ExecutionEngine *v4 = b->engine();
QString uriString = callData->args[0].toQString();
bool ok;
QString out = decode(uriString, DecodeAll, &ok);
if (!ok) {
+ Scope scope(v4);
ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
RETURN_RESULT(scope.engine->throwURIError(s));
}
- RETURN_RESULT(scope.engine->newString(out));
+ RETURN_RESULT(v4->newString(out));
}
/// encodeURI [15.1.3.3]
-void GlobalFunctions::method_encodeURI(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue GlobalFunctions::method_encodeURI(const BuiltinFunction *b, CallData *callData)
{
- if (callData->argc == 0)
+ if (callData->argc() == 0)
RETURN_UNDEFINED();
+ ExecutionEngine *v4 = b->engine();
QString uriString = callData->args[0].toQString();
bool ok;
QString out = encode(uriString, uriUnescapedReserved, &ok);
if (!ok) {
+ Scope scope(v4);
ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
RETURN_RESULT(scope.engine->throwURIError(s));
}
- RETURN_RESULT(scope.engine->newString(out));
+ RETURN_RESULT(v4->newString(out));
}
/// encodeURIComponent [15.1.3.4]
-void GlobalFunctions::method_encodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue GlobalFunctions::method_encodeURIComponent(const BuiltinFunction *b, CallData *callData)
{
- if (callData->argc == 0)
+ if (callData->argc() == 0)
RETURN_UNDEFINED();
+ ExecutionEngine *v4 = b->engine();
QString uriString = callData->args[0].toQString();
bool ok;
QString out = encode(uriString, uriUnescaped, &ok);
if (!ok) {
+ Scope scope(v4);
ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
RETURN_RESULT(scope.engine->throwURIError(s));
}
- RETURN_RESULT(scope.engine->newString(out));
+ RETURN_RESULT(v4->newString(out));
}
-void GlobalFunctions::method_escape(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue GlobalFunctions::method_escape(const BuiltinFunction *b, CallData *callData)
{
- if (!callData->argc)
- RETURN_RESULT(scope.engine->newString(QStringLiteral("undefined")));
+ ExecutionEngine *v4 = b->engine();
+ if (!callData->argc())
+ RETURN_RESULT(v4->newString(QStringLiteral("undefined")));
QString str = callData->args[0].toQString();
- RETURN_RESULT(scope.engine->newString(escape(str)));
+ RETURN_RESULT(v4->newString(escape(str)));
}
-void GlobalFunctions::method_unescape(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue GlobalFunctions::method_unescape(const BuiltinFunction *b, CallData *callData)
{
- if (!callData->argc)
- RETURN_RESULT(scope.engine->newString(QStringLiteral("undefined")));
+ ExecutionEngine *v4 = b->engine();
+ if (!callData->argc())
+ RETURN_RESULT(v4->newString(QStringLiteral("undefined")));
QString str = callData->args[0].toQString();
- RETURN_RESULT(scope.engine->newString(unescape(str)));
+ RETURN_RESULT(v4->newString(unescape(str)));
}
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index 273f1ba7ea..af72d3af2f 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -69,23 +69,23 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject
{
V4_OBJECT2(EvalFunction, FunctionObject)
- void evalCall(Scope &scope, CallData *callData, bool directCall) const;
+ ReturnedValue evalCall(const Value *thisObject, const Value *argv, int argc, bool directCall) const;
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
struct GlobalFunctions
{
- static void method_parseInt(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_parseFloat(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_decodeURI(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_decodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_encodeURI(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_encodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_escape(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_unescape(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_parseInt(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_parseFloat(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_isNaN(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_isFinite(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_decodeURI(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_decodeURIComponent(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_encodeURI(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_encodeURIComponent(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_escape(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_unescape(const BuiltinFunction *, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 1edb7d3914..3e04ed63df 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -39,6 +39,7 @@
#include "qv4include_p.h"
#include "qv4scopedvalue_p.h"
+#include "qv4jscall_p.h"
#include <QtQml/qjsengine.h>
#if QT_CONFIG(qml_network)
@@ -118,10 +119,10 @@ void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status)
if (!f)
return;
- QV4::ScopedCallData callData(scope, 1);
- callData->thisObject = v4->globalObject->asReturnedValue();
- callData->args[0] = status;
- f->call(scope, callData);
+ QV4::JSCallData jsCallData(scope, 1);
+ *jsCallData->thisObject = v4->globalObject->asReturnedValue();
+ jsCallData->args[0] = status;
+ f->call(jsCallData);
if (scope.hasException())
scope.engine->catchException();
}
@@ -195,9 +196,10 @@ void QV4Include::finished()
/*
Documented in qv8engine.cpp
*/
-void QV4Include::method_include(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+QV4::ReturnedValue QV4Include::method_include(const QV4::BuiltinFunction *b, QV4::CallData *callData)
{
- if (!callData->argc)
+ QV4::Scope scope(b);
+ if (!callData->argc())
RETURN_UNDEFINED();
QQmlContextData *context = scope.engine->callingQmlContext();
@@ -206,7 +208,7 @@ void QV4Include::method_include(const QV4::BuiltinFunction *, QV4::Scope &scope,
RETURN_RESULT(scope.engine->throwError(QString::fromUtf8("Qt.include(): Can only be called from JavaScript files")));
QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue());
- if (callData->argc >= 2 && callData->args[1].as<QV4::FunctionObject>())
+ if (callData->argc() >= 2 && callData->args[1].as<QV4::FunctionObject>())
callbackFunction = callData->args[1];
#if QT_CONFIG(qml_network)
@@ -260,13 +262,13 @@ void QV4Include::method_include(const QV4::BuiltinFunction *, QV4::Scope &scope,
callback(callbackFunction, result);
}
- scope.result = result;
#else
QV4::ScopedValue result(scope);
result = resultValue(scope.engine, NetworkError);
callback(callbackFunction, result);
- scope.result = result;
#endif
+
+ return result->asReturnedValue();
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h
index 5908d6bfde..68537ba2e8 100644
--- a/src/qml/jsruntime/qv4include_p.h
+++ b/src/qml/jsruntime/qv4include_p.h
@@ -77,7 +77,7 @@ public:
Exception = 3
};
- static void method_include(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static QV4::ReturnedValue method_include(const QV4::BuiltinFunction *, QV4::CallData *callData);
private Q_SLOTS:
void finished();
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
new file mode 100644
index 0000000000..6d641bf9c5
--- /dev/null
+++ b/src/qml/jsruntime/qv4jscall_p.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4JSCALL_H
+#define QV4JSCALL_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qv4object_p.h"
+#include "qv4function_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4context_p.h"
+#include "qv4scopedvalue_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct JSCallData {
+ JSCallData(const Scope &scope, int argc = 0, const Value *argv = 0, const Value *thisObject = 0)
+ : scope(scope), argc(argc)
+ {
+ if (thisObject)
+ this->thisObject = const_cast<Value *>(thisObject);
+ else
+ this->thisObject = scope.alloc(1);
+ if (argv)
+ this->args = const_cast<Value *>(argv);
+ else
+ this->args = scope.alloc(argc);
+ }
+
+ JSCallData *operator->() {
+ return this;
+ }
+
+ CallData *callData(const FunctionObject *f = nullptr) const {
+ int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc;
+ CallData *ptr = reinterpret_cast<CallData *>(scope.engine->jsStackTop);
+ scope.engine->jsStackTop += size;
+ ptr->function = Encode::undefined();
+ ptr->context = Encode::undefined();
+ ptr->accumulator = Encode::undefined();
+ ptr->thisObject = thisObject->asReturnedValue();
+ ptr->setArgc(argc);
+ if (argc)
+ memcpy(ptr->args, args, argc*sizeof(Value));
+ if (f)
+ ptr->function = f->asReturnedValue();
+ return ptr;
+ }
+ const Scope &scope;
+ int argc;
+ Value *args;
+ Value *thisObject;
+};
+
+inline
+ReturnedValue FunctionObject::callAsConstructor(const JSCallData &data) const
+{
+ return d()->jsConstruct(this, data.args, data.argc);
+}
+
+inline
+ReturnedValue FunctionObject::call(const JSCallData &data) const
+{
+ return d()->jsCall(this, data.thisObject, data.args, data.argc);
+}
+
+
+struct ScopedStackFrame {
+ Scope &scope;
+ CppStackFrame frame;
+
+ ScopedStackFrame(Scope &scope, Heap::ExecutionContext *context)
+ : scope(scope)
+ {
+ frame.parent = scope.engine->currentStackFrame;
+ if (!context)
+ return;
+ frame.jsFrame = reinterpret_cast<CallData *>(scope.alloc(sizeof(CallData)/sizeof(Value)));
+ frame.jsFrame->context = context;
+ frame.v4Function = frame.parent ? frame.parent->v4Function : 0;
+ scope.engine->currentStackFrame = &frame;
+ }
+ ~ScopedStackFrame() {
+ scope.engine->currentStackFrame = frame.parent;
+ }
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4JSCALL_H
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 0f021c8bd0..5e580b8b4d 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -46,6 +46,7 @@
#include <qv4runtime_p.h>
#include <qv4variantobject_p.h>
#include "qv4string_p.h"
+#include "qv4jscall_p.h"
#include <qstack.h>
#include <qstringlist.h>
@@ -689,57 +690,57 @@ static QString quote(const QString &str)
QString Stringify::Str(const QString &key, const Value &v)
{
Scope scope(v4);
- scope.result = v;
- ScopedObject o(scope, scope.result);
+ ScopedValue value(scope, v);
+ ScopedObject o(scope, value);
if (o) {
ScopedString s(scope, v4->newString(QStringLiteral("toJSON")));
ScopedFunctionObject toJSON(scope, o->get(s));
if (!!toJSON) {
- ScopedCallData callData(scope, 1);
- callData->thisObject = scope.result;
- callData->args[0] = v4->newString(key);
- toJSON->call(scope, callData);
+ JSCallData jsCallData(scope, 1);
+ *jsCallData->thisObject = value;
+ jsCallData->args[0] = v4->newString(key);
+ value = toJSON->call(jsCallData);
}
}
if (replacerFunction) {
ScopedObject holder(scope, v4->newObject());
- holder->put(scope.engine->id_empty(), scope.result);
- ScopedCallData callData(scope, 2);
- callData->args[0] = v4->newString(key);
- callData->args[1] = scope.result;
- callData->thisObject = holder;
- replacerFunction->call(scope, callData);
+ holder->put(scope.engine->id_empty(), value);
+ JSCallData jsCallData(scope, 2);
+ jsCallData->args[0] = v4->newString(key);
+ jsCallData->args[1] = value;
+ *jsCallData->thisObject = holder;
+ value = replacerFunction->call(jsCallData);
}
- o = scope.result.asReturnedValue();
+ o = value->asReturnedValue();
if (o) {
if (NumberObject *n = o->as<NumberObject>())
- scope.result = Encode(n->value());
+ value = Encode(n->value());
else if (StringObject *so = o->as<StringObject>())
- scope.result = so->d()->string;
+ value = so->d()->string;
else if (BooleanObject *b = o->as<BooleanObject>())
- scope.result = Encode(b->value());
+ value = Encode(b->value());
}
- if (scope.result.isNull())
+ if (value->isNull())
return QStringLiteral("null");
- if (scope.result.isBoolean())
- return scope.result.booleanValue() ? QStringLiteral("true") : QStringLiteral("false");
- if (String *s = scope.result.stringValue())
- return quote(s->toQString());
-
- if (scope.result.isNumber()) {
- double d = scope.result.toNumber();
- return std::isfinite(d) ? scope.result.toQString() : 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 (const QV4::VariantObject *v = scope.result.as<QV4::VariantObject>()) {
+ if (const QV4::VariantObject *v = value->as<QV4::VariantObject>()) {
return v->d()->data().toString();
}
- o = scope.result.asReturnedValue();
+ o = value->asReturnedValue();
if (o) {
if (!o->as<FunctionObject>()) {
if (o->as<ArrayObject>()) {
@@ -883,25 +884,28 @@ void Heap::JsonObject::init()
}
-void JsonObject::method_parse(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue JsonObject::method_parse(const BuiltinFunction *b, CallData *callData)
{
- ScopedValue v(scope, callData->argument(0));
- QString jtext = v->toQString();
+ ExecutionEngine *v4 = b->engine();
+ QString jtext;
+ if (callData->argc() > 0)
+ jtext = callData->args[0].toQString();
DEBUG << "parsing source = " << jtext;
- JsonParser parser(scope.engine, jtext.constData(), jtext.length());
+ JsonParser parser(v4, jtext.constData(), jtext.length());
QJsonParseError error;
- ScopedValue result(scope, parser.parse(&error));
+ ReturnedValue result = parser.parse(&error);
if (error.error != QJsonParseError::NoError) {
DEBUG << "parse error" << error.errorString();
- RETURN_RESULT(scope.engine->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")));
+ RETURN_RESULT(v4->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")));
}
- scope.result = result;
+ return result;
}
-void JsonObject::method_stringify(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue JsonObject::method_stringify(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
Stringify stringify(scope.engine);
ScopedObject o(scope, callData->argument(1));
@@ -946,7 +950,7 @@ void JsonObject::method_stringify(const BuiltinFunction *, Scope &scope, CallDat
QString result = stringify.Str(QString(), arg0);
if (result.isEmpty() || scope.engine->hasException)
RETURN_UNDEFINED();
- scope.result = scope.engine->newString(result);
+ return Encode(scope.engine->newString(result));
}
diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h
index a73ce1c74e..19dba14aef 100644
--- a/src/qml/jsruntime/qv4jsonobject_p.h
+++ b/src/qml/jsruntime/qv4jsonobject_p.h
@@ -88,8 +88,8 @@ private:
typedef QSet<ObjectItem> V4ObjectSet;
public:
- static void method_parse(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_stringify(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_parse(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_stringify(const BuiltinFunction *, CallData *callData);
static ReturnedValue fromJsonValue(ExecutionEngine *engine, const QJsonValue &value);
static ReturnedValue fromJsonObject(ExecutionEngine *engine, const QJsonObject &object);
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index afadf59bd5..ec3482c1e9 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qv4lookup_p.h"
#include "qv4functionobject_p.h"
-#include "qv4scopedvalue_p.h"
+#include "qv4jscall_p.h"
#include "qv4string_p.h"
#include <private/qv4identifiertable_p.h>
@@ -50,7 +50,7 @@ using namespace QV4;
ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttributes *attrs)
{
ExecutionEngine *engine = o->engine();
- Identifier *name = engine->identifierTable->identifier(engine->current->compilationUnit->runtimeStrings[nameIndex]);
+ Identifier *name = engine->identifierTable->identifier(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
int i = 0;
Heap::Object *obj = o->d();
while (i < Size && obj) {
@@ -86,7 +86,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
{
Heap::Object *obj = thisObject->d();
ExecutionEngine *engine = thisObject->engine();
- Identifier *name = engine->identifierTable->identifier(engine->current->compilationUnit->runtimeStrings[nameIndex]);
+ Identifier *name = engine->identifierTable->identifier(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
int i = 0;
while (i < Size && obj) {
classList[i] = obj->internalClass;
@@ -117,140 +117,6 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
return Primitive::emptyValue().asReturnedValue();
}
-ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
-{
- uint idx;
- if (object.isObject() && index.asArrayIndex(idx)) {
- l->indexedGetter = indexedGetterObjectInt;
- return indexedGetterObjectInt(l, engine, object, index);
- }
- return indexedGetterFallback(l, engine, object, index);
-}
-
-ReturnedValue Lookup::indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
-{
- Q_UNUSED(l);
- Scope scope(engine);
- uint idx = 0;
- bool isInt = index.asArrayIndex(idx);
-
- ScopedObject o(scope, object);
- if (!o) {
- if (isInt) {
- if (const String *str = object.as<String>()) {
- if (idx >= (uint)str->toQString().length()) {
- return Encode::undefined();
- }
- const QString s = str->toQString().mid(idx, 1);
- return scope.engine->newString(s)->asReturnedValue();
- }
- }
-
- if (object.isNullOrUndefined()) {
- QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow());
- return engine->throwTypeError(message);
- }
-
- o = RuntimeHelpers::convertToObject(scope.engine, object);
- if (!o) // type error
- return Encode::undefined();
- }
-
- if (isInt) {
- if (o->d()->arrayData && !o->d()->arrayData->attrs) {
- ScopedValue v(scope, Scoped<ArrayData>(scope, o->arrayData())->get(idx));
- if (!v->isEmpty())
- return v->asReturnedValue();
- }
-
- return o->getIndexed(idx);
- }
-
- ScopedString name(scope, index.toString(scope.engine));
- if (scope.hasException())
- return Encode::undefined();
- return o->get(name);
-
-}
-
-
-ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
-{
- uint idx;
- if (index.asArrayIndex(idx)) {
- if (Heap::Base *b = object.heapObject()) {
- if (b->vtable()->isObject) {
- Heap::Object *o = static_cast<Heap::Object *>(b);
- if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
- Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->values.size)
- if (!s->data(idx).isEmpty())
- return s->data(idx).asReturnedValue();
- }
- }
- }
- }
-
- return indexedGetterFallback(l, engine, object, index);
-}
-
-void Lookup::indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v)
-{
- if (Object *o = object.objectValue()) {
- uint idx;
- if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple && index.asArrayIndex(idx)) {
- l->indexedSetter = indexedSetterObjectInt;
- indexedSetterObjectInt(l, engine, object, index, v);
- return;
- }
- }
- indexedSetterFallback(l, engine, object, index, v);
-}
-
-void Lookup::indexedSetterFallback(Lookup *, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
-{
- Scope scope(engine);
- ScopedObject o(scope, object.toObject(scope.engine));
- if (scope.engine->hasException)
- return;
-
- uint idx;
- if (index.asArrayIndex(idx)) {
- if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
- Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->values.size) {
- s->setData(engine, idx, value);
- return;
- }
- }
- o->putIndexed(idx, value);
- return;
- }
-
- ScopedString name(scope, index.toString(scope.engine));
- o->put(name, value);
-}
-
-void Lookup::indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v)
-{
- uint idx;
- if (index.asArrayIndex(idx)) {
- if (Heap::Base *b = object.heapObject()) {
- if (b->vtable()->isObject) {
- Heap::Object *o = static_cast<Heap::Object *>(b);
- if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
- Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->values.size) {
- s->setData(engine, idx, v);
- return;
- }
- }
- }
- }
- }
- indexedSetterFallback(l, engine, object, index, v);
-}
-
ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (const Object *o = object.as<Object>())
@@ -268,7 +134,7 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va
Q_ASSERT(object.isString());
proto = engine->stringPrototype();
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
if (name->equals(engine->id_length())) {
// special case, as the property is on the object itself
l->getter = stringLengthGetter;
@@ -369,7 +235,7 @@ ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const V
QV4::ScopedObject o(scope, object.toObject(scope.engine));
if (!o)
return Encode::undefined();
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
return o->get(name);
}
@@ -534,10 +400,9 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, ExecutionEngine *engine, const
if (!getter)
return Encode::undefined();
- ScopedCallData callData(scope, 0);
- callData->thisObject = object;
- getter->call(scope, callData);
- return scope.result.asReturnedValue();
+ JSCallData jsCallData(scope);
+ *jsCallData->thisObject = object;
+ return getter->call(jsCallData);
}
}
l->getter = getterFallback;
@@ -557,10 +422,9 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const
if (!getter)
return Encode::undefined();
- ScopedCallData callData(scope, 0);
- callData->thisObject = object;
- getter->call(scope, callData);
- return scope.result.asReturnedValue();
+ JSCallData jsCallData(scope);
+ *jsCallData->thisObject = object;
+ return getter->call(jsCallData);
}
}
l->getter = getterFallback;
@@ -583,10 +447,9 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const
if (!getter)
return Encode::undefined();
- ScopedCallData callData(scope, 0);
- callData->thisObject = object;
- getter->call(scope, callData);
- return scope.result.asReturnedValue();
+ JSCallData jsCallData(scope);
+ *jsCallData->thisObject = object;
+ return getter->call(jsCallData);
}
}
}
@@ -639,10 +502,9 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engin
if (!getter)
return Encode::undefined();
- ScopedCallData callData(scope, 0);
- callData->thisObject = object;
- getter->call(scope, callData);
- return scope.result.asReturnedValue();
+ JSCallData jsCallData(scope);
+ *jsCallData->thisObject = object;
+ return getter->call(jsCallData);
}
}
l->getter = getterGeneric;
@@ -660,10 +522,9 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin
if (!getter)
return Encode::undefined();
- ScopedCallData callData(scope, 0);
- callData->thisObject = object;
- getter->call(scope, callData);
- return scope.result.asReturnedValue();
+ JSCallData jsCallData(scope);
+ *jsCallData->thisObject = object;
+ return getter->call(jsCallData);
}
}
l->getter = getterGeneric;
@@ -720,7 +581,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine)
}
}
Scope scope(engine);
- ScopedString n(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]);
+ ScopedString n(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
return engine->throwReferenceError(n);
}
@@ -780,10 +641,8 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionEngine *engine)
if (!getter)
return Encode::undefined();
- ScopedCallData callData(scope, 0);
- callData->thisObject = Primitive::undefinedValue();
- getter->call(scope, callData);
- return scope.result.asReturnedValue();
+ JSCallData jsCallData(scope);
+ return getter->call(jsCallData);
}
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -799,10 +658,8 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionEngine *engine)
if (!getter)
return Encode::undefined();
- ScopedCallData callData(scope, 0);
- callData->thisObject = Primitive::undefinedValue();
- getter->call(scope, callData);
- return scope.result.asReturnedValue();
+ JSCallData jsCallData(scope);
+ return getter->call(jsCallData);
}
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -821,10 +678,8 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine)
if (!getter)
return Encode::undefined();
- ScopedCallData callData(scope, 0);
- callData->thisObject = Primitive::undefinedValue();
- getter->call(scope, callData);
- return scope.result.asReturnedValue();
+ JSCallData jsCallData(scope);
+ return getter->call(jsCallData);
}
}
}
@@ -832,87 +687,88 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine)
return globalGetterGeneric(l, engine);
}
-void Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+bool Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Scope scope(engine);
ScopedObject o(scope, object);
if (!o) {
o = RuntimeHelpers::convertToObject(scope.engine, object);
if (!o) // type error
- return;
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]);
- o->put(name, value);
- return;
+ return false;
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
+ return o->put(name, value);
}
- o->setLookup(l, value);
+ return o->setLookup(l, value);
}
-void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+bool Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Lookup l1 = *l;
if (Object *o = object.as<Object>()) {
- o->setLookup(l, value);
+ if (!o->setLookup(l, value))
+ return false;
if (l->setter == Lookup::setter0 || l->setter == Lookup::setter0Inline) {
l->setter = setter0setter0;
l->classList[1] = l1.classList[0];
l->index2 = l1.index;
- return;
+ return true;
}
}
l->setter = setterFallback;
- setterFallback(l, engine, object, value);
+ return setterFallback(l, engine, object, value);
}
-void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+bool Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
QV4::Scope scope(engine);
QV4::ScopedObject o(scope, object.toObject(scope.engine));
- if (o) {
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[l->nameIndex]);
- o->put(name, value);
- }
+ if (!o)
+ return false;
+
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
+ return o->put(name, value);
}
-void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+bool Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
o->setProperty(engine, l->index, value);
- return;
+ return true;
}
- setterTwoClasses(l, engine, object, value);
+ return setterTwoClasses(l, engine, object, value);
}
-void Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+bool Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
o->d()->setInlineProperty(engine, l->index, value);
- return;
+ return true;
}
- setterTwoClasses(l, engine, object, value);
+ return setterTwoClasses(l, engine, object, value);
}
-void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+bool Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
Q_ASSERT(!o->prototype());
o->setInternalClass(l->classList[3]);
o->setProperty(l->index, value);
- return;
+ return true;
}
l->setter = setterFallback;
- setterFallback(l, engine, object, value);
+ return setterFallback(l, engine, object, value);
}
-void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+bool Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
@@ -922,15 +778,15 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, co
Q_ASSERT(!p->prototype());
o->setInternalClass(l->classList[3]);
o->setProperty(l->index, value);
- return;
+ return true;
}
}
l->setter = setterFallback;
- setterFallback(l, engine, object, value);
+ return setterFallback(l, engine, object, value);
}
-void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+bool Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
@@ -943,32 +799,31 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co
Q_ASSERT(!p->prototype());
o->setInternalClass(l->classList[3]);
o->setProperty(l->index, value);
- return;
+ return true;
}
}
}
l->setter = setterFallback;
- setterFallback(l, engine, object, value);
+ return setterFallback(l, engine, object, value);
}
-void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+bool Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Object *o = static_cast<Object *>(object.managed());
if (o) {
if (o->internalClass() == l->classList[0]) {
o->setProperty(l->index, value);
- return;
+ return true;
}
if (o->internalClass() == l->classList[1]) {
o->setProperty(l->index2, value);
- return;
+ return true;
}
}
l->setter = setterFallback;
- setterFallback(l, engine, object, value);
-
+ return setterFallback(l, engine, object, value);
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index ce5189a780..826760aa2d 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -67,11 +67,9 @@ namespace QV4 {
struct Lookup {
enum { Size = 4 };
union {
- ReturnedValue (*indexedGetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
- void (*indexedSetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
- void (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v);
+ bool (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v);
};
union {
InternalClass *classList[Size];
@@ -90,14 +88,6 @@ struct Lookup {
uint index;
uint nameIndex;
- static ReturnedValue indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
- static ReturnedValue indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
- static ReturnedValue indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
-
- static void indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
- static void indexedSetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value);
- static void indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
-
static ReturnedValue getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterFallback(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -133,15 +123,15 @@ struct Lookup {
static ReturnedValue globalGetterAccessor1(Lookup *l, ExecutionEngine *engine);
static ReturnedValue globalGetterAccessor2(Lookup *l, ExecutionEngine *engine);
- static void setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
- static void setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
- static void setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
- static void setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
- static void setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
- static void setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
- static void setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
- static void setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
- static void setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
ReturnedValue lookup(const Value &thisObject, Object *obj, PropertyAttributes *attrs);
ReturnedValue lookup(const Object *obj, PropertyAttributes *attrs);
@@ -151,7 +141,6 @@ struct Lookup {
Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
// Ensure that these offsets are always at this point to keep generated code compatible
// across 32-bit and 64-bit (matters when cross-compiling).
-Q_STATIC_ASSERT(offsetof(Lookup, indexedGetter) == 0);
Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0);
}
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index 46230b5bc1..0c94c1ac43 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -94,9 +94,9 @@ static Q_ALWAYS_INLINE double copySign(double x, double y)
return ::copysign(x, y);
}
-void MathObject::method_abs(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_abs(const BuiltinFunction *, CallData *callData)
{
- if (!callData->argc)
+ if (!callData->argc())
RETURN_RESULT(Encode(qt_qnan()));
if (callData->args[0].isInteger()) {
@@ -111,37 +111,37 @@ void MathObject::method_abs(const BuiltinFunction *, Scope &scope, CallData *cal
RETURN_RESULT(Encode(v < 0 ? -v : v));
}
-void MathObject::method_acos(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_acos(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : 2;
+ double v = callData->argc() ? callData->args[0].toNumber() : 2;
if (v > 1)
RETURN_RESULT(Encode(qt_qnan()));
RETURN_RESULT(Encode(std::acos(v)));
}
-void MathObject::method_asin(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_asin(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : 2;
+ double v = callData->argc() ? callData->args[0].toNumber() : 2;
if (v > 1)
RETURN_RESULT(Encode(qt_qnan()));
else
RETURN_RESULT(Encode(std::asin(v)));
}
-void MathObject::method_atan(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_atan(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
if (v == 0.0)
RETURN_RESULT(Encode(v));
else
RETURN_RESULT(Encode(std::atan(v)));
}
-void MathObject::method_atan2(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_atan2(const BuiltinFunction *, CallData *callData)
{
- double v1 = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- double v2 = callData->argc > 1 ? callData->args[1].toNumber() : qt_qnan();
+ double v1 = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ double v2 = callData->argc() > 1 ? callData->args[1].toNumber() : qt_qnan();
if ((v1 < 0) && qt_is_finite(v1) && qt_is_inf(v2) && (copySign(1.0, v2) == 1.0))
RETURN_RESULT(Encode(copySign(0, -1.0)));
@@ -156,24 +156,24 @@ void MathObject::method_atan2(const BuiltinFunction *, Scope &scope, CallData *c
RETURN_RESULT(Encode(std::atan2(v1, v2)));
}
-void MathObject::method_ceil(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_ceil(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
if (v < 0.0 && v > -1.0)
RETURN_RESULT(Encode(copySign(0, -1.0)));
else
RETURN_RESULT(Encode(std::ceil(v)));
}
-void MathObject::method_cos(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_cos(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
RETURN_RESULT(Encode(std::cos(v)));
}
-void MathObject::method_exp(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_exp(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
if (qt_is_inf(v)) {
if (copySign(1.0, v) == -1.0)
RETURN_RESULT(Encode(0));
@@ -184,25 +184,27 @@ void MathObject::method_exp(const BuiltinFunction *, Scope &scope, CallData *cal
}
}
-void MathObject::method_floor(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_floor(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
- RETURN_RESULT(Encode(std::floor(v)));
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
+ Value result = Primitive::fromDouble(std::floor(v));
+ result.isInt32();
+ RETURN_RESULT(result);
}
-void MathObject::method_log(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_log(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
if (v < 0)
RETURN_RESULT(Encode(qt_qnan()));
else
RETURN_RESULT(Encode(std::log(v)));
}
-void MathObject::method_max(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_max(const BuiltinFunction *, CallData *callData)
{
double mx = -qt_inf();
- for (int i = 0; i < callData->argc; ++i) {
+ for (int i = 0, ei = callData->argc(); i < ei; ++i) {
double x = callData->args[i].toNumber();
if (x > mx || std::isnan(x))
mx = x;
@@ -210,10 +212,10 @@ void MathObject::method_max(const BuiltinFunction *, Scope &scope, CallData *cal
RETURN_RESULT(Encode(mx));
}
-void MathObject::method_min(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_min(const BuiltinFunction *, CallData *callData)
{
double mx = qt_inf();
- for (int i = 0; i < callData->argc; ++i) {
+ for (int i = 0, ei = callData->argc(); i < ei; ++i) {
double x = callData->args[i].toNumber();
if ((x == 0 && mx == x && copySign(1.0, x) == -1.0)
|| (x < mx) || std::isnan(x)) {
@@ -223,10 +225,10 @@ void MathObject::method_min(const BuiltinFunction *, Scope &scope, CallData *cal
RETURN_RESULT(Encode(mx));
}
-void MathObject::method_pow(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_pow(const BuiltinFunction *, CallData *callData)
{
- double x = callData->argc > 0 ? callData->args[0].toNumber() : qt_qnan();
- double y = callData->argc > 1 ? callData->args[1].toNumber() : qt_qnan();
+ double x = callData->argc() > 0 ? callData->args[0].toNumber() : qt_qnan();
+ double y = callData->argc() > 1 ? callData->args[1].toNumber() : qt_qnan();
if (std::isnan(y))
RETURN_RESULT(Encode(qt_qnan()));
@@ -273,21 +275,21 @@ void MathObject::method_pow(const BuiltinFunction *, Scope &scope, CallData *cal
RETURN_RESULT(Encode(qt_qnan()));
}
-void MathObject::method_random(const BuiltinFunction *, Scope &scope, CallData *)
+ReturnedValue MathObject::method_random(const BuiltinFunction *, CallData *)
{
RETURN_RESULT(Encode(QRandomGenerator::getReal()));
}
-void MathObject::method_round(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_round(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
v = copySign(std::floor(v + 0.5), v);
RETURN_RESULT(Encode(v));
}
-void MathObject::method_sign(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_sign(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
if (std::isnan(v))
RETURN_RESULT(Encode(qt_qnan()));
@@ -298,21 +300,21 @@ void MathObject::method_sign(const BuiltinFunction *, Scope &scope, CallData *ca
RETURN_RESULT(Encode(std::signbit(v) ? -1 : 1));
}
-void MathObject::method_sin(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_sin(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
RETURN_RESULT(Encode(std::sin(v)));
}
-void MathObject::method_sqrt(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_sqrt(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
RETURN_RESULT(Encode(std::sqrt(v)));
}
-void MathObject::method_tan(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue MathObject::method_tan(const BuiltinFunction *, CallData *callData)
{
- double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v = callData->argc() ? callData->args[0].toNumber() : qt_qnan();
if (v == 0.0)
RETURN_RESULT(Encode(v));
else
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index e617712905..016f0c16ca 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -69,25 +69,25 @@ struct MathObject: Object
V4_OBJECT2(MathObject, Object)
Q_MANAGED_TYPE(MathObject)
- static void method_abs(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_acos(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_asin(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_atan(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_atan2(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_ceil(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_cos(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_exp(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_floor(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_log(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_max(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_min(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_pow(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_random(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_round(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_sign(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_sin(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_sqrt(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_tan(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_abs(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_acos(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_asin(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_atan(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_atan2(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_ceil(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_cos(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_exp(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_floor(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_log(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_max(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_min(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_pow(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_random(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_round(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_sign(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_sin(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_sqrt(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_tan(const BuiltinFunction *, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index d5c80dbf80..ca5340c37d 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -78,16 +78,16 @@ void Heap::NumberCtor::init(QV4::ExecutionContext *scope)
Heap::FunctionObject::init(scope, QStringLiteral("Number"));
}
-void NumberCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue NumberCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- double dbl = callData->argc ? callData->args[0].toNumber() : 0.;
- scope.result = Encode(scope.engine->newNumberObject(dbl));
+ double dbl = argc ? argv[0].toNumber() : 0.;
+ return Encode(f->engine()->newNumberObject(dbl));
}
-void NumberCtor::call(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue NumberCtor::call(const FunctionObject *, const Value *, const Value *argv, int argc)
{
- double dbl = callData->argc ? callData->args[0].toNumber() : 0.;
- scope.result = Encode(dbl);
+ double dbl = argc ? argv[0].toNumber() : 0.;
+ return Encode(dbl);
}
void NumberPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -124,119 +124,101 @@ QT_WARNING_POP
defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision, 1);
}
-inline ReturnedValue thisNumberValue(Scope &scope, CallData *callData)
+inline ReturnedValue thisNumberValue(ExecutionEngine *v4, CallData *callData)
{
if (callData->thisObject.isNumber())
return callData->thisObject.asReturnedValue();
NumberObject *n = callData->thisObject.as<NumberObject>();
if (!n) {
- scope.engine->throwTypeError();
+ v4->throwTypeError();
return Encode::undefined();
}
return Encode(n->value());
}
-inline double thisNumber(Scope &scope, CallData *callData)
+inline double thisNumber(ExecutionEngine *engine, CallData *callData)
{
if (callData->thisObject.isNumber())
return callData->thisObject.asDouble();
NumberObject *n = callData->thisObject.as<NumberObject>();
if (!n) {
- scope.engine->throwTypeError();
+ engine->throwTypeError();
return 0;
}
return n->value();
}
-void NumberPrototype::method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue NumberPrototype::method_isFinite(const BuiltinFunction *, CallData *callData)
{
- if (!callData->argc) {
- scope.result = Encode(false);
- return;
- }
+ if (!callData->argc())
+ return Encode(false);
double v = callData->args[0].toNumber();
- scope.result = Encode(!std::isnan(v) && !qt_is_inf(v));
+ return Encode(!std::isnan(v) && !qt_is_inf(v));
}
-void NumberPrototype::method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue NumberPrototype::method_isInteger(const BuiltinFunction *, CallData *callData)
{
- if (!callData->argc) {
- scope.result = Encode(false);
- return;
- }
+ if (!callData->argc())
+ return Encode(false);
const Value &v = callData->args[0];
- if (!v.isNumber()) {
- scope.result = Encode(false);
- return;
- }
+ if (!v.isNumber())
+ return Encode(false);
double dv = v.toNumber();
- if (std::isnan(dv) || qt_is_inf(dv)) {
- scope.result = Encode(false);
- return;
- }
+ if (std::isnan(dv) || qt_is_inf(dv))
+ return Encode(false);
double iv = v.toInteger();
- scope.result = Encode(dv == iv);
+ return Encode(dv == iv);
}
-void NumberPrototype::method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue NumberPrototype::method_isSafeInteger(const BuiltinFunction *, CallData *callData)
{
- if (!callData->argc) {
- scope.result = Encode(false);
- return;
- }
+ if (!callData->argc())
+ return Encode(false);
const Value &v = callData->args[0];
- if (!v.isNumber()) {
- scope.result = Encode(false);
- return;
- }
+ if (!v.isNumber())
+ return Encode(false);
double dv = v.toNumber();
- if (std::isnan(dv) || qt_is_inf(dv)) {
- scope.result = Encode(false);
- return;
- }
+ if (std::isnan(dv) || qt_is_inf(dv))
+ return Encode(false);
double iv = v.toInteger();
- scope.result = Encode(dv == iv && std::fabs(iv) <= (2^53)-1);
+ return Encode(dv == iv && std::fabs(iv) <= (2^53)-1);
}
-void NumberPrototype::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue NumberPrototype::method_isNaN(const BuiltinFunction *, CallData *callData)
{
- if (!callData->argc) {
- scope.result = Encode(false);
- return;
- }
+ if (!callData->argc())
+ return Encode(false);
double v = callData->args[0].toNumber();
// cast to bool explicitly as std::isnan() may give us ::isnan(), which
// sometimes returns an int and we don't want the Encode(int) overload.
- scope.result = Encode(bool(std::isnan(v)));
+ return Encode(bool(std::isnan(v)));
}
-void NumberPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue NumberPrototype::method_toString(const BuiltinFunction *b, CallData *callData)
{
- double num = thisNumber(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ double num = thisNumber(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
- if (callData->argc && !callData->args[0].isUndefined()) {
+ if (callData->argc() && !callData->args[0].isUndefined()) {
int radix = callData->args[0].toInt32();
if (radix < 2 || radix > 36) {
- scope.result = scope.engine->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix")
- .arg(radix));
- return;
+ return v4->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix").arg(radix));
}
if (std::isnan(num)) {
- scope.result = scope.engine->newString(QStringLiteral("NaN"));
- return;
+ return Encode(v4->newString(QStringLiteral("NaN")));
} else if (qt_is_inf(num)) {
- scope.result = scope.engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"));
- return;
+ return Encode(v4->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity")));
}
if (radix != 10) {
@@ -266,43 +248,42 @@ void NumberPrototype::method_toString(const BuiltinFunction *, Scope &scope, Cal
}
if (negative)
str.prepend(QLatin1Char('-'));
- scope.result = scope.engine->newString(str);
- return;
+ return Encode(v4->newString(str));
}
}
- scope.result = Primitive::fromDouble(num).toString(scope.engine);
+ return Encode(Primitive::fromDouble(num).toString(v4));
}
-void NumberPrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue NumberPrototype::method_toLocaleString(const BuiltinFunction *b, CallData *callData)
{
- ScopedValue v(scope, thisNumberValue(scope, callData));
- scope.result = v->toString(scope.engine);
- CHECK_EXCEPTION();
+ Scope scope(b);
+ ScopedValue v(scope, thisNumberValue(b->engine(), callData));
+ return Encode(v->toString(scope.engine));
}
-void NumberPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue NumberPrototype::method_valueOf(const BuiltinFunction *b, CallData *callData)
{
- scope.result = thisNumberValue(scope, callData);
+ return thisNumberValue(b->engine(), callData);
}
-void NumberPrototype::method_toFixed(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue NumberPrototype::method_toFixed(const BuiltinFunction *b, CallData *callData)
{
- double v = thisNumber(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ double v = thisNumber(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
double fdigits = 0;
- if (callData->argc > 0)
+ if (callData->argc() > 0)
fdigits = callData->args[0].toInteger();
if (std::isnan(fdigits))
fdigits = 0;
- if (fdigits < 0 || fdigits > 20) {
- scope.result = scope.engine->throwRangeError(callData->thisObject);
- return;
- }
+ if (fdigits < 0 || fdigits > 20)
+ return v4->throwRangeError(callData->thisObject);
QString str;
if (std::isnan(v))
@@ -312,49 +293,51 @@ void NumberPrototype::method_toFixed(const BuiltinFunction *, Scope &scope, Call
else if (v < 1.e21)
str = NumberLocale::instance()->toString(v, 'f', int(fdigits));
else {
- scope.result = RuntimeHelpers::stringFromNumber(scope.engine, v);
- return;
+ return Encode(RuntimeHelpers::stringFromNumber(v4, v));
}
- scope.result = scope.engine->newString(str);
+ return Encode(v4->newString(str));
}
-void NumberPrototype::method_toExponential(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue NumberPrototype::method_toExponential(const BuiltinFunction *b, CallData *callData)
{
- double d = thisNumber(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ double d = thisNumber(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+
int fdigits = NumberLocale::instance()->defaultDoublePrecision;
- if (callData->argc && !callData->args[0].isUndefined()) {
+ if (callData->argc() && !callData->args[0].isUndefined()) {
fdigits = callData->args[0].toInt32();
if (fdigits < 0 || fdigits > 20) {
- ScopedString error(scope, scope.engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range")));
- scope.result = scope.engine->throwRangeError(error);
- return;
+ Scope scope(v4);
+ ScopedString error(scope, v4->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range")));
+ return v4->throwRangeError(error);
}
}
QString result = NumberLocale::instance()->toString(d, 'e', fdigits);
- scope.result = scope.engine->newString(result);
+ return Encode(v4->newString(result));
}
-void NumberPrototype::method_toPrecision(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue NumberPrototype::method_toPrecision(const BuiltinFunction *b, CallData *callData)
{
- ScopedValue v(scope, thisNumberValue(scope, callData));
- CHECK_EXCEPTION();
+ Scope scope(b);
+ ScopedValue v(scope, thisNumberValue(scope.engine, callData));
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
- if (!callData->argc || callData->args[0].isUndefined()) {
- scope.result = v->toString(scope.engine);
- return;
- }
+
+ if (!callData->argc() || callData->args[0].isUndefined())
+ return Encode(v->toString(scope.engine));
int precision = callData->args[0].toInt32();
if (precision < 1 || precision > 21) {
ScopedString error(scope, scope.engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range")));
- scope.result = scope.engine->throwRangeError(error);
- return;
+ return scope.engine->throwRangeError(error);
}
QString result = NumberLocale::instance()->toString(v->asDouble(), 'g', precision);
- scope.result = scope.engine->newString(result);
+ return Encode(scope.engine->newString(result));
}
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 0bc2cd8c65..e4ff87c93a 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 void construct(const Managed *that, Scope &scope, CallData *callData);
- static void call(const Managed *, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
struct NumberPrototype: NumberObject
@@ -88,16 +88,16 @@ struct NumberPrototype: NumberObject
V4_PROTOTYPE(objectPrototype)
void init(ExecutionEngine *engine, Object *ctor);
- static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_isNaN(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_toFixed(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toExponential(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toPrecision(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_isFinite(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_isInteger(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_isSafeInteger(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_isNaN(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toLocaleString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_valueOf(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toFixed(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toExponential(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toPrecision(const BuiltinFunction *, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 94d5a74fe5..1859466348 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -38,8 +38,6 @@
****************************************************************************/
#include "qv4object_p.h"
-#include "qv4jsir_p.h"
-#include "qv4isel_p.h"
#include "qv4objectproto_p.h"
#include "qv4stringobject_p.h"
#include "qv4argumentsobject_p.h"
@@ -51,6 +49,7 @@
#include "qv4identifier_p.h"
#include "qv4string_p.h"
#include "qv4identifiertable_p.h"
+#include "qv4jscall_p.h"
#include <stdint.h>
@@ -108,10 +107,9 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property
return Encode::undefined();
Scope scope(f->engine());
- ScopedCallData callData(scope);
- callData->thisObject = thisObject;
- f->call(scope, callData);
- return scope.result.asReturnedValue();
+ JSCallData jsCallData(scope);
+ *jsCallData->thisObject = thisObject;
+ return f->call(jsCallData);
}
bool Object::putValue(uint memberIndex, const Value &value)
@@ -127,25 +125,20 @@ bool Object::putValue(uint memberIndex, const Value &value)
if (set) {
Scope scope(ic->engine);
ScopedFunctionObject setter(scope, set);
- ScopedCallData callData(scope, 1);
- callData->args[0] = value;
- callData->thisObject = this;
- setter->call(scope, callData);
+ JSCallData jsCallData(scope, 1);
+ jsCallData->args[0] = value;
+ *jsCallData->thisObject = this;
+ setter->call(jsCallData);
return !ic->engine->hasException;
}
- goto reject;
+ return false;
}
if (!attrs.isWritable())
- goto reject;
+ return false;
setProperty(memberIndex, value);
return true;
-
- reject:
- if (engine()->current->strictMode)
- engine()->throwTypeError();
- return false;
}
void Object::defineDefaultProperty(const QString &name, const Value &value)
@@ -156,7 +149,7 @@ void Object::defineDefaultProperty(const QString &name, const Value &value)
defineDefaultProperty(s, value);
}
-void Object::defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount)
+void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(const BuiltinFunction *, CallData *), int argumentCount)
{
ExecutionEngine *e = engine();
Scope scope(e);
@@ -167,7 +160,7 @@ void Object::defineDefaultProperty(const QString &name, void (*code)(const Built
defineDefaultProperty(s, function);
}
-void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount)
+void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(const BuiltinFunction *, CallData *), int argumentCount)
{
ExecutionEngine *e = engine();
Scope scope(e);
@@ -177,8 +170,8 @@ void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunct
defineDefaultProperty(name, function);
}
-void Object::defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
- void (*setter)(const BuiltinFunction *, Scope &, CallData *))
+void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const BuiltinFunction *, CallData *),
+ ReturnedValue (*setter)(const BuiltinFunction *, CallData *))
{
ExecutionEngine *e = engine();
Scope scope(e);
@@ -186,8 +179,8 @@ void Object::defineAccessorProperty(const QString &name, void (*getter)(const Bu
defineAccessorProperty(s, getter, setter);
}
-void Object::defineAccessorProperty(String *name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
- void (*setter)(const BuiltinFunction *, Scope &, CallData *))
+void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(const BuiltinFunction *, CallData *),
+ ReturnedValue (*setter)(const BuiltinFunction *, CallData *))
{
ExecutionEngine *v4 = engine();
QV4::Scope scope(v4);
@@ -402,14 +395,14 @@ bool Object::hasOwnProperty(uint index) const
return false;
}
-void Object::construct(const Managed *m, Scope &scope, CallData *)
+ReturnedValue Object::callAsConstructor(const FunctionObject *f, const Value *, int)
{
- scope.result = static_cast<const Object *>(m)->engine()->throwTypeError();
+ return f->engine()->throwTypeError();
}
-void Object::call(const Managed *m, Scope &scope, CallData *)
+ReturnedValue Object::call(const FunctionObject *f, const Value *, const Value *, int)
{
- scope.result = static_cast<const Object *>(m)->engine()->throwTypeError();
+ return f->engine()->throwTypeError();
}
ReturnedValue Object::get(const Managed *m, String *name, bool *hasProperty)
@@ -512,11 +505,11 @@ ReturnedValue Object::getLookup(const Managed *m, Lookup *l)
return Encode::undefined();
}
-void Object::setLookup(Managed *m, Lookup *l, const Value &value)
+bool Object::setLookup(Managed *m, Lookup *l, const Value &value)
{
Scope scope(static_cast<Object *>(m)->engine());
ScopedObject o(scope, static_cast<Object *>(m));
- ScopedString name(scope, scope.engine->current->compilationUnit->runtimeStrings[l->nameIndex]);
+ ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
InternalClass *c = o->internalClass();
uint idx = c->find(name);
@@ -526,42 +519,44 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value)
l->index = idx;
l->setter = idx < o->d()->vtable()->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0;
o->setProperty(idx, value);
- return;
+ return true;
}
- if (idx != UINT_MAX) {
- o->putValue(idx, value);
- return;
- }
+ if (idx != UINT_MAX)
+ return o->putValue(idx, value);
}
- o->put(name, value);
+ if (!o->put(name, value)) {
+ l->setter = Lookup::setterFallback;
+ return false;
+ }
if (o->internalClass() == c)
- return;
+ return true;
idx = o->internalClass()->find(name);
- if (idx == UINT_MAX)
- return;
+ if (idx == UINT_MAX) // ### can this even happen?
+ return false;
l->classList[0] = c;
l->classList[3] = o->internalClass();
l->index = idx;
if (!o->prototype()) {
l->setter = Lookup::setterInsert0;
- return;
+ return true;
}
o = o->prototype();
l->classList[1] = o->internalClass();
if (!o->prototype()) {
l->setter = Lookup::setterInsert1;
- return;
+ return true;
}
o = o->prototype();
l->classList[2] = o->internalClass();
if (!o->prototype()) {
l->setter = Lookup::setterInsert2;
- return;
+ return true;
}
l->setter = Lookup::setterGeneric;
+ return true;
}
void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *pd, PropertyAttributes *attrs)
@@ -725,9 +720,9 @@ bool Object::internalPut(String *name, const Value &value)
if (attrs.isAccessor()) {
if (memberIndex->as<FunctionObject>())
goto cont;
- goto reject;
+ return false;
} else if (!attrs.isWritable())
- goto reject;
+ return false;
else if (isArrayObject() && name->equals(engine->id_length())) {
bool ok;
uint l = value.asArrayLength(&ok);
@@ -737,14 +732,14 @@ bool Object::internalPut(String *name, const Value &value)
}
ok = setArrayLength(l);
if (!ok)
- goto reject;
+ return false;
} else {
memberIndex.set(engine, value);
}
return true;
} else if (!prototype()) {
if (!isExtensible())
- goto reject;
+ return false;
} else {
// clause 4
Scope scope(engine);
@@ -752,12 +747,12 @@ bool Object::internalPut(String *name, const Value &value)
if (!memberIndex.isNull()) {
if (attrs.isAccessor()) {
if (!memberIndex->as<FunctionObject>())
- goto reject;
+ return false;
} else if (!isExtensible() || !attrs.isWritable()) {
- goto reject;
+ return false;
}
} else if (!isExtensible()) {
- goto reject;
+ return false;
}
}
@@ -769,24 +764,15 @@ bool Object::internalPut(String *name, const Value &value)
Scope scope(engine);
ScopedFunctionObject setter(scope, *memberIndex);
- ScopedCallData callData(scope, 1);
- callData->args[0] = value;
- callData->thisObject = this;
- setter->call(scope, callData);
- return !internalClass()->engine->hasException;
+ JSCallData jsCallData(scope, 1);
+ jsCallData->args[0] = value;
+ *jsCallData->thisObject = this;
+ setter->call(jsCallData);
+ return !engine->hasException;
}
insertMember(name, value);
return true;
-
- reject:
- // ### this should be removed once everything is ported to use Object::set()
- if (engine->current->strictMode) {
- QString message = QLatin1String("Cannot assign to read-only property \"") +
- name->toQString() + QLatin1Char('\"');
- engine->throwTypeError(message);
- }
- return false;
}
bool Object::internalPutIndexed(uint index, const Value &value)
@@ -802,7 +788,7 @@ bool Object::internalPutIndexed(uint index, const Value &value)
if (arrayIndex.isNull() && isStringObject()) {
if (index < static_cast<StringObject *>(this)->length())
// not writable
- goto reject;
+ return false;
}
// clause 1
@@ -810,15 +796,15 @@ bool Object::internalPutIndexed(uint index, const Value &value)
if (attrs.isAccessor()) {
if (arrayIndex->as<FunctionObject>())
goto cont;
- goto reject;
+ return false;
} else if (!attrs.isWritable())
- goto reject;
+ return false;
arrayIndex.set(engine, value);
return true;
} else if (!prototype()) {
if (!isExtensible())
- goto reject;
+ return false;
} else {
// clause 4
Scope scope(engine);
@@ -826,12 +812,12 @@ bool Object::internalPutIndexed(uint index, const Value &value)
if (!arrayIndex.isNull()) {
if (attrs.isAccessor()) {
if (!arrayIndex->as<FunctionObject>())
- goto reject;
+ return false;
} else if (!isExtensible() || !attrs.isWritable()) {
- goto reject;
+ return false;
}
} else if (!isExtensible()) {
- goto reject;
+ return false;
}
}
@@ -843,21 +829,15 @@ bool Object::internalPutIndexed(uint index, const Value &value)
Scope scope(engine);
ScopedFunctionObject setter(scope, *arrayIndex);
- ScopedCallData callData(scope, 1);
- callData->args[0] = value;
- callData->thisObject = this;
- setter->call(scope, callData);
- return !internalClass()->engine->hasException;
+ JSCallData jsCallData(scope, 1);
+ jsCallData->args[0] = value;
+ *jsCallData->thisObject = this;
+ setter->call(jsCallData);
+ return !engine->hasException;
}
arraySet(index, value);
return true;
-
- reject:
- // ### this should be removed once everything is ported to use Object::setIndexed()
- if (engine->current->strictMode)
- engine->throwTypeError();
- return false;
}
// Section 8.12.7
@@ -878,8 +858,6 @@ bool Object::internalDeleteProperty(String *name)
InternalClass::removeMember(this, name->identifier());
return true;
}
- if (engine()->current->strictMode)
- engine()->throwTypeError();
return false;
}
@@ -896,8 +874,6 @@ bool Object::internalDeleteIndexedProperty(uint index)
if (!ad || ad->vtable()->del(this, index))
return true;
- if (engine()->current->strictMode)
- engine()->throwTypeError();
return false;
}
@@ -921,7 +897,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const
if (attrs.isEmpty() || p->isSubset(attrs, lp, cattrs))
return true;
if (!cattrs.isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable())
- goto reject;
+ return false;
bool succeeded = true;
if (attrs.type() == PropertyAttributes::Data) {
bool ok;
@@ -938,7 +914,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const
InternalClass::changeMember(this, engine->id_length(), cattrs);
}
if (!succeeded)
- goto reject;
+ return false;
return true;
}
@@ -948,7 +924,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const
if (memberIndex == UINT_MAX) {
// clause 3
if (!isExtensible())
- goto reject;
+ return false;
// clause 4
ScopedProperty pd(scope);
pd->copy(p, attrs);
@@ -958,26 +934,18 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const
}
return __defineOwnProperty__(engine, memberIndex, name, p, attrs);
-reject:
- if (engine->current->strictMode)
- engine->throwTypeError();
- return false;
}
bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs)
{
// 15.4.5.1, 4b
if (isArrayObject() && index >= getLength() && !internalClass()->propertyData[Heap::ArrayObject::LengthPropertyIndex].isWritable())
- goto reject;
+ return false;
if (ArgumentsObject::isNonStrictArgumentsObject(this))
return static_cast<ArgumentsObject *>(this)->defineOwnProperty(engine, index, p, attrs);
return defineOwnProperty2(engine, index, p, attrs);
-reject:
- if (engine->current->strictMode)
- engine->throwTypeError();
- return false;
}
bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs)
@@ -994,7 +962,7 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope
if (!hasProperty) {
// clause 3
if (!isExtensible())
- goto reject;
+ return false;
// clause 4
Scope scope(engine);
ScopedProperty pp(scope);
@@ -1010,10 +978,6 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope
}
return __defineOwnProperty__(engine, index, 0, p, attrs);
-reject:
- if (engine->current->strictMode)
- engine->throwTypeError();
- return false;
}
bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *member, const Property *p, PropertyAttributes attrs)
@@ -1040,9 +1004,9 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *
// clause 7
if (!cattrs.isConfigurable()) {
if (attrs.isConfigurable())
- goto reject;
+ return false;
if (attrs.hasEnumerable() && attrs.isEnumerable() != cattrs.isEnumerable())
- goto reject;
+ return false;
}
// clause 8
@@ -1053,7 +1017,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *
if (cattrs.isData() != attrs.isData()) {
// 9a
if (!cattrs.isConfigurable())
- goto reject;
+ return false;
if (cattrs.isData()) {
// 9b
cattrs.setType(PropertyAttributes::Accessor);
@@ -1079,15 +1043,15 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *
} else if (cattrs.isData() && attrs.isData()) { // clause 10
if (!cattrs.isConfigurable() && !cattrs.isWritable()) {
if (attrs.isWritable() || !current->value.sameValue(p->value))
- goto reject;
+ return false;
}
} else { // clause 10
Q_ASSERT(cattrs.isAccessor() && attrs.isAccessor());
if (!cattrs.isConfigurable()) {
if (!p->value.isEmpty() && current->value.rawValue() != p->value.rawValue())
- goto reject;
+ return false;
if (!p->set.isEmpty() && current->set.rawValue() != p->set.rawValue())
- goto reject;
+ return false;
}
}
@@ -1102,10 +1066,6 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *
arrayData()->setProperty(scope.engine, index, current);
}
return true;
- reject:
- if (engine->current->strictMode)
- engine->throwTypeError();
- return false;
}
@@ -1260,7 +1220,7 @@ void Heap::ArrayObject::init(const QStringList &list)
ReturnedValue ArrayObject::getLookup(const Managed *m, Lookup *l)
{
Scope scope(static_cast<const Object *>(m)->engine());
- ScopedString name(scope, scope.engine->current->compilationUnit->runtimeStrings[l->nameIndex]);
+ ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
if (name->equals(scope.engine->id_length())) {
// special case, as the property is on the object itself
l->getter = Lookup::arrayLengthGetter;
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 066a93cc61..af68f09700 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -57,6 +57,7 @@
#include "qv4scopedvalue_p.h"
#include "qv4value_p.h"
#include "qv4internalclass_p.h"
+#include "qv4string_p.h"
QT_BEGIN_NAMESPACE
@@ -174,8 +175,8 @@ Q_STATIC_ASSERT(Object::markTable == ((2 << 2) | (2 << 4)));
struct ObjectVTable
{
VTable vTable;
- void (*call)(const Managed *, Scope &scope, CallData *data);
- void (*construct)(const Managed *, Scope &scope, CallData *data);
+ ReturnedValue (*call)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ ReturnedValue (*callAsConstructor)(const FunctionObject *, const Value *argv, int argc);
ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty);
ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty);
bool (*put)(Managed *, String *name, const Value &value);
@@ -185,7 +186,7 @@ struct ObjectVTable
bool (*deleteProperty)(Managed *m, String *name);
bool (*deleteIndexedProperty)(Managed *m, uint index);
ReturnedValue (*getLookup)(const Managed *m, Lookup *l);
- void (*setLookup)(Managed *m, Lookup *l, const Value &v);
+ bool (*setLookup)(Managed *m, Lookup *l, const Value &v);
uint (*getLength)(const Managed *m);
void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
ReturnedValue (*instanceOf)(const Object *typeObject, const Value &var);
@@ -196,7 +197,7 @@ const QV4::ObjectVTable classname::static_vtbl = \
{ \
DEFINE_MANAGED_VTABLE_INT(classname, (std::is_same<classname::SuperClass, Object>::value) ? nullptr : &classname::SuperClass::static_vtbl.vTable), \
call, \
- construct, \
+ callAsConstructor, \
get, \
getIndexed, \
put, \
@@ -287,12 +288,12 @@ struct Q_QML_EXPORT Object: Managed {
insertMember(name, value, Attr_Data|Attr_NotEnumerable);
}
void defineDefaultProperty(const QString &name, const Value &value);
- void defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0);
- void defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0);
- void defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
- void (*setter)(const BuiltinFunction *, Scope &, CallData *));
- void defineAccessorProperty(String *name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
- void (*setter)(const BuiltinFunction *, Scope &, CallData *));
+ void defineDefaultProperty(const QString &name, ReturnedValue (*code)(const BuiltinFunction *, CallData *), int argumentCount = 0);
+ void defineDefaultProperty(String *name, ReturnedValue (*code)(const BuiltinFunction *, CallData *), int argumentCount = 0);
+ void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const BuiltinFunction *, CallData *),
+ ReturnedValue (*setter)(const BuiltinFunction *, CallData *));
+ void defineAccessorProperty(String *name, ReturnedValue (*getter)(const BuiltinFunction *, CallData *),
+ ReturnedValue (*setter)(const BuiltinFunction *, CallData *));
/* Fixed: Writable: false, Enumerable: false, Configurable: false */
void defineReadonlyProperty(const QString &name, const Value &value);
void defineReadonlyProperty(String *name, const Value &value);
@@ -408,19 +409,6 @@ public:
return ret;
}
- inline bool setIndexed(uint idx, const Value &v, ThrowOnFailure shouldThrow)
- {
- bool ret = vtable()->putIndexed(this, idx, v);
- if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) {
- ExecutionEngine *e = engine();
- if (!e->hasException) { // allow a custom set impl to throw itself
- e->throwTypeError();
- }
- }
- return ret;
- }
-
-
PropertyAttributes query(String *name) const
{ return vtable()->query(this, name); }
PropertyAttributes queryIndexed(uint index) const
@@ -431,21 +419,17 @@ public:
{ return vtable()->deleteIndexedProperty(this, index); }
ReturnedValue getLookup(Lookup *l) const
{ return vtable()->getLookup(this, l); }
- void setLookup(Lookup *l, const Value &v)
- { vtable()->setLookup(this, l, v); }
+ bool setLookup(Lookup *l, const Value &v)
+ { return vtable()->setLookup(this, l, v); }
void advanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
{ vtable()->advanceIterator(this, it, name, index, p, attributes); }
uint getLength() const { return vtable()->getLength(this); }
ReturnedValue instanceOf(const Value &var) const
{ return vtable()->instanceOf(this, var); }
- 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 construct(const Managed *m, Scope &scope, CallData *);
- static void call(const Managed *m, Scope &scope, CallData *);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
static bool put(Managed *m, String *name, const Value &value);
@@ -455,7 +439,7 @@ protected:
static bool deleteProperty(Managed *m, String *name);
static bool deleteIndexedProperty(Managed *m, uint index);
static ReturnedValue getLookup(const Managed *m, Lookup *l);
- static void setLookup(Managed *m, Lookup *l, const Value &v);
+ static bool setLookup(Managed *m, Lookup *l, const Value &v);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static uint getLength(const Managed *m);
static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 2e72c0f13f..07573e61f3 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -46,6 +46,7 @@
#include "qv4runtime_p.h"
#include "qv4objectiterator_p.h"
#include "qv4string_p.h"
+#include "qv4jscall_p.h"
#include <QtCore/QDateTime>
#include <QtCore/QStringList>
@@ -60,27 +61,29 @@ void Heap::ObjectCtor::init(QV4::ExecutionContext *scope)
Heap::FunctionObject::init(scope, QStringLiteral("Object"));
}
-void ObjectCtor::construct(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue ObjectCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- const ObjectCtor *ctor = static_cast<const ObjectCtor *>(that);
- if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) {
+ ExecutionEngine *v4 = f->engine();
+ const ObjectCtor *ctor = static_cast<const ObjectCtor *>(f);
+ if (!argc || argv[0].isUndefined() || argv[0].isNull()) {
+ Scope scope(v4);
ScopedObject obj(scope, scope.engine->newObject());
ScopedObject proto(scope, ctor->get(scope.engine->id_prototype()));
if (!!proto)
obj->setPrototype(proto);
- scope.result = obj.asReturnedValue();
+ return obj.asReturnedValue();
} else {
- scope.result = callData->args[0].toObject(scope.engine);
+ return argv[0].toObject(v4)->asReturnedValue();
}
}
-void ObjectCtor::call(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue ObjectCtor::call(const FunctionObject *m, const Value *, const Value *argv, int argc)
{
- ExecutionEngine *v4 = scope.engine;
- if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) {
- scope.result = v4->newObject()->asReturnedValue();
+ ExecutionEngine *v4 = m->engine();
+ if (!argc || argv[0].isUndefined() || argv[0].isNull()) {
+ return v4->newObject()->asReturnedValue();
} else {
- scope.result = callData->args[0].toObject(v4);
+ return argv[0].toObject(v4)->asReturnedValue();
}
}
@@ -123,58 +126,78 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
insertMember(v4->id___proto__(), p, Attr_Accessor|Attr_NotEnumerable);
}
-void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
+ if (callData->argc() < 1)
+ return scope.engine->throwTypeError();
+
ScopedObject o(scope, callData->args[0].toObject(scope.engine));
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
ScopedObject p(scope, o->prototype());
- scope.result = !!p ? p->asReturnedValue() : Encode::null();
+ return (!!p ? p->asReturnedValue() : Encode::null());
}
-void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
+ if (callData->argc() < 1)
+ return scope.engine->throwTypeError();
+
ScopedObject O(scope, callData->args[0].toObject(scope.engine));
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
if (ArgumentsObject::isNonStrictArgumentsObject(O))
static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate();
ScopedValue v(scope, callData->argument(1));
ScopedString name(scope, v->toString(scope.engine));
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
PropertyAttributes attrs;
ScopedProperty desc(scope);
O->getOwnProperty(name, &attrs, desc);
- scope.result = fromPropertyDescriptor(scope.engine, desc, attrs);
+ return fromPropertyDescriptor(scope.engine, desc, attrs);
}
-void ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
+ if (callData->argc() < 1)
+ return scope.engine->throwTypeError();
+
ScopedObject O(scope, callData->args[0].toObject(scope.engine));
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
- scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
+ return Encode(getOwnPropertyNames(scope.engine, callData->args[0]));
}
// 19.1.2.1
-void ObjectPrototype::method_assign(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_assign(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
+ if (callData->argc() < 1)
+ return scope.engine->throwTypeError();
+
ScopedObject to(scope, callData->args[0].toObject(scope.engine));
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
- if (callData->argc == 1) {
- scope.result = to;
- return;
- }
+ if (callData->argc() == 1)
+ return to.asReturnedValue();
- for (int i = 1; i < callData->argc; ++i) {
+ for (int i = 1, ei = callData->argc(); i < ei; ++i) {
if (callData->args[i].isUndefined() || callData->args[i].isNull())
continue;
ScopedObject from(scope, callData->args[i].toObject(scope.engine));
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
QV4::ScopedArrayObject keys(scope, QV4::ObjectPrototype::getOwnPropertyNames(scope.engine, from));
quint32 length = keys->getLength();
@@ -195,64 +218,66 @@ void ObjectPrototype::method_assign(const BuiltinFunction *, Scope &scope, CallD
propValue = from->get(nextKey);
to->set(nextKey, propValue, Object::DoThrowOnRejection);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
}
}
- scope.result = to;
+ return to.asReturnedValue();
}
-void ObjectPrototype::method_create(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_create(const BuiltinFunction *builtin, CallData *callData)
{
+ Scope scope(builtin);
ScopedValue O(scope, callData->argument(0));
- if (!O->isObject() && !O->isNull()) {
- scope.result = scope.engine->throwTypeError();
- return;
- }
+ if (!O->isObject() && !O->isNull())
+ return scope.engine->throwTypeError();
ScopedObject newObject(scope, scope.engine->newObject());
newObject->setPrototype(O->as<Object>());
- if (callData->argc > 1 && !callData->args[1].isUndefined()) {
+ if (callData->argc() > 1 && !callData->args[1].isUndefined()) {
callData->args[0] = newObject;
- method_defineProperties(builtin, scope, callData);
- return;
+ return method_defineProperties(builtin, callData);
}
- scope.result = newObject;
+ return newObject.asReturnedValue();
}
-void ObjectPrototype::method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_defineProperty(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject O(scope, callData->argument(0));
- if (!O) {
- scope.result = scope.engine->throwTypeError();
- return;
- }
+ if (!O)
+ return scope.engine->throwTypeError();
ScopedString name(scope, callData->argument(1), ScopedString::Convert);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
ScopedValue attributes(scope, callData->argument(2));
ScopedProperty pd(scope);
PropertyAttributes attrs;
toPropertyDescriptor(scope.engine, attributes, pd, &attrs);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
if (!O->__defineOwnProperty__(scope.engine, name, pd, attrs))
THROW_TYPE_ERROR();
- scope.result = O;
+ return O.asReturnedValue();
}
-void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_defineProperties(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject O(scope, callData->argument(0));
if (!O)
THROW_TYPE_ERROR();
ScopedObject o(scope, callData->argument(1), ScopedObject::Convert);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
ScopedValue val(scope);
@@ -269,7 +294,8 @@ void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &sc
PropertyAttributes nattrs;
val = o->getValue(pd->value, attrs);
toPropertyDescriptor(scope.engine, val, n, &nattrs);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
bool ok;
if (name)
ok = O->__defineOwnProperty__(scope.engine, name, n, nattrs);
@@ -279,17 +305,16 @@ void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &sc
THROW_TYPE_ERROR();
}
- scope.result = O;
+ return O.asReturnedValue();
}
-void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_seal(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->argument(0));
- if (!o) {
+ if (!o)
// 19.1.2.17, 1
- scope.result = callData->argument(0);
- return;
- }
+ return callData->argument(0);
o->setInternalClass(o->internalClass()->sealed());
@@ -301,17 +326,16 @@ void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallDat
}
}
- scope.result = o;
+ return o.asReturnedValue();
}
-void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_freeze(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->argument(0));
- if (!o) {
+ if (!o)
// 19.1.2.5, 1
- scope.result = callData->argument(0);
- return;
- }
+ return callData->argument(0);
if (ArgumentsObject::isNonStrictArgumentsObject(o))
static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate();
@@ -327,116 +351,94 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD
o->arrayData()->attrs[i].setWritable(false);
}
}
- scope.result = o;
+ return o.asReturnedValue();
}
-void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_preventExtensions(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->args[0].toObject(scope.engine));
- if (!o) {
- scope.result = callData->argument(0);
- return;
- }
+ if (!o)
+ return callData->argument(0);
o->setInternalClass(o->internalClass()->nonExtensible());
- scope.result = o;
+ return o.asReturnedValue();
}
-void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_isSealed(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->args[0].toObject(scope.engine));
- if (!o) {
- scope.result = Encode(true);
- return;
- }
+ if (!o)
+ return Encode(true);
- if (o->isExtensible()) {
- scope.result = Encode(false);
- return;
- }
+ if (o->isExtensible())
+ return Encode(false);
- if (o->internalClass() != o->internalClass()->sealed()) {
- scope.result = Encode(false);
- return;
- }
+ if (o->internalClass() != o->internalClass()->sealed())
+ return Encode(false);
- if (!o->arrayData() || !o->arrayData()->length()) {
- scope.result = Encode(true);
- return;
- }
+ if (!o->arrayData() || !o->arrayData()->length())
+ return Encode(true);
Q_ASSERT(o->arrayData() && o->arrayData()->length());
- if (!o->arrayData()->attrs) {
- scope.result = Encode(false);
- return;
- }
+ if (!o->arrayData()->attrs)
+ return Encode(false);
for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
- if (o->arrayData()->attributes(i).isConfigurable()) {
- scope.result = Encode(false);
- return;
- }
+ if (o->arrayData()->attributes(i).isConfigurable())
+ return Encode(false);
}
- scope.result = Encode(true);
+ return Encode(true);
}
-void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_isFrozen(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->args[0].toObject(scope.engine));
- if (!o) {
- scope.result = Encode(true);
- return;
- }
+ if (!o)
+ return Encode(true);
- if (o->isExtensible()) {
- scope.result = Encode(false);
- return;
- }
+ if (o->isExtensible())
+ return Encode(false);
- if (o->internalClass() != o->internalClass()->frozen()) {
- scope.result = Encode(false);
- return;
- }
+ if (o->internalClass() != o->internalClass()->frozen())
+ return Encode(false);
- if (!o->arrayData() || !o->arrayData()->length()) {
- scope.result = Encode(true);
- return;
- }
+ if (!o->arrayData() || !o->arrayData()->length())
+ return Encode(true);
Q_ASSERT(o->arrayData() && o->arrayData()->length());
- if (!o->arrayData()->attrs) {
- scope.result = Encode(false);
- return;
- }
+ if (!o->arrayData()->attrs)
+ return Encode(false);
for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
- if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) {
- scope.result = Encode(false);
- return;
- }
+ if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable())
+ return Encode(false);
}
- scope.result = Encode(true);
+ return Encode(true);
}
-void ObjectPrototype::method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_isExtensible(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->args[0].toObject(scope.engine));
- if (!o) {
- scope.result = Encode(false);
- return;
- }
+ if (!o)
+ return Encode(false);
- scope.result = Encode((bool)o->isExtensible());
+ return Encode((bool)o->isExtensible());
}
-void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_keys(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->args[0].toObject(scope.engine));
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
ScopedArrayObject a(scope, scope.engine->newArrayObject());
@@ -449,24 +451,27 @@ void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallDat
a->push_back(name);
}
- scope.result = a;
+ return a.asReturnedValue();
}
-void ObjectPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_toString(const BuiltinFunction *b, CallData *callData)
{
+ ExecutionEngine *v4 = b->engine();
if (callData->thisObject.isUndefined()) {
- scope.result = scope.engine->newString(QStringLiteral("[object Undefined]"));
+ return Encode(v4->newString(QStringLiteral("[object Undefined]")));
} else if (callData->thisObject.isNull()) {
- scope.result = scope.engine->newString(QStringLiteral("[object Null]"));
+ return Encode(v4->newString(QStringLiteral("[object Null]")));
} else {
+ Scope scope(v4);
ScopedObject obj(scope, callData->thisObject.toObject(scope.engine));
QString className = obj->className();
- scope.result = scope.engine->newString(QStringLiteral("[object %1]").arg(className));
+ return Encode(v4->newString(QStringLiteral("[object %1]").arg(className)));
}
}
-void ObjectPrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_toLocaleString(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->thisObject.toObject(scope.engine));
if (!o)
RETURN_UNDEFINED();
@@ -474,64 +479,69 @@ void ObjectPrototype::method_toLocaleString(const BuiltinFunction *, Scope &scop
ScopedFunctionObject f(scope, o->get(scope.engine->id_toString()));
if (!f)
THROW_TYPE_ERROR();
- ScopedCallData cData(scope);
- cData->thisObject = o;
- f->call(scope, callData);
+ JSCallData jsCallData(scope);
+ *jsCallData->thisObject = o;
+ return f->call(jsCallData);
}
-void ObjectPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_valueOf(const BuiltinFunction *b, CallData *callData)
{
- scope.result = callData->thisObject.toObject(scope.engine);
+ return Encode(callData->thisObject.toObject(b->engine()));
}
-void ObjectPrototype::method_hasOwnProperty(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_hasOwnProperty(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedString P(scope, callData->argument(0), ScopedString::Convert);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
ScopedObject O(scope, callData->thisObject, ScopedObject::Convert);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
bool r = O->hasOwnProperty(P);
if (!r)
r = !O->query(P).isEmpty();
- scope.result = Encode(r);
+ return Encode(r);
}
-void ObjectPrototype::method_isPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_isPrototypeOf(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject V(scope, callData->argument(0));
- if (!V) {
- scope.result = Encode(false);
- return;
- }
+ if (!V)
+ return Encode(false);
ScopedObject O(scope, callData->thisObject, ScopedObject::Convert);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
ScopedObject proto(scope, V->prototype());
while (proto) {
- if (O->d() == proto->d()) {
- scope.result = Encode(true);
- return;
- }
+ if (O->d() == proto->d())
+ return Encode(true);
proto = proto->prototype();
}
- scope.result = Encode(false);
+ return Encode(false);
}
-void ObjectPrototype::method_propertyIsEnumerable(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_propertyIsEnumerable(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedString p(scope, callData->argument(0), ScopedString::Convert);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
ScopedObject o(scope, callData->thisObject, ScopedObject::Convert);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
PropertyAttributes attrs;
o->getOwnProperty(p, &attrs);
- scope.result = Encode(attrs.isEnumerable());
+ return Encode(attrs.isEnumerable());
}
-void ObjectPrototype::method_defineGetter(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_defineGetter(const BuiltinFunction *b, CallData *callData)
{
- if (callData->argc < 2)
+ Scope scope(b);
+ if (callData->argc() < 2)
THROW_TYPE_ERROR();
ScopedFunctionObject f(scope, callData->argument(1));
@@ -539,7 +549,8 @@ void ObjectPrototype::method_defineGetter(const BuiltinFunction *, Scope &scope,
THROW_TYPE_ERROR();
ScopedString prop(scope, callData->argument(0), ScopedString::Convert);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
ScopedObject o(scope, callData->thisObject);
if (!o) {
@@ -551,13 +562,16 @@ void ObjectPrototype::method_defineGetter(const BuiltinFunction *, Scope &scope,
ScopedProperty pd(scope);
pd->value = f;
pd->set = Primitive::emptyValue();
- o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor);
+ bool ok = o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor);
+ if (!ok)
+ THROW_TYPE_ERROR();
RETURN_UNDEFINED();
}
-void ObjectPrototype::method_defineSetter(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_defineSetter(const BuiltinFunction *b, CallData *callData)
{
- if (callData->argc < 2)
+ Scope scope(b);
+ if (callData->argc() < 2)
THROW_TYPE_ERROR();
ScopedFunctionObject f(scope, callData->argument(1));
@@ -565,7 +579,8 @@ void ObjectPrototype::method_defineSetter(const BuiltinFunction *, Scope &scope,
THROW_TYPE_ERROR();
ScopedString prop(scope, callData->argument(0), ScopedString::Convert);
- CHECK_EXCEPTION();
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
ScopedObject o(scope, callData->thisObject);
if (!o) {
@@ -577,23 +592,27 @@ void ObjectPrototype::method_defineSetter(const BuiltinFunction *, Scope &scope,
ScopedProperty pd(scope);
pd->value = Primitive::emptyValue();
pd->set = f;
- o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor);
+ bool ok = o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor);
+ if (!ok)
+ THROW_TYPE_ERROR();
RETURN_UNDEFINED();
}
-void ObjectPrototype::method_get_proto(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_get_proto(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->thisObject.as<Object>());
if (!o)
THROW_TYPE_ERROR();
- scope.result = o->prototype();
+ return Encode(o->prototype());
}
-void ObjectPrototype::method_set_proto(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue ObjectPrototype::method_set_proto(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
ScopedObject o(scope, callData->thisObject);
- if (!o || !callData->argc)
+ if (!o || !callData->argc())
THROW_TYPE_ERROR();
if (callData->args[0].isNull()) {
@@ -610,10 +629,8 @@ void ObjectPrototype::method_set_proto(const BuiltinFunction *, Scope &scope, Ca
ok = o->setPrototype(p);
}
}
- if (!ok) {
- scope.result = scope.engine->throwTypeError(QStringLiteral("Cyclic __proto__ value"));
- return;
- }
+ if (!ok)
+ return scope.engine->throwTypeError(QStringLiteral("Cyclic __proto__ value"));
RETURN_UNDEFINED();
}
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index 44b54267f3..7c97963baa 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -70,41 +70,41 @@ struct ObjectCtor: FunctionObject
{
V4_OBJECT2(ObjectCtor, FunctionObject)
- static void construct(const Managed *that, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *m, const Value *thisObject, const Value *argv, int argc);
};
struct ObjectPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
- 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_assign(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 ReturnedValue method_getPrototypeOf(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getOwnPropertyDescriptor(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_getOwnPropertyNames(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_assign(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_create(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_defineProperty(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_defineProperties(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_seal(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_freeze(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_preventExtensions(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_isSealed(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_isFrozen(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_isExtensible(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_keys(const BuiltinFunction *, CallData *callData);
+
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toLocaleString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_valueOf(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_hasOwnProperty(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_isPrototypeOf(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_propertyIsEnumerable(const BuiltinFunction *, CallData *callData);
+
+ static ReturnedValue method_defineGetter(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_defineSetter(const BuiltinFunction *, CallData *callData);
+
+ static ReturnedValue method_get_proto(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_set_proto(const BuiltinFunction *, 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/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index 9de597ad0e..9b71342467 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -59,9 +59,6 @@
#ifdef QT_NO_QML_DEBUGGER
-#define Q_V4_PROFILE_ALLOC(engine, size, type) (!engine)
-#define Q_V4_PROFILE_DEALLOC(engine, size, type) (!engine)
-#define Q_V4_PROFILE(engine, function) (function->code(engine, function->codeData))
QT_BEGIN_NAMESPACE
@@ -75,22 +72,6 @@ QT_END_NAMESPACE
#else
-#define Q_V4_PROFILE_ALLOC(engine, size, type)\
- (engine->profiler() &&\
- (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
- engine->profiler()->trackAlloc(size, type) : false)
-
-#define Q_V4_PROFILE_DEALLOC(engine, size, type) \
- (engine->profiler() &&\
- (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\
- engine->profiler()->trackDealloc(size, type) : false)
-
-#define Q_V4_PROFILE(engine, function)\
- (Q_UNLIKELY(engine->profiler()) &&\
- (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureFunctionCall)) ?\
- Profiling::FunctionCallProfiler::profileCall(engine->profiler(), engine, function) :\
- function->code(engine, function->codeData))
-
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -270,19 +251,21 @@ public:
// It's enough to ref() the function in the destructor as it will probably not disappear while
// it's executing ...
- FunctionCallProfiler(Profiler *profiler, Function *function) :
- profiler(profiler), function(function), startTime(profiler->m_timer.nsecsElapsed())
- {}
-
- ~FunctionCallProfiler()
+ FunctionCallProfiler(ExecutionEngine *engine, Function *f)
+ : profiler(0)
{
- profiler->m_data.append(FunctionCall(function, startTime, profiler->m_timer.nsecsElapsed()));
+ Profiler *p = engine->profiler();
+ if (Q_UNLIKELY(p) && (p->featuresEnabled & (1 << Profiling::FeatureFunctionCall))) {
+ profiler = p;
+ function = f;
+ startTime = profiler->m_timer.nsecsElapsed();
+ }
}
- static ReturnedValue profileCall(Profiler *profiler, ExecutionEngine *engine, Function *function)
+ ~FunctionCallProfiler()
{
- FunctionCallProfiler callProfiler(profiler, function);
- return function->code(engine, function->codeData);
+ if (profiler)
+ profiler->m_data.append(FunctionCall(function, startTime, profiler->m_timer.nsecsElapsed()));
}
Profiler *profiler;
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 8b9ef149d6..ce0c89be57 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -296,13 +296,9 @@ void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContex
{
Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext);
outer.set(internalClass->engine, outerContext->d());
- strictMode = false;
- callData = outer->callData;
- lookups = outer->lookups;
- constantTable = outer->constantTable;
- compilationUnit = outer->compilationUnit;
+ v4Function = outer->v4Function;
- this->qml.set(internalClass->engine, qml->d());
+ this->activation.set(internalClass->engine, qml->d());
}
Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, const QUrl &source, Value *sendFunction)
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 48c9ee2c36..f0782c7ee1 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -76,12 +76,12 @@ struct QQmlContextWrapper : Object {
QQmlQPointer<QObject> scopeObject;
};
-#define QmlContextMembers(class, Member) \
- Member(class, Pointer, QQmlContextWrapper *, qml)
+#define QmlContextMembers(class, Member)
DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext) {
DECLARE_MARK_TABLE(QmlContext);
+ QQmlContextWrapper *qml() { return static_cast<QQmlContextWrapper *>(activation.get()); }
void init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml);
};
@@ -109,10 +109,10 @@ struct Q_QML_EXPORT QmlContext : public ExecutionContext
static Heap::QmlContext *create(QV4::ExecutionContext *parent, QQmlContextData *context, QObject *scopeObject);
QObject *qmlScope() const {
- return d()->qml->scopeObject;
+ return d()->qml()->scopeObject;
}
QQmlContextData *qmlContext() const {
- return *d()->qml->context;
+ return *d()->qml()->context;
}
};
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index fb3aa47d1b..9746b82817 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -62,6 +62,7 @@
#include <private/qv4regexpobject_p.h>
#include <private/qv4dateobject_p.h>
#include <private/qv4scopedvalue_p.h>
+#include <private/qv4jscall_p.h>
#include <private/qv4mm_p.h>
#include <private/qqmlscriptstring_p.h>
#include <private/qv4compileddata_p.h>
@@ -468,11 +469,11 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
if (auto binding = QQmlPropertyPrivate::binding(object, QQmlPropertyIndex(property->coreIndex()))) {
Q_ASSERT(!binding->isValueTypeProxy());
const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
- const auto stackFrame = engine->currentStackFrame();
+ const auto stackFrame = engine->currentStackFrame;
qCInfo(lcBindingRemoval,
"Overwriting binding on %s::%s at %s:%d that was initially bound at %s",
object->metaObject()->className(), qPrintable(property->name(object)),
- qPrintable(stackFrame.source), stackFrame.line,
+ qPrintable(stackFrame->source()), stackFrame->lineNumber(),
qPrintable(qmlBinding->expressionIdentifier()));
}
}
@@ -815,18 +816,18 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
QV4::Scope scope(v4);
QV4::ScopedFunctionObject f(scope, This->function.value());
- QV4::ScopedCallData callData(scope, argCount);
- callData->thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value();
+ QV4::JSCallData jsCallData(scope, argCount);
+ *jsCallData->thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value();
for (int ii = 0; ii < argCount; ++ii) {
int type = argsTypes[ii + 1];
if (type == qMetaTypeId<QVariant>()) {
- callData->args[ii] = v4->fromVariant(*((QVariant *)metaArgs[ii + 1]));
+ jsCallData->args[ii] = v4->fromVariant(*((QVariant *)metaArgs[ii + 1]));
} else {
- callData->args[ii] = v4->fromVariant(QVariant(type, metaArgs[ii + 1]));
+ jsCallData->args[ii] = v4->fromVariant(QVariant(type, metaArgs[ii + 1]));
}
}
- f->call(scope, callData);
+ f->call(jsCallData);
if (scope.hasException()) {
QQmlError error = v4->catchExceptionAsQmlError();
if (error.description().isEmpty()) {
@@ -899,9 +900,11 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
} // namespace QV4
-void QObjectWrapper::method_connect(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue QObjectWrapper::method_connect(const BuiltinFunction *b, CallData *callData)
{
- if (callData->argc == 0)
+ QV4::Scope scope(b);
+
+ if (callData->argc() == 0)
THROW_GENERIC_ERROR("Function.prototype.connect: no arguments given");
QPair<QObject *, int> signalInfo = extractQtSignal(callData->thisObject);
@@ -920,9 +923,9 @@ void QObjectWrapper::method_connect(const BuiltinFunction *, Scope &scope, CallD
QV4::ScopedFunctionObject f(scope);
QV4::ScopedValue thisObject (scope, QV4::Encode::undefined());
- if (callData->argc == 1) {
+ if (callData->argc() == 1) {
f = callData->args[0];
- } else if (callData->argc >= 2) {
+ } else if (callData->argc() >= 2) {
thisObject = callData->args[0];
f = callData->args[1];
}
@@ -949,9 +952,11 @@ void QObjectWrapper::method_connect(const BuiltinFunction *, Scope &scope, CallD
RETURN_UNDEFINED();
}
-void QObjectWrapper::method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue QObjectWrapper::method_disconnect(const BuiltinFunction *b, CallData *callData)
{
- if (callData->argc == 0)
+ QV4::Scope scope(b);
+
+ if (callData->argc() == 0)
THROW_GENERIC_ERROR("Function.prototype.disconnect: no arguments given");
QPair<QObject *, int> signalInfo = extractQtSignal(callData->thisObject);
@@ -970,9 +975,9 @@ void QObjectWrapper::method_disconnect(const BuiltinFunction *, Scope &scope, Ca
QV4::ScopedFunctionObject functionValue(scope);
QV4::ScopedValue functionThisValue(scope, QV4::Encode::undefined());
- if (callData->argc == 1) {
+ if (callData->argc() == 1) {
functionValue = callData->args[0];
- } else if (callData->argc >= 2) {
+ } else if (callData->argc() >= 2) {
functionThisValue = callData->args[0];
functionValue = callData->args[1];
}
@@ -1412,7 +1417,7 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ
+ QLatin1String(unknownTypeError));
}
- if (args[0] > callArgs->argc) {
+ if (args[0] > callArgs->argc()) {
QString error = QLatin1String("Insufficient arguments");
return engine->throwError(error);
}
@@ -1443,7 +1448,7 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const
QV4::ExecutionEngine *engine, QV4::CallData *callArgs, const QQmlPropertyCache *propertyCache,
QMetaObject::Call callType = QMetaObject::InvokeMetaMethod)
{
- int argumentCount = callArgs->argc;
+ int argumentCount = callArgs->argc();
QQmlPropertyData best;
int bestParameterScore = INT_MAX;
@@ -1848,7 +1853,7 @@ const QMetaObject *Heap::QObjectMethod::metaObject()
return object()->metaObject();
}
-QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) const
+QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionEngine *engine) const
{
QString result;
if (const QMetaObject *metaObject = d()->metaObject()) {
@@ -1867,15 +1872,15 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) co
result = QLatin1String("null");
}
- return ctx->engine()->newString(result)->asReturnedValue();
+ return engine->newString(result)->asReturnedValue();
}
-QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const
+QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionEngine *engine, const Value *args, int argc) const
{
if (!d()->object())
return Encode::undefined();
if (QQmlData::keepAliveDuringGarbageCollection(d()->object()))
- return ctx->engine()->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object"));
+ return engine->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object"));
int delay = 0;
if (argc > 0)
@@ -1889,32 +1894,24 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con
return Encode::undefined();
}
-void QObjectMethod::call(const Managed *m, Scope &scope, CallData *callData)
+ReturnedValue QObjectMethod::call(const FunctionObject *m, const Value *thisObject, const Value *argv, int argc)
{
const QObjectMethod *This = static_cast<const QObjectMethod*>(m);
- This->callInternal(callData, scope);
+ return This->callInternal(thisObject, argv, argc);
}
-void QObjectMethod::callInternal(CallData *callData, Scope &scope) const
+ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value *argv, int argc) const
{
ExecutionEngine *v4 = engine();
- ExecutionContext *context = v4->currentContext;
- 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;
- }
+ if (d()->index == DestroyMethod)
+ return method_destroy(v4, argv, argc);
+ else if (d()->index == ToStringMethod)
+ return method_toString(v4);
QQmlObjectOrGadget object(d()->object());
if (!d()->object()) {
- if (!d()->valueTypeWrapper) {
- scope.result = Encode::undefined();
- return;
- }
+ if (!d()->valueTypeWrapper)
+ return Encode::undefined();
object = QQmlObjectOrGadget(d()->propertyCache(), d()->valueTypeWrapper->gadgetPtr);
}
@@ -1923,20 +1920,16 @@ void QObjectMethod::callInternal(CallData *callData, Scope &scope) const
if (d()->propertyCache()) {
QQmlPropertyData *data = d()->propertyCache()->method(d()->index);
- if (!data) {
- scope.result = QV4::Encode::undefined();
- return;
- }
+ if (!data)
+ return QV4::Encode::undefined();
method = *data;
} else {
const QMetaObject *mo = d()->object()->metaObject();
const QMetaMethod moMethod = mo->method(d()->index);
method.load(moMethod);
- if (method.coreIndex() == -1) {
- scope.result = QV4::Encode::undefined();
- return;
- }
+ if (method.coreIndex() == -1)
+ return QV4::Encode::undefined();
// Look for overloaded methods
QByteArray methodName = moMethod.name();
@@ -1951,21 +1944,25 @@ void QObjectMethod::callInternal(CallData *callData, Scope &scope) const
}
}
+ Scope scope(v4);
+ JSCallData cData(scope, argc, argv, thisObject);
+ CallData *callData = cData.callData();
+
if (method.isV4Function()) {
- scope.result = QV4::Encode::undefined();
- QQmlV4Function func(callData, &scope.result, v4);
+ QV4::ScopedValue rv(scope, QV4::Primitive::undefinedValue());
+ QQmlV4Function func(callData, rv, v4);
QQmlV4Function *funcptr = &func;
void *args[] = { 0, &funcptr };
object.metacall(QMetaObject::InvokeMetaMethod, method.coreIndex(), args);
- return;
+ return rv->asReturnedValue();
}
if (!method.isOverload()) {
- scope.result = CallPrecise(object, method, v4, callData);
+ return CallPrecise(object, method, v4, callData);
} else {
- scope.result = CallOverloaded(object, method, v4, callData, d()->propertyCache());
+ return CallOverloaded(object, method, v4, callData, d()->propertyCache());
}
}
@@ -2028,13 +2025,14 @@ void QMetaObjectWrapper::init(ExecutionEngine *) {
}
}
-void QMetaObjectWrapper::construct(const Managed *m, Scope &scope, CallData *callData)
+ReturnedValue QMetaObjectWrapper::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(m);
- scope.result = This->constructInternal(callData);
+ const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(f);
+ return This->constructInternal(argv, argc);
}
-ReturnedValue QMetaObjectWrapper::constructInternal(CallData * callData) const {
+ReturnedValue QMetaObjectWrapper::constructInternal(const Value *argv, int argc) const
+{
d()->ensureConstructorsCache();
@@ -2047,6 +2045,8 @@ ReturnedValue QMetaObjectWrapper::constructInternal(CallData * callData) const {
Scope scope(v4);
Scoped<QObjectWrapper> object(scope);
+ JSCallData cData(scope, argc, argv);
+ CallData *callData = cData.callData();
if (d()->constructorCount == 1) {
object = callConstructor(d()->constructors[0], v4, callData);
@@ -2071,7 +2071,7 @@ ReturnedValue QMetaObjectWrapper::callConstructor(const QQmlPropertyData &data,
ReturnedValue QMetaObjectWrapper::callOverloadedConstructor(QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const {
const int numberOfConstructors = d()->constructorCount;
- const int argumentCount = callArgs->argc;
+ const int argumentCount = callArgs->argc();
const QQmlStaticMetaObject object(d()->metaObject);
QQmlPropertyData best;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 018e444f7c..7b31fcc1e5 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -198,8 +198,8 @@ protected:
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static void markObjects(Heap::Base *that, QV4::MarkStack *markStack);
- static void method_connect(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_connect(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_disconnect(const BuiltinFunction *, CallData *callData);
private:
Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object);
@@ -234,12 +234,12 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
int methodIndex() const { return d()->index; }
QObject *object() const { return d()->object(); }
- QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx) const;
- QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const;
+ QV4::ReturnedValue method_toString(QV4::ExecutionEngine *engine) const;
+ QV4::ReturnedValue method_destroy(QV4::ExecutionEngine *ctx, const Value *args, int argc) const;
- static void call(const Managed *, Scope &scope, CallData *callData);
+ static ReturnedValue call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- void callInternal(CallData *callData, Scope &scope) const;
+ ReturnedValue callInternal(const Value *thisObject, const Value *argv, int argc) const;
static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function);
};
@@ -251,14 +251,14 @@ struct Q_QML_EXPORT QMetaObjectWrapper : public QV4::FunctionObject
V4_NEEDS_DESTROY
static ReturnedValue create(ExecutionEngine *engine, const QMetaObject* metaObject);
- static void construct(const Managed *, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *, const Value *argv, int argc);
static bool isEqualTo(Managed *a, Managed *b);
const QMetaObject *metaObject() const { return d()->metaObject; }
private:
void init(ExecutionEngine *engine);
- ReturnedValue constructInternal(CallData *callData) const;
+ ReturnedValue constructInternal(const Value *argv, int argc) const;
ReturnedValue callConstructor(const QQmlPropertyData &data, QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const;
ReturnedValue callOverloadedConstructor(QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const;
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 162f0fba57..fb49def317 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -62,7 +62,7 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets)
WTF::String s(string);
#if ENABLE(YARR_JIT)
- if (!jitCode()->isFallBack() && jitCode()->has16BitCode())
+ if (d()->hasValidJITCode())
return uint(jitCode()->execute(s.characters16(), start, s.length(), (int*)matchOffsets).start);
#endif
@@ -82,7 +82,7 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo
return result->d();
Scope scope(engine);
- Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline, global));
+ Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(pattern, ignoreCase, multiline, global));
result->d()->cache = cache;
cachedValue.set(engine, result);
@@ -90,7 +90,7 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo
return result->d();
}
-void Heap::RegExp::init(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline, bool global)
+void Heap::RegExp::init(const QString &pattern, bool ignoreCase, bool multiline, bool global)
{
Base::init();
this->pattern = new QString(pattern);
@@ -98,20 +98,28 @@ void Heap::RegExp::init(ExecutionEngine* engine, const QString &pattern, bool ig
this->multiLine = multiline;
this->global = global;
+ valid = false;
+
const char* error = 0;
- JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), ignoreCase, multiline, &error);
+ JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), ignoreCase, multiLine, &error);
if (error)
return;
subPatternCount = yarrPattern.m_numSubpatterns;
- OwnPtr<JSC::Yarr::BytecodePattern> p = JSC::Yarr::byteCompile(yarrPattern, engine->bumperPointerAllocator);
- byteCode = p.take();
#if ENABLE(YARR_JIT)
- jitCode = new JSC::Yarr::YarrCodeBlock;
- if (!yarrPattern.m_containsBackreferences && engine->iselFactory->jitCompileRegexps()) {
- JSC::JSGlobalData dummy(engine->regExpAllocator);
+ if (!yarrPattern.m_containsBackreferences) {
+ jitCode = new JSC::Yarr::YarrCodeBlock;
+ JSC::JSGlobalData dummy(internalClass->engine->regExpAllocator);
JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, *jitCode);
}
#endif
+ if (hasValidJITCode()) {
+ valid = true;
+ return;
+ }
+ OwnPtr<JSC::Yarr::BytecodePattern> p = JSC::Yarr::byteCompile(yarrPattern, internalClass->engine->bumperPointerAllocator);
+ byteCode = p.take();
+ if (byteCode)
+ valid = true;
}
void Heap::RegExp::destroy()
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index 998f6e3da3..498468e165 100644
--- a/src/qml/jsruntime/qv4regexp_p.h
+++ b/src/qml/jsruntime/qv4regexp_p.h
@@ -76,7 +76,7 @@ struct RegExpCacheKey;
namespace Heap {
struct RegExp : Base {
- void init(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline, bool global);
+ void init(const QString& pattern, bool ignoreCase, bool multiline, bool global);
void destroy();
QString *pattern;
@@ -84,11 +84,19 @@ struct RegExp : Base {
#if ENABLE(YARR_JIT)
JSC::Yarr::YarrCodeBlock *jitCode;
#endif
+ bool hasValidJITCode() const {
+#if ENABLE(YARR_JIT)
+ return jitCode && !jitCode->isFallBack() && jitCode->has16BitCode();
+#else
+ return false;
+#endif
+ }
RegExpCache *cache;
int subPatternCount;
bool ignoreCase;
bool multiLine;
bool global;
+ bool valid;
int captureCount() const { return subPatternCount + 1; }
};
@@ -116,7 +124,7 @@ struct RegExp : public Managed
static Heap::RegExp *create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false, bool global = false);
- bool isValid() const { return d()->byteCode; }
+ bool isValid() const { return d()->valid; }
uint match(const QString& string, int start, uint *matchOffsets);
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 83bfe21c67..3ff5349e74 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -38,20 +38,17 @@
****************************************************************************/
#include "qv4regexpobject_p.h"
-#include "qv4jsir_p.h"
-#include "qv4isel_p.h"
#include "qv4objectproto_p.h"
#include "qv4regexp_p.h"
#include "qv4stringobject_p.h"
#include <private/qv4mm_p.h>
#include "qv4scopedvalue_p.h"
+#include "qv4jscall_p.h"
#include <private/qqmljsengine_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
-#include <qv4jsir_p.h>
-#include <qv4codegen_p.h>
#include "private/qlocale_tools_p.h"
#include <QtCore/QDebug>
@@ -217,39 +214,33 @@ void Heap::RegExpCtor::clearLastMatch()
lastMatchEnd = 0;
}
-void RegExpCtor::construct(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue RegExpCtor::callAsConstructor(const FunctionObject *fo, const Value *argv, int argc)
{
- ScopedValue r(scope, callData->argument(0));
- ScopedValue f(scope, callData->argument(1));
+ Scope scope(fo->engine());
+ ScopedValue r(scope, argc ? argv[0] : Primitive::undefinedValue());
+ ScopedValue f(scope, argc > 1 ? argv[1] : Primitive::undefinedValue());
Scoped<RegExpObject> re(scope, r);
if (re) {
- if (!f->isUndefined()) {
- scope.result = scope.engine->throwTypeError();
- return;
- }
+ if (!f->isUndefined())
+ return scope.engine->throwTypeError();
Scoped<RegExp> regexp(scope, re->value());
- scope.result = Encode(scope.engine->newRegExpObject(regexp));
- return;
+ return Encode(scope.engine->newRegExpObject(regexp));
}
QString pattern;
if (!r->isUndefined())
pattern = r->toQString();
- if (scope.hasException()) {
- scope.result = Encode::undefined();
- return;
- }
+ if (scope.hasException())
+ return Encode::undefined();
bool global = false;
bool ignoreCase = false;
bool multiLine = false;
if (!f->isUndefined()) {
ScopedString s(scope, f->toString(scope.engine));
- if (scope.hasException()) {
- scope.result = Encode::undefined();
- return;
- }
+ if (scope.hasException())
+ return Encode::undefined();
QString str = s->toQString();
for (int i = 0; i < str.length(); ++i) {
if (str.at(i) == QLatin1Char('g') && !global) {
@@ -259,31 +250,27 @@ void RegExpCtor::construct(const Managed *, Scope &scope, CallData *callData)
} else if (str.at(i) == QLatin1Char('m') && !multiLine) {
multiLine = true;
} else {
- scope.result = scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor"));
- return;
+ return scope.engine->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor"));
}
}
}
Scoped<RegExp> regexp(scope, RegExp::create(scope.engine, pattern, ignoreCase, multiLine, global));
if (!regexp->isValid()) {
- scope.result = scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression"));
- return;
+ return scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression"));
}
- scope.result = Encode(scope.engine->newRegExpObject(regexp));
+ return Encode(scope.engine->newRegExpObject(regexp));
}
-void RegExpCtor::call(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue RegExpCtor::call(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
- if (callData->argc > 0 && callData->args[0].as<RegExpObject>()) {
- if (callData->argc == 1 || callData->args[1].isUndefined()) {
- scope.result = callData->args[0];
- return;
- }
+ if (argc > 0 && argv[0].as<RegExpObject>()) {
+ if (argc == 1 || argv[1].isUndefined())
+ return Encode(argv[0]);
}
- construct(that, scope, callData);
+ return callAsConstructor(f, argv, argc);
}
void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
@@ -323,11 +310,58 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
defineDefaultProperty(QStringLiteral("compile"), method_compile, 2);
}
-void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallData *callData)
+/* used by String.match */
+ReturnedValue RegExpPrototype::execFirstMatch(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
+ Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
+ Q_ASSERT(r && r->global());
+
+ ScopedString str(scope, callData->args[0]);
+ Q_ASSERT(str);
+ QString s = str->toQString();
+
+ int offset = r->lastIndex();
+ if (offset < 0 || offset > s.length()) {
+ r->setLastIndex(0);
+ RETURN_RESULT(Encode::null());
+ }
+
+ Q_ALLOCA_VAR(uint, matchOffsets, r->value()->captureCount() * 2 * sizeof(uint));
+ const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets);
+
+ RegExpCtor *regExpCtor = static_cast<RegExpCtor *>(scope.engine->regExpCtor());
+ regExpCtor->d()->clearLastMatch();
+
+ if (result == -1) {
+ r->setLastIndex(0);
+ RETURN_RESULT(Encode::null());
+ }
+
+ ReturnedValue retVal = Encode::undefined();
+ // return first match
+ if (r->value()->captureCount()) {
+ int start = matchOffsets[0];
+ int end = matchOffsets[1];
+ retVal = (start != -1) ? scope.engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
+ }
+
+ RegExpCtor::Data *dd = regExpCtor->d();
+ dd->lastInput.set(scope.engine, str->d());
+ dd->lastMatchStart = matchOffsets[0];
+ dd->lastMatchEnd = matchOffsets[1];
+
+ r->setLastIndex(matchOffsets[1]);
+
+ return retVal;
+}
+
+ReturnedValue RegExpPrototype::method_exec(const BuiltinFunction *b, CallData *callData)
+{
+ Scope scope(b);
Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
if (!r)
- THROW_TYPE_ERROR();
+ return scope.engine->throwTypeError();
ScopedValue arg(scope, callData->argument(0));
ScopedString str(scope, arg->toString(scope.engine));
@@ -344,7 +378,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
Q_ALLOCA_VAR(uint, matchOffsets, r->value()->captureCount() * 2 * sizeof(uint));
const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets);
- Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
+ RegExpCtor *regExpCtor = static_cast<RegExpCtor *>(scope.engine->regExpCtor());
regExpCtor->d()->clearLastMatch();
if (result == -1) {
@@ -376,73 +410,81 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
if (r->global())
r->setLastIndex(matchOffsets[1]);
- scope.result = array;
+ return array.asReturnedValue();
}
-void RegExpPrototype::method_test(const BuiltinFunction *b, Scope &scope, CallData *callData)
+ReturnedValue RegExpPrototype::method_test(const BuiltinFunction *b, CallData *callData)
{
- method_exec(b, scope, callData);
- scope.result = Encode(!scope.result.isNull());
+ Value res = Value::fromReturnedValue(method_exec(b, callData));
+ return Encode(!res.isNull());
}
-void RegExpPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue RegExpPrototype::method_toString(const BuiltinFunction *b, CallData *callData)
{
- Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
+ ExecutionEngine *v4 = b->engine();
+ RegExpObject *r = callData->thisObject.as<RegExpObject>();
if (!r)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
- scope.result = scope.engine->newString(r->toString());
+ return Encode(v4->newString(r->toString()));
}
-void RegExpPrototype::method_compile(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue RegExpPrototype::method_compile(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
if (!r)
- THROW_TYPE_ERROR();
+ return scope.engine->throwTypeError();
- ScopedCallData cData(scope, callData->argc);
- memcpy(cData->args, callData->args, callData->argc*sizeof(Value));
+ JSCallData jsCallData(scope, callData->argc());
+ memcpy(jsCallData->args, callData->args, callData->argc()*sizeof(Value));
- scope.engine->regExpCtor()->as<FunctionObject>()->construct(scope, cData);
- Scoped<RegExpObject> re(scope, scope.result.asReturnedValue());
+ Scoped<RegExpObject> re(scope, scope.engine->regExpCtor()->callAsConstructor(jsCallData));
r->d()->value.set(scope.engine, re->value());
+ return Encode::undefined();
}
template <int index>
-void RegExpPrototype::method_get_lastMatch_n(const BuiltinFunction *, Scope &scope, CallData *)
+ReturnedValue RegExpPrototype::method_get_lastMatch_n(const BuiltinFunction *b, CallData *)
{
+ Scope scope(b);
ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastMatch());
- scope.result = lastMatch ? lastMatch->getIndexed(index) : Encode::undefined();
- if (scope.result.isUndefined())
- scope.result = scope.engine->newString();
+ ScopedValue res(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined());
+ if (res->isUndefined())
+ res = scope.engine->newString();
+ return res->asReturnedValue();
}
-void RegExpPrototype::method_get_lastParen(const BuiltinFunction *, Scope &scope, CallData *)
+ReturnedValue RegExpPrototype::method_get_lastParen(const BuiltinFunction *b, CallData *)
{
+ Scope scope(b);
ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastMatch());
- scope.result = lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined();
- if (scope.result.isUndefined())
- scope.result = scope.engine->newString();
+ ScopedValue res(scope, lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined());
+ if (res->isUndefined())
+ res = scope.engine->newString();
+ return res->asReturnedValue();
}
-void RegExpPrototype::method_get_input(const BuiltinFunction *, Scope &scope, CallData *)
+ReturnedValue RegExpPrototype::method_get_input(const BuiltinFunction *b, CallData *)
{
- scope.result = static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastInput();
+ return static_cast<RegExpCtor*>(b->engine()->regExpCtor())->lastInput()->asReturnedValue();
}
-void RegExpPrototype::method_get_leftContext(const BuiltinFunction *, Scope &scope, CallData *)
+ReturnedValue RegExpPrototype::method_get_leftContext(const BuiltinFunction *b, CallData *)
{
+ Scope scope(b);
Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
QString lastInput = regExpCtor->lastInput()->toQString();
- scope.result = scope.engine->newString(lastInput.left(regExpCtor->lastMatchStart()));
+ return Encode(scope.engine->newString(lastInput.left(regExpCtor->lastMatchStart())));
}
-void RegExpPrototype::method_get_rightContext(const BuiltinFunction *, Scope &scope, CallData *)
+ReturnedValue RegExpPrototype::method_get_rightContext(const BuiltinFunction *b, CallData *)
{
+ Scope scope(b);
Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
QString lastInput = regExpCtor->lastInput()->toQString();
- scope.result = scope.engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()));
+ return Encode(scope.engine->newString(lastInput.mid(regExpCtor->lastMatchEnd())));
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 65055ccc81..1f92516928 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -55,8 +55,6 @@
#include "qv4context_p.h"
#include "qv4functionobject_p.h"
#include "qv4string_p.h"
-#include <qv4codegen_p.h>
-#include <qv4isel_p.h>
#include "qv4managed_p.h"
#include "qv4property_p.h"
#include "qv4objectiterator_p.h"
@@ -106,7 +104,7 @@ struct RegExpObject: Object {
V4_INTERNALCLASS(RegExpObject)
V4_PROTOTYPE(regExpPrototype)
- // needs to be compatible with the flags in qv4jsir_p.h
+ // needs to be compatible with the flags in qv4compileddata_p.h
enum Flags {
RegExp_Global = 0x01,
RegExp_IgnoreCase = 0x02,
@@ -152,25 +150,27 @@ struct RegExpCtor: FunctionObject
int lastMatchStart() { return d()->lastMatchStart; }
int lastMatchEnd() { return d()->lastMatchEnd; }
- static void construct(const Managed *m, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
struct RegExpPrototype: RegExpObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static void method_exec(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_test(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_compile(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_exec(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_test(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_compile(const BuiltinFunction *, CallData *callData);
template <int index>
- static void method_get_lastMatch_n(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_get_lastParen(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_get_input(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_get_leftContext(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_get_rightContext(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_get_lastMatch_n(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_get_lastParen(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_get_input(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_get_leftContext(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_get_rightContext(const BuiltinFunction *, CallData *callData);
+
+ static ReturnedValue execFirstMatch(const BuiltinFunction *b, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 4b952bcbbc..7a5d114271 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -55,6 +55,7 @@
#include "qv4regexpobject_p.h"
#include "private/qlocale_tools_p.h"
#include "qv4scopedvalue_p.h"
+#include "qv4jscall_p.h"
#include <private/qv4qmlcontext_p.h>
#include <private/qqmltypewrapper_p.h>
#include <private/qqmlengine_p.h>
@@ -310,47 +311,47 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId)
{
- QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->runtimeFunctions[functionId];
+ QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId];
Q_ASSERT(clos);
- return FunctionObject::createScriptFunction(engine->currentContext, clos)->asReturnedValue();
+ ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
+ return FunctionObject::createScriptFunction(current, clos)->asReturnedValue();
}
-ReturnedValue Runtime::method_deleteElement(ExecutionEngine *engine, const Value &base, const Value &index)
+bool Runtime::method_deleteElement(ExecutionEngine *engine, const Value &base, const Value &index)
{
Scope scope(engine);
ScopedObject o(scope, base);
if (o) {
uint n = index.asArrayIndex();
- if (n < UINT_MAX) {
- return Encode((bool)o->deleteIndexedProperty(n));
- }
+ if (n < UINT_MAX)
+ return o->deleteIndexedProperty(n);
}
ScopedString name(scope, index.toString(engine));
return method_deleteMemberString(engine, base, name);
}
-ReturnedValue Runtime::method_deleteMember(ExecutionEngine *engine, const Value &base, int nameIndex)
+bool Runtime::method_deleteMember(ExecutionEngine *engine, const Value &base, int nameIndex)
{
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
return method_deleteMemberString(engine, base, name);
}
-ReturnedValue Runtime::method_deleteMemberString(ExecutionEngine *engine, const Value &base, String *name)
+bool Runtime::method_deleteMemberString(ExecutionEngine *engine, const Value &base, String *name)
{
Scope scope(engine);
ScopedObject obj(scope, base.toObject(engine));
if (scope.engine->hasException)
return Encode::undefined();
- return Encode(obj->deleteProperty(name));
+ return obj->deleteProperty(name);
}
-ReturnedValue Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex)
+bool Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
- return Encode(engine->currentContext->deleteProperty(name));
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).deleteProperty(name);
}
QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &lval, const Value &rval)
@@ -425,14 +426,13 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH
qSwap(meth1, meth2);
Scope scope(engine);
- ScopedCallData callData(scope, 0);
- callData->thisObject = *object;
-
+ ScopedValue result(scope);
ScopedValue conv(scope, object->get(meth1));
+
if (FunctionObject *o = conv->as<FunctionObject>()) {
- o->call(scope, callData);
- if (scope.result.isPrimitive())
- return scope.result.asReturnedValue();
+ result = o->call(object, nullptr, 0);
+ if (result->isPrimitive())
+ return result->asReturnedValue();
}
if (engine->hasException)
@@ -440,9 +440,9 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(const Object *object, int typeH
conv = object->get(meth2);
if (FunctionObject *o = conv->as<FunctionObject>()) {
- o->call(scope, callData);
- if (scope.result.isPrimitive())
- return scope.result.asReturnedValue();
+ result = o->call(object, nullptr, 0);
+ if (result->isPrimitive())
+ return result->asReturnedValue();
}
return engine->throwTypeError();
@@ -469,8 +469,9 @@ Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Val
}
}
-Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Value &value)
+Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, Value value, TypeHint hint)
{
+ redo:
switch (value.type()) {
case Value::Empty_Type:
Q_ASSERT(!"empty Value encountered");
@@ -484,15 +485,15 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val
return engine->id_true()->d();
else
return engine->id_false()->d();
- case Value::Managed_Type:
- if (String *s = value.stringValue())
- return s->d();
- {
- Scope scope(engine);
- ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, STRING_HINT));
- Q_ASSERT(!prim->isManaged() || prim->isString());
- return RuntimeHelpers::convertToString(engine, prim);
- }
+ case Value::Managed_Type: {
+ if (value.isString())
+ return static_cast<const String &>(value).d();
+ value = Primitive::fromReturnedValue(RuntimeHelpers::toPrimitive(value, hint));
+ Q_ASSERT(value.isPrimitive());
+ if (value.isString())
+ return static_cast<const String &>(value).d();
+ goto redo;
+ }
case Value::Integer_Type:
return RuntimeHelpers::stringFromNumber(engine, value.int_32());
default: // double
@@ -502,34 +503,9 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val
// This is slightly different from the method above, as
// the + operator requires a slightly different conversion
-static Heap::String *convert_to_string_add(ExecutionEngine *engine, const Value &value)
+static Heap::String *convert_to_string_add(ExecutionEngine *engine, Value value)
{
- switch (value.type()) {
- case Value::Empty_Type:
- Q_ASSERT(!"empty Value encountered");
- Q_UNREACHABLE();
- case Value::Undefined_Type:
- return engine->id_undefined()->d();
- case Value::Null_Type:
- return engine->id_null()->d();
- case Value::Boolean_Type:
- if (value.booleanValue())
- return engine->id_true()->d();
- else
- return engine->id_false()->d();
- case Value::Managed_Type:
- if (String *s = value.stringValue())
- return s->d();
- {
- Scope scope(engine);
- ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, PREFERREDTYPE_HINT));
- return RuntimeHelpers::convertToString(engine, prim);
- }
- case Value::Integer_Type:
- return RuntimeHelpers::stringFromNumber(engine, value.int_32());
- default: // double
- return RuntimeHelpers::stringFromNumber(engine, value.doubleValue());
- } // switch
+ return RuntimeHelpers::convertToString(engine, value, PREFERREDTYPE_HINT);
}
QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -549,7 +525,7 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu
pright = convert_to_string_add(engine, pright);
sright = static_cast<String *>(pright.ptr);
}
- if (scope.engine->hasException)
+ if (engine->hasException)
return Encode::undefined();
if (!sleft->d()->length())
return sright->asReturnedValue();
@@ -563,42 +539,14 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu
return Encode(x + y);
}
-QV4::ReturnedValue Runtime::method_addString(ExecutionEngine *engine, const Value &left, const Value &right)
+bool Runtime::method_storeProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)
{
- Q_ASSERT(left.isString() || right.isString());
-
Scope scope(engine);
- ScopedValue pleft(scope, left);
- ScopedValue pright(scope, right);
- String *sleft = pleft->stringValue();
- String *sright = pright->stringValue();
-
- if (!sleft) {
- pleft = convert_to_string_add(engine, pleft);
- sleft = static_cast<String *>(pleft.ptr);
- }
- if (!sright) {
- pright = convert_to_string_add(engine, pright);
- sright = static_cast<String *>(pright.ptr);
- }
- if (scope.engine->hasException)
- return Encode::undefined();
- if (!sleft->d()->length())
- return pright->asReturnedValue();
- if (!sright->d()->length())
- return pleft->asReturnedValue();
- MemoryManager *mm = engine->memoryManager;
- return (mm->alloc<String>(sleft->d(), sright->d()))->asReturnedValue();
-}
-
-void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)
-{
- Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
ScopedObject o(scope, object.toObject(engine));
if (!o)
- return;
- o->put(name, value);
+ return false;
+ return o->put(name, value);
}
static Q_NEVER_INLINE ReturnedValue getElementIntFallback(ExecutionEngine *engine, const Value &object, uint idx)
@@ -656,7 +604,7 @@ static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine,
return o->get(name);
}
-ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &object, const Value &index)
+ReturnedValue Runtime::method_loadElement(ExecutionEngine *engine, const Value &object, const Value &index)
{
uint idx;
if (index.asArrayIndex(idx)) {
@@ -677,12 +625,12 @@ ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &o
return getElementFallback(engine, object, index);
}
-static Q_NEVER_INLINE void setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
+static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
Scope scope(engine);
ScopedObject o(scope, object.toObject(engine));
if (engine->hasException)
- return;
+ return false;
uint idx;
if (index.asArrayIndex(idx)) {
@@ -690,18 +638,17 @@ static Q_NEVER_INLINE void setElementFallback(ExecutionEngine *engine, const Val
Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
if (idx < s->values.size) {
s->setData(engine, idx, value);
- return;
+ return true;
}
}
- o->putIndexed(idx, value);
- return;
+ return o->putIndexed(idx, value);
}
ScopedString name(scope, index.toString(engine));
- o->put(name, value);
+ return o->put(name, value);
}
-void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
+bool Runtime::method_storeElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
uint idx;
if (index.asArrayIndex(idx)) {
@@ -712,7 +659,7 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
if (idx < s->values.size) {
s->setData(engine, idx, value);
- return;
+ return true;
}
}
}
@@ -742,17 +689,31 @@ ReturnedValue Runtime::method_foreachNextPropertyName(const Value &foreach_itera
}
-void Runtime::method_setActivationProperty(ExecutionEngine *engine, int nameIndex, const Value &value)
+void Runtime::method_storeNameSloppy(ExecutionEngine *engine, int nameIndex, const Value &value)
+{
+ Scope scope(engine);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value);
+
+ if (e == ExecutionContext::RangeError)
+ engine->globalObject->put(name, value);
+}
+
+void Runtime::method_storeNameStrict(ExecutionEngine *engine, int nameIndex, const Value &value)
{
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
- engine->currentContext->setProperty(name, value);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value);
+ if (e == ExecutionContext::TypeError)
+ engine->throwTypeError();
+ else if (e == ExecutionContext::RangeError)
+ engine->throwReferenceError(name);
}
-ReturnedValue Runtime::method_getProperty(ExecutionEngine *engine, const Value &object, int nameIndex)
+ReturnedValue Runtime::method_loadProperty(ExecutionEngine *engine, const Value &object, int nameIndex)
{
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
ScopedObject o(scope, object);
if (o)
@@ -769,11 +730,11 @@ ReturnedValue Runtime::method_getProperty(ExecutionEngine *engine, const Value &
return o->get(name);
}
-ReturnedValue Runtime::method_getActivationProperty(ExecutionEngine *engine, int nameIndex)
+ReturnedValue Runtime::method_loadName(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
- return engine->currentContext->getProperty(name);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name);
}
#endif // V4_BOOTSTRAP
@@ -1002,233 +963,142 @@ uint Runtime::method_compareIn(ExecutionEngine *engine, const Value &left, const
}
-ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint index, CallData *callData)
+ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint index, Value *argv, int argc)
{
- Scope scope(engine);
- Q_ASSERT(callData->thisObject.isUndefined());
-
- Lookup *l = engine->current->lookups + index;
- ScopedFunctionObject o(scope, l->globalGetter(l, engine));
- if (!o)
+ Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index;
+ Value function = Value::fromReturnedValue(l->globalGetter(l, engine));
+ if (!function.isFunctionObject())
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())) {
- static_cast<EvalFunction *>(o.getPointer())->evalCall(scope, callData, true);
- } else {
- o->call(scope, callData);
- }
-
- return scope.result.asReturnedValue();
+ Value thisObject = Primitive::undefinedValue();
+ return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc);
}
-
-ReturnedValue Runtime::method_callActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
+ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Value *argv, int argc)
{
- Q_ASSERT(callData->thisObject.isUndefined());
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
+ ScopedValue thisObject(scope);
- ScopedObject base(scope);
- ScopedValue func(scope, engine->currentContext->getPropertyAndBase(name, base.getRef()));
- if (scope.engine->hasException)
+ ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
+ ScopedFunctionObject function(scope, ctx.getPropertyAndBase(engine->id_eval(), thisObject));
+ if (engine->hasException)
return Encode::undefined();
- if (base)
- callData->thisObject = base;
-
- FunctionObject *o = func->as<FunctionObject>();
- if (!o) {
+ if (!function) {
QString objectAsString = QStringLiteral("[null]");
- if (base)
- objectAsString = ScopedValue(scope, base.asReturnedValue())->toQStringNoThrow();
- QString msg = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString()).arg(objectAsString);
+ if (!thisObject->isUndefined())
+ objectAsString = thisObject->toQStringNoThrow();
+ QString msg = QStringLiteral("Property 'eval' of object %2 is not a function").arg(objectAsString);
return engine->throwTypeError(msg);
}
- if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) {
- static_cast<EvalFunction *>(o)->evalCall(scope, callData, true);
- } else {
- o->call(scope, callData);
- }
+ if (function->d() == engine->evalFunction()->d())
+ return static_cast<EvalFunction *>(function.getPointer())->evalCall(thisObject, argv, argc, true);
- return scope.result.asReturnedValue();
+ return function->call(thisObject, argv, argc);
}
-ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData)
+ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, Value *argv, int argc)
{
Scope scope(engine);
- ScopedFunctionObject o(scope, method_getQmlScopeObjectProperty(engine, callData->thisObject, propertyIndex, /*captureRequired*/true));
- if (!o) {
- QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex);
- return engine->throwTypeError(error);
- }
+ ScopedValue thisObject(scope);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- o->call(scope, callData);
- return scope.result.asReturnedValue();
-}
+ ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
+ ScopedFunctionObject f(scope, ctx.getPropertyAndBase(name, thisObject));
+ if (engine->hasException)
+ return Encode::undefined();
-ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engine, int propertyIndex, CallData *callData)
-{
- Scope scope(engine);
- ScopedFunctionObject o(scope, method_getQmlContextObjectProperty(engine, callData->thisObject, propertyIndex, /*captureRequired*/true));
- if (!o) {
- QString error = QStringLiteral("Property '%1' of context object is not a function").arg(propertyIndex);
- return engine->throwTypeError(error);
+ if (!f) {
+ QString objectAsString = QStringLiteral("[null]");
+ if (!thisObject->isUndefined())
+ objectAsString = thisObject->toQStringNoThrow();
+ QString msg = QStringLiteral("Property '%1' of object %2 is not a function")
+ .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString(),
+ objectAsString);
+ return engine->throwTypeError(msg);
}
- o->call(scope, callData);
- return scope.result.asReturnedValue();
+ return f->call(thisObject, argv, argc);
}
-ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
+ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)
{
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
- ScopedObject baseObject(scope, callData->thisObject);
- if (!baseObject) {
- Q_ASSERT(!callData->thisObject.isEmpty());
- if (callData->thisObject.isNullOrUndefined()) {
- QString message = QStringLiteral("Cannot call method '%1' of %2").arg(name->toQString()).arg(callData->thisObject.toQStringNoThrow());
+
+ if (!base->isObject()) {
+ Q_ASSERT(!base->isEmpty());
+ if (base->isNullOrUndefined()) {
+ QString message = QStringLiteral("Cannot call method '%1' of %2")
+ .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString(),
+ base->toQStringNoThrow());
return engine->throwTypeError(message);
}
- baseObject = RuntimeHelpers::convertToObject(scope.engine, callData->thisObject);
- if (!baseObject) // type error
+ ScopedValue thisObject(scope, RuntimeHelpers::convertToObject(engine, *base));
+ if (engine->hasException) // type error
return Encode::undefined();
- callData->thisObject = baseObject.asReturnedValue();
+ base = thisObject;
}
- ScopedFunctionObject o(scope, baseObject->get(name));
- 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());
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ ScopedFunctionObject f(scope, static_cast<Object *>(base)->get(name));
+
+ if (!f) {
+ QString error = QStringLiteral("Property '%1' of object %2 is not a function")
+ .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString(),
+ base->toQStringNoThrow());
return engine->throwTypeError(error);
}
+ return f->call(base, argv, argc);
}
-ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData)
-{
- Lookup *l = engine->current->lookups + index;
- Value v;
- v = l->getter(l, engine, callData->thisObject);
- Object *o = v.objectValue();
- if (Q_LIKELY(o)) {
- Scope scope(engine);
- o->call(scope, callData);
- return scope.result.asReturnedValue();
- }
- return engine->throwTypeError();
-}
-
-ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, const Value &index, CallData *callData)
+ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc)
{
- Scope scope(engine);
- ScopedObject baseObject(scope, callData->thisObject.toObject(engine));
- ScopedString s(scope, index.toString(engine));
-
- if (scope.engine->hasException)
- return Encode::undefined();
- callData->thisObject = baseObject;
+ Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index;
+ // ok to have the value on the stack here
+ Value f = Value::fromReturnedValue(l->getter(l, engine, *base));
- ScopedObject o(scope, baseObject->get(s));
- if (!o)
+ if (!f.isFunctionObject())
return engine->throwTypeError();
- o->call(scope, callData);
- return scope.result.asReturnedValue();
-}
-
-ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, CallData *callData)
-{
- if (Object *o = func.objectValue()) {
- Scope scope(engine);
- o->call(scope, callData);
- return scope.result.asReturnedValue();
- }
- return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
+ return static_cast<FunctionObject &>(f).call(base, argv, argc);
}
-
-ReturnedValue Runtime::method_constructGlobalLookup(ExecutionEngine *engine, uint index, CallData *callData)
+ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base, const Value &index, Value *argv, int argc)
{
Scope scope(engine);
- Q_ASSERT(callData->thisObject.isUndefined());
-
- Lookup *l = engine->current->lookups + index;
- ScopedObject f(scope, l->globalGetter(l, engine));
- if (f) {
- f->construct(scope, callData);
- return scope.result.asReturnedValue();
- } else {
- return engine->throwTypeError();
- }
-}
-
+ ScopedValue thisObject(scope, base->toObject(engine));
+ base = thisObject;
-ReturnedValue Runtime::method_constructActivationProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
-{
- Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
- ScopedValue func(scope, engine->currentContext->getProperty(name));
- if (scope.engine->hasException)
+ ScopedString str(scope, index.toString(engine));
+ if (engine->hasException)
return Encode::undefined();
- Object *f = func->as<Object>();
+ ScopedFunctionObject f(scope, static_cast<Object *>(base)->get(str));
if (!f)
return engine->throwTypeError();
- f->construct(scope, callData);
- return scope.result.asReturnedValue();
+ return f->call(base, argv, argc);
}
-ReturnedValue Runtime::method_constructValue(ExecutionEngine *engine, const Value &func, CallData *callData)
+ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, Value *argv, int argc)
{
- const Object *f = func.as<Object>();
- if (!f)
- return engine->throwTypeError();
-
- Scope scope(engine);
- f->construct(scope, callData);
- return scope.result.asReturnedValue();
+ if (!func.isFunctionObject())
+ return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
+ return static_cast<const FunctionObject &>(func).call(nullptr, argv, argc);
}
-ReturnedValue Runtime::method_constructProperty(ExecutionEngine *engine, int nameIndex, CallData *callData)
-{
- Scope scope(engine);
- ScopedObject thisObject(scope, callData->thisObject.toObject(engine));
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
- if (scope.engine->hasException)
- return Encode::undefined();
- ScopedObject f(scope, thisObject->get(name));
- if (f) {
- Scope scope(engine);
- f->construct(scope, callData);
- return scope.result.asReturnedValue();
- } else {
+ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &function, Value *argv, int argc)
+{
+ if (!function.isFunctionObject())
return engine->throwTypeError();
- }
-}
-ReturnedValue Runtime::method_constructPropertyLookup(ExecutionEngine *engine, uint index, CallData *callData)
-{
- Lookup *l = engine->current->lookups + index;
- Value v;
- v = l->getter(l, engine, callData->thisObject);
- Object *o = v.objectValue();
- if (Q_LIKELY(o)) {
- Scope scope(engine);
- o->construct(scope, callData);
- return scope.result.asReturnedValue();
- }
- return engine->throwTypeError();
+ return static_cast<const FunctionObject &>(function).callAsConstructor(argv, argc);
}
-
void Runtime::method_throwException(ExecutionEngine *engine, const Value &value)
{
if (!value.isEmpty())
@@ -1267,96 +1137,37 @@ ReturnedValue Runtime::method_typeofValue(ExecutionEngine *engine, const Value &
QV4::ReturnedValue Runtime::method_typeofName(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
- ScopedValue prop(scope, engine->currentContext->getProperty(name));
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ ScopedValue prop(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name));
// typeof doesn't throw. clear any possible exception
scope.engine->hasException = false;
return method_typeofValue(engine, prop);
}
-#ifndef V4_BOOTSTRAP
-ReturnedValue Runtime::method_typeofScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
-{
- Scope scope(engine);
- ScopedValue prop(scope, method_getQmlScopeObjectProperty(engine, context, propertyIndex, /*captureRequired*/true));
- if (scope.engine->hasException)
- return Encode::undefined();
- return method_typeofValue(engine, prop);
-}
-
-ReturnedValue Runtime::method_typeofContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex)
-{
- Scope scope(engine);
- ScopedValue prop(scope, method_getQmlContextObjectProperty(engine, context, propertyIndex, /*captureRequired*/true));
- if (scope.engine->hasException)
- return Encode::undefined();
- return method_typeofValue(engine, prop);
-}
-#endif // V4_BOOTSTRAP
-
-QV4::ReturnedValue Runtime::method_typeofMember(ExecutionEngine *engine, const Value &base, int nameIndex)
-{
- Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
- ScopedObject obj(scope, base.toObject(engine));
- if (scope.engine->hasException)
- return Encode::undefined();
- ScopedValue prop(scope, obj->get(name));
- return method_typeofValue(engine, prop);
-}
-
-QV4::ReturnedValue Runtime::method_typeofElement(ExecutionEngine *engine, const Value &base, const Value &index)
-{
- Scope scope(engine);
- ScopedString name(scope, index.toString(engine));
- ScopedObject obj(scope, base.toObject(engine));
- if (scope.engine->hasException)
- return Encode::undefined();
- ScopedValue prop(scope, obj->get(name));
- return method_typeofValue(engine, prop);
-}
-
-ReturnedValue Runtime::method_unwindException(ExecutionEngine *engine)
-{
- if (!engine->hasException)
- return Primitive::emptyValue().asReturnedValue();
- return engine->catchException(0);
-}
-
/* The next three methods are a bit tricky. They can't open up a Scope, as that
* would mess up the pushing of the context.
*
* Instead the push/pop pair acts as a non local scope.
*/
-void Runtime::method_pushWithScope(const Value &o, NoThrowEngine *engine)
-{
- QV4::Value *v = engine->jsAlloca(1);
- Heap::Object *withObject = o.toObject(engine);
- *v = withObject;
- engine->pushContext(engine->currentContext->newWithContext(withObject));
- Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
-}
-
-void Runtime::method_pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex)
+ReturnedValue Runtime::method_createWithContext(ExecutionContext *parent, const Value &o)
{
- engine->jsAlloca(1); // keep this symmetric with pushWithScope
- ExecutionContext *c = engine->currentContext;
- engine->pushContext(c->newCatchContext(c->d()->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0)));
- Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
+ Q_ASSERT(o.isObject());
+ const Object &obj = static_cast<const Object &>(o);
+ return parent->newWithContext(obj.d())->asReturnedValue();
}
-void Runtime::method_popScope(NoThrowEngine *engine)
+ReturnedValue Runtime::method_createCatchContext(ExecutionContext *parent, int exceptionVarNameIndex)
{
- Q_ASSERT(engine->jsStackTop == engine->currentContext + 2);
- engine->popContext();
- engine->jsStackTop -= 3;
+ ExecutionEngine *e = parent->engine();
+ return parent->newCatchContext(e->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex],
+ e->catchException(0))->asReturnedValue();
}
void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex)
{
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
- engine->currentContext->createMutableBinding(name, deletable);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).createMutableBinding(name, deletable);
}
ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *values, uint length)
@@ -1367,7 +1178,7 @@ ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *value
ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)
{
Scope scope(engine);
- QV4::InternalClass *klass = static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->runtimeClasses[classId];
+ QV4::InternalClass *klass = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeClasses[classId];
ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype()));
{
@@ -1406,134 +1217,49 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::
return o.asReturnedValue();
}
-QV4::ReturnedValue Runtime::method_setupArgumentsObject(ExecutionEngine *engine)
+QV4::ReturnedValue Runtime::method_createMappedArgumentsObject(ExecutionEngine *engine)
{
- Q_ASSERT(engine->current->type == Heap::ExecutionContext::Type_CallContext);
- QV4::CallContext *c = static_cast<QV4::CallContext *>(engine->currentContext);
- QV4::InternalClass *ic = engine->internalClasses[c->d()->strictMode ? EngineBase::Class_StrictArgumentsObject : EngineBase::Class_ArgumentsObject];
- return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->objectPrototype(), c)->asReturnedValue();
+ Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext);
+ QV4::CallContext *c = static_cast<QV4::CallContext *>(&engine->currentStackFrame->jsFrame->context);
+ QV4::InternalClass *ic = engine->internalClasses[EngineBase::Class_ArgumentsObject];
+ return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->objectPrototype(), c, false)->asReturnedValue();
}
-#endif // V4_BOOTSTRAP
-
-QV4::ReturnedValue Runtime::method_increment(const Value &value)
+QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine *engine)
{
- TRACE1(value);
-
- if (value.isInteger() && value.integerValue() < INT_MAX)
- return Encode(value.integerValue() + 1);
- else {
- double d = value.toNumber();
- return Encode(d + 1.);
- }
-}
-
-QV4::ReturnedValue Runtime::method_decrement(const Value &value)
-{
- TRACE1(value);
-
- if (value.isInteger() && value.integerValue() > INT_MIN)
- return Encode(value.integerValue() - 1);
- else {
- double d = value.toNumber();
- return Encode(d - 1.);
- }
-}
-
-ReturnedValue Runtime::method_toDouble(const Value &value)
-{
- TRACE1(value);
- return Encode(value.toNumber());
-}
-
-int Runtime::method_toInt(const Value &value)
-{
- TRACE1(value);
- return value.toInt32();
-}
-
-int Runtime::method_doubleToInt(const double &d)
-{
- TRACE0();
- return Primitive::toInt32(d);
-}
-
-unsigned Runtime::method_toUInt(const Value &value)
-{
- TRACE1(value);
- return value.toUInt32();
-}
-
-unsigned Runtime::method_doubleToUInt(const double &d)
-{
- TRACE0();
- return Primitive::toUInt32(d);
+ Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext);
+ QV4::CallContext *c = static_cast<QV4::CallContext *>(&engine->currentStackFrame->jsFrame->context);
+ QV4::InternalClass *ic = engine->internalClasses[EngineBase::Class_StrictArgumentsObject];
+ return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->objectPrototype(), c, true)->asReturnedValue();
}
-#ifndef V4_BOOTSTRAP
-
-ReturnedValue Runtime::method_getQmlContext(NoThrowEngine *engine)
+ReturnedValue Runtime::method_loadQmlContext(NoThrowEngine *engine)
{
return engine->qmlContext()->asReturnedValue();
}
ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id)
{
- Heap::RegExpObject *ro = engine->newRegExpObject(
- static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)
- ->runtimeRegularExpressions[id].as<RegExp>());
+ Heap::RegExpObject *ro = engine->newRegExpObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id].as<RegExp>());
return ro->asReturnedValue();
}
-ReturnedValue Runtime::method_getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
-{
- Scope scope(engine);
- QV4::Scoped<QObjectWrapper> wrapper(scope, object);
- if (!wrapper) {
- engine->throwTypeError(QStringLiteral("Cannot read property of null"));
- return Encode::undefined();
- }
- return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->object(), propertyIndex, captureRequired);
-}
-
-QV4::ReturnedValue Runtime::method_getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex)
-{
- QObject *scopeObject = engine->qmlScopeObject();
- QObject *attachedObject = qmlAttachedPropertiesObjectById(attachedPropertiesId, scopeObject);
-
- QJSEngine *jsEngine = engine->jsEngine();
- QQmlData::ensurePropertyCache(jsEngine, attachedObject);
- return QV4::QObjectWrapper::getProperty(engine, attachedObject, propertyIndex, /*captureRequired*/true);
-}
-
-ReturnedValue Runtime::method_getQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)
+ReturnedValue Runtime::method_loadQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)
{
const QmlContext &c = static_cast<const QmlContext &>(context);
- return QV4::QObjectWrapper::getProperty(engine, c.d()->qml->scopeObject, propertyIndex, captureRequired);
+ return QV4::QObjectWrapper::getProperty(engine, c.d()->qml()->scopeObject, propertyIndex, captureRequired);
}
-ReturnedValue Runtime::method_getQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)
+ReturnedValue Runtime::method_loadQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)
{
const QmlContext &c = static_cast<const QmlContext &>(context);
- return QV4::QObjectWrapper::getProperty(engine, (*c.d()->qml->context)->contextObject, propertyIndex, captureRequired);
-}
-
-ReturnedValue Runtime::method_getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
-{
- Scope scope(engine);
- QV4::Scoped<QQmlTypeWrapper> wrapper(scope, object);
- if (!wrapper) {
- scope.engine->throwTypeError(QStringLiteral("Cannot read property of null"));
- return Encode::undefined();
- }
- return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->singletonObject(), propertyIndex, captureRequired);
+ return QV4::QObjectWrapper::getProperty(engine, (*c.d()->qml()->context)->contextObject, propertyIndex, captureRequired);
}
-ReturnedValue Runtime::method_getQmlIdObject(ExecutionEngine *engine, const Value &c, uint index)
+ReturnedValue Runtime::method_loadQmlIdObject(ExecutionEngine *engine, const Value &c, uint index)
{
- Scope scope(engine);
const QmlContext &qmlContext = static_cast<const QmlContext &>(c);
- QQmlContextData *context = *qmlContext.d()->qml->context;
+ QQmlContextData *context = *qmlContext.d()->qml()->context;
if (!context || index >= (uint)context->idValueCount)
return Encode::undefined();
@@ -1544,30 +1270,19 @@ ReturnedValue Runtime::method_getQmlIdObject(ExecutionEngine *engine, const Valu
return QObjectWrapper::wrap(engine, context->idValues[index].data());
}
-void Runtime::method_setQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)
+void Runtime::method_storeQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)
{
const QmlContext &c = static_cast<const QmlContext &>(context);
- return QV4::QObjectWrapper::setProperty(engine, c.d()->qml->scopeObject, propertyIndex, value);
+ return QV4::QObjectWrapper::setProperty(engine, c.d()->qml()->scopeObject, propertyIndex, value);
}
-void Runtime::method_setQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)
+void Runtime::method_storeQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)
{
const QmlContext &c = static_cast<const QmlContext &>(context);
- return QV4::QObjectWrapper::setProperty(engine, (*c.d()->qml->context)->contextObject, propertyIndex, value);
+ return QV4::QObjectWrapper::setProperty(engine, (*c.d()->qml()->context)->contextObject, propertyIndex, value);
}
-void Runtime::method_setQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value)
-{
- Scope scope(engine);
- QV4::Scoped<QObjectWrapper> wrapper(scope, object);
- if (!wrapper) {
- engine->throwTypeError(QStringLiteral("Cannot write property of null"));
- return;
- }
- wrapper->setProperty(engine, propertyIndex, value);
-}
-
-ReturnedValue Runtime::method_getQmlImportedScripts(NoThrowEngine *engine)
+ReturnedValue Runtime::method_loadQmlImportedScripts(NoThrowEngine *engine)
{
QQmlContextData *context = engine->callingQmlContext();
if (!context)
@@ -1575,44 +1290,20 @@ ReturnedValue Runtime::method_getQmlImportedScripts(NoThrowEngine *engine)
return context->importedScripts.value();
}
-QV4::ReturnedValue Runtime::method_getQmlSingleton(QV4::NoThrowEngine *engine, int nameIndex)
+QV4::ReturnedValue Runtime::method_loadQmlSingleton(QV4::NoThrowEngine *engine, int nameIndex)
{
Scope scope(engine);
- ScopedString name(scope, engine->current->compilationUnit->runtimeStrings[nameIndex]);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
return engine->qmlSingletonWrapper(name);
}
-void Runtime::method_convertThisToObject(ExecutionEngine *engine)
-{
- Value *t = &engine->current->callData->thisObject;
- if (t->isObject())
- return;
- if (t->isNullOrUndefined()) {
- *t = engine->globalObject->asReturnedValue();
- } else {
- *t = t->toObject(engine)->asReturnedValue();
- }
-}
-
-ReturnedValue Runtime::method_uPlus(const Value &value)
-{
- TRACE1(value);
-
- if (value.isNumber())
- return value.asReturnedValue();
- if (value.integerCompatible())
- return Encode(value.int_32());
-
- double n = value.toNumberImpl();
- return Encode(n);
-}
-
ReturnedValue Runtime::method_uMinus(const Value &value)
{
TRACE1(value);
// +0 != -0, so we need to convert to double when negating 0
- if (value.isInteger() && value.integerValue())
+ if (value.isInteger() && value.integerValue() &&
+ value.integerValue() != std::numeric_limits<int>::min())
return Encode(-value.integerValue());
else {
double n = RuntimeHelpers::toNumber(value);
@@ -1620,49 +1311,7 @@ ReturnedValue Runtime::method_uMinus(const Value &value)
}
}
-ReturnedValue Runtime::method_complement(const Value &value)
-{
- TRACE1(value);
-
- int n = value.toInt32();
- return Encode((int)~n);
-}
-
-ReturnedValue Runtime::method_uNot(const Value &value)
-{
- TRACE1(value);
-
- bool b = value.toBoolean();
- return Encode(!b);
-}
-
// binary operators
-ReturnedValue Runtime::method_bitOr(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- int lval = left.toInt32();
- int rval = right.toInt32();
- return Encode(lval | rval);
-}
-
-ReturnedValue Runtime::method_bitXor(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- int lval = left.toInt32();
- int rval = right.toInt32();
- return Encode(lval ^ rval);
-}
-
-ReturnedValue Runtime::method_bitAnd(const Value &left, const Value &right)
-{
- TRACE2(left, right);
-
- int lval = left.toInt32();
- int rval = right.toInt32();
- return Encode(lval & rval);
-}
#ifndef V4_BOOTSTRAP
ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -1878,11 +1527,6 @@ Bool Runtime::method_compareStrictNotEqual(const Value &left, const Value &right
return ! RuntimeHelpers::strictEqual(left, right);
}
-Bool Runtime::method_toBoolean(const Value &value)
-{
- return value.toBoolean();
-}
-
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index 0d787714cf..3a26c23990 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -83,8 +83,8 @@ private:
};
# define TRACE0() RuntimeCounters::instance->count(Q_FUNC_INFO);
-# define TRACE1(x) RuntimeCounters::instance->count(Q_FUNC_INFO, x->type());
-# define TRACE2(x, y) RuntimeCounters::instance->count(Q_FUNC_INFO, x->type(), y->type());
+# define TRACE1(x) RuntimeCounters::instance->count(Q_FUNC_INFO, x.type());
+# define TRACE2(x, y) RuntimeCounters::instance->count(Q_FUNC_INFO, x.type(), y.type());
#else
# define TRACE0()
# define TRACE1(x)
@@ -99,14 +99,14 @@ enum TypeHint {
struct Q_QML_PRIVATE_EXPORT RuntimeHelpers {
static ReturnedValue objectDefaultValue(const Object *object, int typeHint);
- static ReturnedValue toPrimitive(const Value &value, int typeHint);
+ static ReturnedValue toPrimitive(const Value &value, TypeHint typeHint);
static double stringToNumber(const QString &s);
static Heap::String *stringFromNumber(ExecutionEngine *engine, double number);
static double toNumber(const Value &value);
static void numberToString(QString *result, double num, int radix = 10);
- static Heap::String *convertToString(ExecutionEngine *engine, const Value &value);
+ static Heap::String *convertToString(ExecutionEngine *engine, Value value, TypeHint = STRING_HINT);
static Heap::Object *convertToObject(ExecutionEngine *engine, const Value &value);
static Bool equalHelper(const Value &x, const Value &y);
@@ -118,12 +118,11 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers {
// type conversion and testing
#ifndef V4_BOOTSTRAP
-inline ReturnedValue RuntimeHelpers::toPrimitive(const Value &value, int typeHint)
+inline ReturnedValue RuntimeHelpers::toPrimitive(const Value &value, TypeHint typeHint)
{
- const Object *o = value.as<Object>();
- if (!o)
+ if (!value.isObject())
return value.asReturnedValue();
- return RuntimeHelpers::objectDefaultValue(o, typeHint);
+ return RuntimeHelpers::objectDefaultValue(&reinterpret_cast<const Object &>(value), typeHint);
}
#endif
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 302facba06..ea31dfd08b 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -58,7 +58,6 @@ namespace QV4 {
typedef uint Bool;
struct NoThrowEngine;
-
namespace {
template <typename T>
struct ExceptionCheck {
@@ -93,84 +92,64 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
#define FOR_EACH_RUNTIME_METHOD(F) \
/* call */ \
- F(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \
- F(ReturnedValue, callActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \
- F(ReturnedValue, callQmlScopeObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData)) \
- F(ReturnedValue, callQmlContextObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData)) \
- F(ReturnedValue, callProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \
- F(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \
- F(ReturnedValue, callElement, (ExecutionEngine *engine, const Value &index, CallData *callData)) \
- F(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, CallData *callData)) \
+ F(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, Value *argv, int argc)) \
+ F(ReturnedValue, callName, (ExecutionEngine *engine, int nameIndex, Value *argv, int argc)) \
+ F(ReturnedValue, callProperty, (ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)) \
+ F(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc)) \
+ F(ReturnedValue, callElement, (ExecutionEngine *engine, Value *base, const Value &index, Value *argv, int argc)) \
+ F(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, Value *argv, int argc)) \
+ F(ReturnedValue, callPossiblyDirectEval, (ExecutionEngine *engine, Value *argv, int argc)) \
\
/* construct */ \
- F(ReturnedValue, constructGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \
- F(ReturnedValue, constructActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \
- F(ReturnedValue, constructProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \
- F(ReturnedValue, constructPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \
- F(ReturnedValue, constructValue, (ExecutionEngine *engine, const Value &func, CallData *callData)) \
+ F(ReturnedValue, construct, (ExecutionEngine *engine, const Value &func, Value *argv, int argc)) \
\
- /* set & get */ \
- F(void, setActivationProperty, (ExecutionEngine *engine, int nameIndex, const Value &value)) \
- F(void, setProperty, (ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)) \
- F(void, setElement, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)) \
- F(ReturnedValue, getProperty, (ExecutionEngine *engine, const Value &object, int nameIndex)) \
- F(ReturnedValue, getActivationProperty, (ExecutionEngine *engine, int nameIndex)) \
- F(ReturnedValue, getElement, (ExecutionEngine *engine, const Value &object, const Value &index)) \
+ /* load & store */ \
+ F(void, storeNameStrict, (ExecutionEngine *engine, int nameIndex, const Value &value)) \
+ F(void, storeNameSloppy, (ExecutionEngine *engine, int nameIndex, const Value &value)) \
+ F(bool, storeProperty, (ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)) \
+ F(bool, storeElement, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)) \
+ F(ReturnedValue, loadProperty, (ExecutionEngine *engine, const Value &object, int nameIndex)) \
+ F(ReturnedValue, loadName, (ExecutionEngine *engine, int nameIndex)) \
+ F(ReturnedValue, loadElement, (ExecutionEngine *engine, const Value &object, const Value &index)) \
\
/* typeof */ \
F(ReturnedValue, typeofValue, (ExecutionEngine *engine, const Value &val)) \
F(ReturnedValue, typeofName, (ExecutionEngine *engine, int nameIndex)) \
- F(ReturnedValue, typeofScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex)) \
- F(ReturnedValue, typeofContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex)) \
- F(ReturnedValue, typeofMember, (ExecutionEngine *engine, const Value &base, int nameIndex)) \
- F(ReturnedValue, typeofElement, (ExecutionEngine *engine, const Value &base, const Value &index)) \
\
/* delete */ \
- F(ReturnedValue, deleteElement, (ExecutionEngine *engine, const Value &base, const Value &index)) \
- F(ReturnedValue, deleteMember, (ExecutionEngine *engine, const Value &base, int nameIndex)) \
- F(ReturnedValue, deleteMemberString, (ExecutionEngine *engine, const Value &base, String *name)) \
- F(ReturnedValue, deleteName, (ExecutionEngine *engine, int nameIndex)) \
+ F(bool, deleteElement, (ExecutionEngine *engine, const Value &base, const Value &index)) \
+ F(bool, deleteMember, (ExecutionEngine *engine, const Value &base, int nameIndex)) \
+ F(bool, deleteMemberString, (ExecutionEngine *engine, const Value &base, String *name)) \
+ F(bool, deleteName, (ExecutionEngine *engine, int nameIndex)) \
\
/* exceptions & scopes */ \
F(void, throwException, (ExecutionEngine *engine, const Value &value)) \
- F(ReturnedValue, unwindException, (ExecutionEngine *engine)) \
- F(void, pushWithScope, (const Value &o, NoThrowEngine *engine)) \
- F(void, pushCatchScope, (NoThrowEngine *engine, int exceptionVarNameIndex)) \
- F(void, popScope, (NoThrowEngine *engine)) \
+ F(ReturnedValue, createWithContext, (ExecutionContext *parent, const Value &o)) \
+ F(ReturnedValue, createCatchContext, (ExecutionContext *parent, int exceptionVarNameIndex)) \
\
/* closures */ \
F(ReturnedValue, closure, (ExecutionEngine *engine, int functionId)) \
\
/* function header */ \
F(void, declareVar, (ExecutionEngine *engine, bool deletable, int nameIndex)) \
- F(ReturnedValue, setupArgumentsObject, (ExecutionEngine *engine)) \
- F(void, convertThisToObject, (ExecutionEngine *engine)) \
+ F(ReturnedValue, createMappedArgumentsObject, (ExecutionEngine *engine)) \
+ F(ReturnedValue, createUnmappedArgumentsObject, (ExecutionEngine *engine)) \
\
/* literals */ \
F(ReturnedValue, arrayLiteral, (ExecutionEngine *engine, Value *values, uint length)) \
F(ReturnedValue, objectLiteral, (ExecutionEngine *engine, const Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)) \
- F(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id)) \
\
/* foreach */ \
F(ReturnedValue, foreachIterator, (ExecutionEngine *engine, const Value &in)) \
F(ReturnedValue, foreachNextPropertyName, (const Value &foreach_iterator)) \
\
/* unary operators */ \
- F(ReturnedValue, uPlus, (const Value &value)) \
F(ReturnedValue, uMinus, (const Value &value)) \
- F(ReturnedValue, uNot, (const Value &value)) \
- F(ReturnedValue, complement, (const Value &value)) \
- F(ReturnedValue, increment, (const Value &value)) \
- F(ReturnedValue, decrement, (const Value &value)) \
\
/* binary operators */ \
F(ReturnedValue, instanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \
F(ReturnedValue, in, (ExecutionEngine *engine, const Value &left, const Value &right)) \
F(ReturnedValue, add, (ExecutionEngine *engine, const Value &left, const Value &right)) \
- F(ReturnedValue, addString, (ExecutionEngine *engine, const Value &left, const Value &right)) \
- F(ReturnedValue, bitOr, (const Value &left, const Value &right)) \
- F(ReturnedValue, bitXor, (const Value &left, const Value &right)) \
- F(ReturnedValue, bitAnd, (const Value &left, const Value &right)) \
F(ReturnedValue, sub, (const Value &left, const Value &right)) \
F(ReturnedValue, mul, (const Value &left, const Value &right)) \
F(ReturnedValue, div, (const Value &left, const Value &right)) \
@@ -200,28 +179,18 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
F(Bool, compareInstanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \
F(Bool, compareIn, (ExecutionEngine *engine, const Value &left, const Value &right)) \
\
- /* conversions */ \
- F(Bool, toBoolean, (const Value &value)) \
- F(ReturnedValue, toDouble, (const Value &value)) \
- F(int, toInt, (const Value &value)) \
- F(int, doubleToInt, (const double &d)) \
- F(unsigned, toUInt, (const Value &value)) \
- F(unsigned, doubleToUInt, (const double &d)) \
+ F(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id)) \
\
/* qml */ \
- F(ReturnedValue, getQmlContext, (NoThrowEngine *engine)) \
- F(ReturnedValue, getQmlImportedScripts, (NoThrowEngine *engine)) \
- F(ReturnedValue, getQmlSingleton, (NoThrowEngine *engine, int nameIndex)) \
- F(ReturnedValue, getQmlAttachedProperty, (ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex)) \
- F(ReturnedValue, getQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
- F(ReturnedValue, getQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
- F(ReturnedValue, getQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)) \
- F(ReturnedValue, getQmlSingletonQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)) \
- F(ReturnedValue, getQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index)) \
- \
- F(void, setQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \
- F(void, setQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \
- F(void, setQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value))
+ F(ReturnedValue, loadQmlContext, (NoThrowEngine *engine)) \
+ F(ReturnedValue, loadQmlImportedScripts, (NoThrowEngine *engine)) \
+ F(ReturnedValue, loadQmlSingleton, (NoThrowEngine *engine, int nameIndex)) \
+ F(ReturnedValue, loadQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
+ F(ReturnedValue, loadQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
+ F(ReturnedValue, loadQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index)) \
+ \
+ F(void, storeQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \
+ F(void, storeQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \
struct Q_QML_PRIVATE_EXPORT Runtime {
Runtime();
diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp
new file mode 100644
index 0000000000..9c115099b5
--- /dev/null
+++ b/src/qml/jsruntime/qv4runtimecodegen.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4runtimecodegen_p.h"
+#include "qv4compilerscanfunctions_p.h"
+
+using namespace QV4;
+
+void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName,
+ const QString &sourceCode,
+ AST::FunctionExpression *ast,
+ Compiler::Module *module)
+{
+ _module = module;
+ _module->fileName = fileName;
+ _context = 0;
+
+ Compiler::ScanFunctions scan(this, sourceCode, Compiler::GlobalCode);
+ // fake a global environment
+ scan.enterEnvironment(0, Compiler::FunctionCode);
+ scan(ast);
+ scan.leaveEnvironment();
+
+ int index = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
+ _module->rootContext = _module->functions.at(index);
+}
+
+void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QString &detail)
+{
+ if (hasError)
+ return;
+ hasError = true;
+ engine->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn);
+}
+
+void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const QString &detail)
+{
+ if (hasError)
+ return;
+ hasError = true;
+ engine->throwReferenceError(detail, _module->fileName, loc.startLine, loc.startColumn);
+}
+
diff --git a/src/qml/jsruntime/qv4runtimecodegen_p.h b/src/qml/jsruntime/qv4runtimecodegen_p.h
new file mode 100644
index 0000000000..be66dc57ca
--- /dev/null
+++ b/src/qml/jsruntime/qv4runtimecodegen_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4RUNTIMECODEGEN_P_H
+#define QV4RUNTIMECODEGEN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4codegen_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+class RuntimeCodegen : public Compiler::Codegen
+{
+public:
+ RuntimeCodegen(ExecutionEngine *engine, Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
+ : Codegen(jsUnitGenerator, strict)
+ , engine(engine)
+ {}
+
+ void generateFromFunctionExpression(const QString &fileName,
+ const QString &sourceCode,
+ AST::FunctionExpression *ast,
+ Compiler::Module *module);
+
+ void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail) override;
+ void throwReferenceError(const AST::SourceLocation &loc, const QString &detail) override;
+private:
+ ExecutionEngine *engine;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4CODEGEN_P_H
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 04a0c74133..afb5c21d36 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -52,7 +52,6 @@
#include "qv4engine_p.h"
#include "qv4value_p.h"
-#include "qv4persistent_p.h"
#include "qv4property_p.h"
#ifdef V4_USE_VALGRIND
@@ -71,56 +70,45 @@ struct ScopedValue;
#define CHECK_EXCEPTION() \
do { \
if (scope.hasException()) { \
- scope.result = QV4::Encode::undefined(); \
- return; \
+ return QV4::Encode::undefined(); \
} \
} while (false)
#define RETURN_UNDEFINED() \
- do { \
- scope.result = QV4::Encode::undefined(); \
- return; \
- } while (false)
+ return QV4::Encode::undefined()
#define RETURN_RESULT(r) \
- do { \
- scope.result = r; \
- return; \
- } while (false)
+ return QV4::Encode(r)
#define THROW_TYPE_ERROR() \
- do { \
- scope.result = scope.engine->throwTypeError(); \
- return; \
- } while (false)
+ return scope.engine->throwTypeError()
#define THROW_GENERIC_ERROR(str) \
- do { \
- scope.result = scope.engine->throwError(QString::fromUtf8(str)); \
- return; \
- } while (false)
+ return scope.engine->throwError(QString::fromUtf8(str))
struct Scope {
- inline Scope(ExecutionContext *ctx)
+ explicit Scope(ExecutionContext *ctx)
: engine(ctx->engine())
, mark(engine->jsStackTop)
- , result(*engine->jsAlloca(1))
{
- result = Encode::undefined();
}
explicit Scope(ExecutionEngine *e)
: engine(e)
, mark(engine->jsStackTop)
- , result(*engine->jsAlloca(1))
{
- result = Encode::undefined();
+ }
+
+ explicit Scope(const Managed *m)
+ : engine(m->engine())
+ , mark(engine->jsStackTop)
+ {
}
~Scope() {
#ifndef QT_NO_DEBUG
Q_ASSERT(engine->jsStackTop >= mark);
- Q_ASSERT(engine->currentContext < mark);
+// Q_ASSERT(engine->currentContext < mark);
memset(mark, 0, (engine->jsStackTop - mark)*sizeof(Value));
#endif
#ifdef V4_USE_VALGRIND
@@ -139,7 +127,6 @@ struct Scope {
ExecutionEngine *engine;
Value *mark;
- Value &result;
private:
Q_DISABLE_COPY(Scope)
@@ -363,27 +350,6 @@ struct Scoped
Value *ptr;
};
-struct ScopedCallData {
- ScopedCallData(const Scope &scope, int argc = 0)
- {
- int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + qMax(argc , int(QV4::Global::ReservedArgumentCount));
- ptr = reinterpret_cast<CallData *>(scope.alloc(size));
- ptr->tag = quint32(QV4::Value::ValueTypeInternal::Integer);
- ptr->argc = argc;
- }
-
- CallData *operator->() {
- return ptr;
- }
-
- operator CallData *() const {
- return ptr;
- }
-
- CallData *ptr;
-};
-
-
inline Value &Value::operator =(const ScopedValue &v)
{
_val = v.ptr->rawValue();
@@ -411,25 +377,6 @@ struct ScopedProperty
Property *property;
};
-struct ExecutionContextSaver
-{
- 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(const Scope &scope)
- : scope(scope.engine)
- {
- savedContext = scope.engine->currentContext;
- }
- ~ExecutionContextSaver()
- {
- Q_ASSERT(scope.engine->jsStackTop > scope.engine->currentContext);
- scope.engine->currentContext = savedContext;
- scope.engine->current = savedContext->d();
- }
-};
-
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 62145f36cc..c3b19ac77c 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -45,6 +45,7 @@
#include "qv4debugging_p.h"
#include "qv4profiling_p.h"
#include "qv4scopedvalue_p.h"
+#include "qv4jscall_p.h"
#include <private/qqmljsengine_p.h>
#include <private/qqmljslexer_p.h>
@@ -52,8 +53,7 @@
#include <private/qqmljsast_p.h>
#include <private/qqmlengine_p.h>
#include <private/qv4profiling_p.h>
-#include <qv4jsir_p.h>
-#include <qv4codegen_p.h>
+#include <qv4runtimecodegen_p.h>
#include <QtCore/QDebug>
#include <QtCore/QString>
@@ -61,7 +61,7 @@
using namespace QV4;
Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit)
- : line(0), column(0), scope(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false)
+ : line(1), column(0), context(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false)
, compilationUnit(compilationUnit), vmFunction(0), parseAsBinding(true)
{
if (qml)
@@ -81,16 +81,16 @@ void Script::parse()
if (parsed)
return;
- using namespace QQmlJS;
+ using namespace QV4::Compiler;
parsed = true;
- ExecutionEngine *v4 = scope->engine();
+ ExecutionEngine *v4 = context->engine();
Scope valueScope(v4);
- IR::Module module(v4->debugger() != 0);
+ Module module(v4->debugger() != 0);
- QQmlJS::Engine ee, *engine = &ee;
+ Engine ee, *engine = &ee;
Lexer lexer(engine);
lexer.setCode(sourceCode, line, parseAsBinding);
Parser parser(engine);
@@ -98,7 +98,7 @@ void Script::parse()
const bool parsed = parser.parseProgram();
const auto diagnosticMessages = parser.diagnosticMessages();
- for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
+ for (const DiagnosticMessage &m : diagnosticMessages) {
if (m.isError()) {
valueScope.engine->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn);
return;
@@ -117,25 +117,15 @@ void Script::parse()
return;
}
- QStringList inheritedLocals;
- if (inheritContext) {
- Scoped<CallContext> ctx(valueScope, scope);
- if (ctx) {
- for (Identifier * const *i = ctx->variables(), * const *ei = i + ctx->variableCount(); i < ei; ++i)
- inheritedLocals.append(*i ? (*i)->string : QString());
- }
- }
-
- RuntimeCodegen cg(v4, strictMode);
- cg.generateFromProgram(sourceFile, sourceCode, program, &module, QQmlJS::Codegen::EvalCode, inheritedLocals);
+ QV4::Compiler::JSUnitGenerator jsGenerator(&module);
+ RuntimeCodegen cg(v4, &jsGenerator, strictMode);
+ if (inheritContext)
+ cg.setUseFastLookups(false);
+ cg.generateFromProgram(sourceFile, sourceCode, program, &module, compilationMode);
if (v4->hasException)
return;
- QV4::Compiler::JSUnitGenerator jsGenerator(&module);
- QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
- if (inheritContext)
- isel->setUseFastLookups(false);
- compilationUnit = isel->compile();
+ compilationUnit = cg.generateCompilationUnit();
vmFunction = compilationUnit->linkToEngine(v4);
}
@@ -153,29 +143,26 @@ ReturnedValue Script::run()
if (!vmFunction)
return Encode::undefined();
- QV4::ExecutionEngine *engine = scope->engine();
+ QV4::ExecutionEngine *engine = context->engine();
QV4::Scope valueScope(engine);
if (qmlContext.isUndefined()) {
TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction);
- ExecutionContextSaver ctxSaver(valueScope);
- ContextStateSaver stateSaver(valueScope, scope);
- scope->d()->strictMode = vmFunction->isStrict();
- scope->d()->lookups = vmFunction->compilationUnit->runtimeLookups;
- scope->d()->constantTable = vmFunction->compilationUnit->constants;
- scope->d()->compilationUnit = vmFunction->compilationUnit;
+ ContextStateSaver stateSaver(valueScope, context);
+ context->d()->v4Function = vmFunction;
- return Q_V4_PROFILE(engine, vmFunction);
+ QV4::JSCallData jsCall(valueScope);
+ jsCall->thisObject = engine->globalObject;
+ QV4::CallData *cData = jsCall.callData();
+ cData->context = *context;
+ return vmFunction->call(cData);
} else {
Scoped<QmlContext> qml(valueScope, qmlContext.value());
- ScopedCallData callData(valueScope);
- callData->thisObject = Primitive::undefinedValue();
- if (vmFunction->canUseSimpleFunction())
- qml->simpleCall(valueScope, callData, vmFunction);
- else
- qml->call(valueScope, callData, vmFunction);
- return valueScope.result.asReturnedValue();
+ JSCallData jsCall(valueScope);
+ QV4::CallData *cData = jsCall.callData();
+ cData->context = *qml;
+ return vmFunction->call(cData);
}
}
@@ -186,24 +173,26 @@ Function *Script::function()
return vmFunction;
}
-QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors, QQmlJS::Directives *directivesCollector)
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator,
+ const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors,
+ Directives *directivesCollector)
{
- using namespace QQmlJS;
+ using namespace QV4::Compiler;
using namespace QQmlJS::AST;
- QQmlJS::Engine ee;
+ Engine ee;
if (directivesCollector)
ee.setDirectives(directivesCollector);
- QQmlJS::Lexer lexer(&ee);
+ Lexer lexer(&ee);
lexer.setCode(source, /*line*/1, /*qml mode*/false);
- QQmlJS::Parser parser(&ee);
+ Parser parser(&ee);
parser.parseProgram();
QList<QQmlError> errors;
const auto diagnosticMessages = parser.diagnosticMessages();
- for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
+ for (const DiagnosticMessage &m : diagnosticMessages) {
if (m.isWarning()) {
qWarning("%s:%d : %s", qPrintable(url.toString()), m.loc.startLine, qPrintable(m.message));
continue;
@@ -230,8 +219,9 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module
return 0;
}
- QQmlJS::Codegen cg(/*strict mode*/false);
- cg.generateFromProgram(url.toString(), source, program, module, QQmlJS::Codegen::EvalCode);
+ Codegen cg(unitGenerator, /*strict mode*/false);
+ cg.setUseFastLookups(false);
+ cg.generateFromProgram(url.toString(), source, program, module, GlobalCode);
errors = cg.qmlErrors();
if (!errors.isEmpty()) {
if (reportedErrors)
@@ -239,9 +229,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module
return 0;
}
- QScopedPointer<EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, module, unitGenerator));
- isel->setUseFastLookups(false);
- return isel->compile(/*generate unit data*/false);
+ return cg.generateCompilationUnit(/*generate unit data*/false);
}
QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext)
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 4ebe2dd609..f3a4853fa3 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -54,6 +54,7 @@
#include "qv4engine_p.h"
#include "qv4functionobject_p.h"
#include "qv4qmlcontext_p.h"
+#include "private/qv4compilercontext_p.h"
#include <QQmlError>
@@ -61,37 +62,21 @@ QT_BEGIN_NAMESPACE
class QQmlContextData;
-namespace QQmlJS {
-class Directives;
-}
-
namespace QV4 {
struct ContextStateSaver {
Value *savedContext;
- bool strictMode;
- Lookup *lookups;
- const QV4::Value *constantTable;
- CompiledData::CompilationUnitBase *compilationUnit;
- int lineNumber;
+ QV4::Function *v4Function;
ContextStateSaver(const Scope &scope, ExecutionContext *context)
: savedContext(scope.alloc(1))
- , strictMode(context->d()->strictMode)
- , lookups(context->d()->lookups)
- , constantTable(context->d()->constantTable)
- , compilationUnit(context->d()->compilationUnit)
- , lineNumber(context->d()->lineNumber)
+ , v4Function(context->d()->v4Function)
{
savedContext->setM(context->d());
}
ContextStateSaver(const Scope &scope, Heap::ExecutionContext *context)
: savedContext(scope.alloc(1))
- , strictMode(context->strictMode)
- , lookups(context->lookups)
- , constantTable(context->constantTable)
- , compilationUnit(context->compilationUnit)
- , lineNumber(context->lineNumber)
+ , v4Function(context->v4Function)
{
savedContext->setM(context);
}
@@ -99,22 +84,18 @@ struct ContextStateSaver {
~ContextStateSaver()
{
Heap::ExecutionContext *ctx = static_cast<Heap::ExecutionContext *>(savedContext->m());
- ctx->strictMode = strictMode;
- ctx->lookups = lookups;
- ctx->constantTable = constantTable;
- ctx->compilationUnit = compilationUnit;
- ctx->lineNumber = lineNumber;
+ ctx->v4Function = v4Function;
}
};
struct Q_QML_EXPORT Script {
- Script(ExecutionContext *scope, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
+ Script(ExecutionContext *scope, QV4::Compiler::CompilationMode mode, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
- , scope(scope), strictMode(false), inheritContext(false), parsed(false)
+ , context(scope), strictMode(false), inheritContext(false), parsed(false), compilationMode(mode)
, vmFunction(0), parseAsBinding(false) {}
Script(ExecutionEngine *engine, QmlContext *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
- , scope(engine->rootContext()), strictMode(false), inheritContext(true), parsed(false)
+ , context(engine->rootContext()), strictMode(false), inheritContext(true), parsed(false)
, vmFunction(0), parseAsBinding(true) {
if (qml)
qmlContext.set(engine, *qml);
@@ -125,10 +106,11 @@ struct Q_QML_EXPORT Script {
int line;
int column;
QString sourceCode;
- ExecutionContext *scope;
+ ExecutionContext *context;
bool strictMode;
bool inheritContext;
bool parsed;
+ QV4::Compiler::CompilationMode compilationMode = QV4::Compiler::EvalCode;
QV4::PersistentValue qmlContext;
QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit;
Function *vmFunction;
@@ -139,7 +121,7 @@ struct Q_QML_EXPORT Script {
Function *function();
- static QQmlRefPointer<CompiledData::CompilationUnit> precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source,
+ static QQmlRefPointer<CompiledData::CompilationUnit> precompile(QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator, const QUrl &url, const QString &source,
QList<QQmlError> *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0);
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext);
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 8afc672aa2..78cd7529d8 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -45,6 +45,7 @@
#include <private/qv4arrayobject_p.h>
#include <private/qqmlengine_p.h>
#include <private/qv4scopedvalue_p.h>
+#include <private/qv4jscall_p.h>
#include "qv4runtime_p.h"
#include "qv4objectiterator_p.h"
#include <private/qqmlvaluetypewrapper_p.h>
@@ -66,10 +67,10 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
QQmlError retn;
retn.setDescription(description);
- QV4::StackFrame frame = v4->currentStackFrame();
+ QV4::CppStackFrame *stackFrame = v4->currentStackFrame;
- retn.setLine(frame.line);
- retn.setUrl(QUrl(frame.source));
+ retn.setLine(stackFrame->lineNumber());
+ retn.setUrl(QUrl(stackFrame->source()));
QQmlEnginePrivate::warning(engine, retn);
}
@@ -416,13 +417,15 @@ public:
bool operator()(typename Container::value_type lhs, typename Container::value_type rhs)
{
QV4::Scope scope(m_v4);
- ScopedObject compare(scope, m_compareFn);
- ScopedCallData callData(scope, 2);
- callData->args[0] = convertElementToValue(m_v4, lhs);
- callData->args[1] = convertElementToValue(m_v4, rhs);
- callData->thisObject = m_v4->globalObject;
- compare->call(scope, callData);
- return scope.result.toNumber() < 0;
+ ScopedFunctionObject compare(scope, m_compareFn);
+ if (!compare)
+ return m_v4->throwTypeError();
+ JSCallData jsCallData(scope, 2);
+ jsCallData->args[0] = convertElementToValue(m_v4, lhs);
+ jsCallData->args[1] = convertElementToValue(m_v4, rhs);
+ *jsCallData->thisObject = m_v4->globalObject;
+ QV4::ScopedValue result(scope, compare->call(jsCallData));
+ return result->toNumber() < 0;
}
private:
@@ -438,7 +441,7 @@ public:
loadReference();
}
- if (callData->argc == 1 && callData->args[0].as<FunctionObject>()) {
+ if (callData->argc() == 1 && callData->args[0].as<FunctionObject>()) {
CompareFunctor cf(scope.engine, callData->args[0]);
std::sort(d()->container->begin(), d()->container->end(), cf);
} else {
@@ -450,8 +453,9 @@ public:
storeReference();
}
- static void method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData)
+ static QV4::ReturnedValue method_get_length(const BuiltinFunction *b, CallData *callData)
{
+ QV4::Scope scope(b);
QV4::Scoped<QQmlSequence<Container> > This(scope, callData->thisObject.as<QQmlSequence<Container> >());
if (!This)
THROW_TYPE_ERROR();
@@ -464,8 +468,9 @@ public:
RETURN_RESULT(Encode(qint32(This->d()->container->size())));
}
- static void method_set_length(const BuiltinFunction *, Scope &scope, CallData *callData)
+ static QV4::ReturnedValue method_set_length(const BuiltinFunction *b, CallData *callData)
{
+ QV4::Scope scope(b);
QV4::Scoped<QQmlSequence<Container> > This(scope, callData->thisObject.as<QQmlSequence<Container> >());
if (!This)
THROW_TYPE_ERROR();
@@ -647,14 +652,20 @@ void SequencePrototype::init()
}
#undef REGISTER_QML_SEQUENCE_METATYPE
-void SequencePrototype::method_sort(const BuiltinFunction *b, Scope &scope, CallData *callData)
+ReturnedValue SequencePrototype::method_valueOf(const BuiltinFunction *f, CallData *callData)
{
+ return Encode(callData->thisObject.toString(f->engine()));
+}
+
+ReturnedValue SequencePrototype::method_sort(const BuiltinFunction *b, CallData *callData)
+{
+ Scope scope(b);
QV4::ScopedObject o(scope, callData->thisObject);
if (!o || !o->isListType())
THROW_TYPE_ERROR();
- if (callData->argc >= 2)
- RETURN_RESULT(o);
+ if (callData->argc() >= 2)
+ return o.asReturnedValue();
#define CALL_SORT(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue) \
if (QQml##SequenceElementTypeName##List *s = o->as<QQml##SequenceElementTypeName##List>()) { \
@@ -665,7 +676,7 @@ void SequencePrototype::method_sort(const BuiltinFunction *b, Scope &scope, Call
#undef CALL_SORT
{}
- RETURN_RESULT(o);
+ return o.asReturnedValue();
}
#define IS_SEQUENCE(unused1, unused2, SequenceType, unused3) \
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 2b8d1ea716..169a48c2f9 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -68,12 +68,8 @@ struct SequencePrototype : public QV4::Object
V4_PROTOTYPE(arrayPrototype)
void init();
- static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
- {
- scope.result = callData->thisObject.toString(scope.engine);
- }
-
- static void method_sort(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_valueOf(const BuiltinFunction *f, CallData *callData);
+ static ReturnedValue method_sort(const BuiltinFunction *, CallData *callData);
static bool isSequenceType(int sequenceTypeId);
static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded);
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 2f34dd6139..d1b936bb4e 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -181,7 +181,8 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
makeIdentifierImpl();
}
- void makeIdentifierImpl() const;
+ // slow path
+ Q_NEVER_INLINE void makeIdentifierImpl() const;
static uint createHashValue(const QChar *ch, int length, uint *subtype)
{
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 7c65c97d73..571a638355 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -45,17 +45,11 @@
#include <private/qv4mm_p.h>
#include "qv4scopedvalue_p.h"
#include "qv4alloca_p.h"
+#include "qv4jscall_p.h"
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QStringList>
-#include <private/qqmljsengine_p.h>
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsparser_p.h>
-#include <private/qqmljsast_p.h>
-#include <qv4jsir_p.h>
-#include <qv4codegen_p.h>
-
#include <cassert>
#ifndef Q_OS_WIN
@@ -108,11 +102,8 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index)
Scoped<StringObject> o(scope, m->as<StringObject>());
Q_ASSERT(!!o);
- if (index < static_cast<uint>(o->d()->string->toQString().length())) {
- if (v4->current->strictMode)
- v4->throwTypeError();
+ if (index < static_cast<uint>(o->d()->string->toQString().length()))
return false;
- }
return true;
}
@@ -152,24 +143,25 @@ void Heap::StringCtor::init(QV4::ExecutionContext *scope)
Heap::FunctionObject::init(scope, QStringLiteral("String"));
}
-void StringCtor::construct(const Managed *m, Scope &scope, CallData *callData)
+ReturnedValue StringCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- ExecutionEngine *v4 = static_cast<const Object *>(m)->engine();
+ ExecutionEngine *v4 = static_cast<const Object *>(f)->engine();
+ Scope scope(v4);
ScopedString value(scope);
- if (callData->argc)
- value = callData->args[0].toString(v4);
+ if (argc)
+ value = argv[0].toString(v4);
else
value = v4->newString();
- scope.result = Encode(v4->newStringObject(value));
+ return Encode(v4->newStringObject(value));
}
-void StringCtor::call(const Managed *, Scope &scope, CallData *callData)
+ReturnedValue StringCtor::call(const FunctionObject *m, const Value *, const Value *argv, int argc)
{
- ExecutionEngine *v4 = scope.engine;
- if (callData->argc)
- scope.result = callData->args[0].toString(v4);
+ ExecutionEngine *v4 = m->engine();
+ if (argc)
+ return argv[0].toString(v4)->asReturnedValue();
else
- scope.result = v4->newString();
+ return v4->newString()->asReturnedValue();
}
void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -208,140 +200,155 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("trim"), method_trim);
}
-static QString getThisString(Scope &scope, CallData *callData)
+static QString getThisString(ExecutionEngine *v4, CallData *callData)
{
- ScopedValue t(scope, callData->thisObject);
+ Value *t = &callData->thisObject;
if (String *s = t->stringValue())
return s->toQString();
if (StringObject *thisString = t->as<StringObject>())
return thisString->d()->string->toQString();
if (t->isUndefined() || t->isNull()) {
- scope.engine->throwTypeError();
+ v4->throwTypeError();
return QString();
}
return t->toQString();
}
-void StringPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_toString(const BuiltinFunction *b, CallData *callData)
{
if (callData->thisObject.isString())
RETURN_RESULT(callData->thisObject);
+ ExecutionEngine *v4 = b->engine();
StringObject *o = callData->thisObject.as<StringObject>();
if (!o)
- THROW_TYPE_ERROR();
- scope.result = o->d()->string;
+ return v4->throwTypeError();
+ return o->d()->string->asReturnedValue();
}
-void StringPrototype::method_charAt(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_charAt(const BuiltinFunction *b, CallData *callData)
{
- const QString str = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString str = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
int pos = 0;
- if (callData->argc > 0)
+ if (callData->argc() > 0)
pos = (int) callData->args[0].toInteger();
QString result;
if (pos >= 0 && pos < str.length())
result += str.at(pos);
- scope.result = scope.engine->newString(result);
+ return Encode(v4->newString(result));
}
-void StringPrototype::method_charCodeAt(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_charCodeAt(const BuiltinFunction *b, CallData *callData)
{
- const QString str = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString str = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
int pos = 0;
- if (callData->argc > 0)
+ if (callData->argc() > 0)
pos = (int) callData->args[0].toInteger();
if (pos >= 0 && pos < str.length())
RETURN_RESULT(Encode(str.at(pos).unicode()));
- scope.result = Encode(qt_qnan());
+ return Encode(qt_qnan());
}
-void StringPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_concat(const BuiltinFunction *b, CallData *callData)
{
- QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ Scope scope(v4);
ScopedString s(scope);
- for (int i = 0; i < callData->argc; ++i) {
+ for (int i = 0; i < callData->argc(); ++i) {
s = callData->args[i].toString(scope.engine);
- CHECK_EXCEPTION();
+ if (v4->hasException)
+ return QV4::Encode::undefined();
Q_ASSERT(s->isString());
value += s->toQString();
}
- scope.result = scope.engine->newString(value);
+ return Encode(v4->newString(value));
}
-void StringPrototype::method_endsWith(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_endsWith(const BuiltinFunction *b, CallData *callData)
{
- QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
QString searchString;
- if (callData->argc) {
+ if (callData->argc()) {
if (callData->args[0].as<RegExpObject>())
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
searchString = callData->args[0].toQString();
}
int pos = value.length();
- if (callData->argc > 1)
+ if (callData->argc() > 1)
pos = (int) callData->args[1].toInteger();
if (pos == value.length())
RETURN_RESULT(Encode(value.endsWith(searchString)));
QStringRef stringToSearch = value.leftRef(pos);
- scope.result = Encode(stringToSearch.endsWith(searchString));
+ return Encode(stringToSearch.endsWith(searchString));
}
-void StringPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_indexOf(const BuiltinFunction *b, CallData *callData)
{
- QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
QString searchString;
- if (callData->argc)
+ if (callData->argc())
searchString = callData->args[0].toQString();
int pos = 0;
- if (callData->argc > 1)
+ if (callData->argc() > 1)
pos = (int) callData->args[1].toInteger();
int index = -1;
if (! value.isEmpty())
index = value.indexOf(searchString, qMin(qMax(pos, 0), value.length()));
- scope.result = Encode(index);
+ return Encode(index);
}
-void StringPrototype::method_includes(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_includes(const BuiltinFunction *b, CallData *callData)
{
- QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
QString searchString;
- if (callData->argc) {
+ if (callData->argc()) {
if (callData->args[0].as<RegExpObject>())
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
searchString = callData->args[0].toQString();
}
int pos = 0;
- if (callData->argc > 1) {
- ScopedValue posArg(scope, callData->argument(1));
- pos = (int) posArg->toInteger();
- if (!posArg->isInteger() && posArg->isNumber() && qIsInf(posArg->toNumber()))
+ if (callData->argc() > 1) {
+ Value &posArg = callData->args[1];
+ pos = (int) posArg.toInteger();
+ if (!posArg.isInteger() && posArg.isNumber() && qIsInf(posArg.toNumber()))
pos = value.length();
}
@@ -349,20 +356,21 @@ void StringPrototype::method_includes(const BuiltinFunction *, Scope &scope, Cal
RETURN_RESULT(Encode(value.contains(searchString)));
QStringRef stringToSearch = value.midRef(pos);
- scope.result = Encode(stringToSearch.contains(searchString));
+ return Encode(stringToSearch.contains(searchString));
}
-void StringPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_lastIndexOf(const BuiltinFunction *b, CallData *callData)
{
- const QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
QString searchString;
- if (callData->argc)
+ if (callData->argc())
searchString = callData->args[0].toQString();
- ScopedValue posArg(scope, callData->argument(1));
- double position = RuntimeHelpers::toNumber(posArg);
+ double position = callData->argc() > 1 ? RuntimeHelpers::toNumber(callData->args[1]) : +qInf();
if (std::isnan(position))
position = +qInf();
else
@@ -374,97 +382,94 @@ void StringPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope,
if (searchString.isNull() && pos == 0)
RETURN_RESULT(Encode(-1));
int index = value.lastIndexOf(searchString, pos);
- scope.result = Encode(index);
+ return Encode(index);
}
-void StringPrototype::method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_localeCompare(const BuiltinFunction *b, CallData *callData)
{
- const QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
- ScopedValue v(scope, callData->argument(0));
- const QString that = v->toQString();
- scope.result = Encode(QString::localeAwareCompare(value, that));
+ if (callData->argc() < 1)
+ callData->args[0] = Encode::undefined();
+
+ const QString that = callData->args[0].toQString();
+ return Encode(QString::localeAwareCompare(value, that));
}
-void StringPrototype::method_match(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_match(const BuiltinFunction *b, CallData *callData)
{
- if (callData->thisObject.isUndefined() || callData->thisObject.isNull())
- THROW_TYPE_ERROR();
+ ExecutionEngine *v4 = b->engine();
+ if (callData->thisObject.isNullOrUndefined())
+ return v4->throwTypeError();
- ScopedString s(scope, callData->thisObject.toString(scope.engine));
+ callData->thisObject = callData->thisObject.toString(v4);
+ if (v4->hasException)
+ return Encode::undefined();
- ScopedValue regexp(scope, callData->argument(0));
- Scoped<RegExpObject> rx(scope, regexp);
- if (!rx) {
- ScopedCallData callData(scope, 1);
- callData->args[0] = regexp;
- scope.engine->regExpCtor()->construct(scope, callData);
- rx = scope.result.asReturnedValue();
- }
+ Q_ASSERT(v4->jsStackTop == callData->args + callData->argc());
+ if (!callData->argc())
+ callData->args[0] = Encode::undefined();
+ callData->setArgc(1);
+ v4->jsStackTop = callData->args + 1;
- if (!rx)
- // ### CHECK
- THROW_TYPE_ERROR();
+ Scope scope(v4);
- bool global = rx->global();
+ if (!callData->args[0].as<RegExpObject>()) {
+ // convert args[0] to a regexp
+ callData->args[0] = RegExpCtor::callAsConstructor(b, callData->args, callData->argc());
+ if (v4->hasException)
+ return Encode::undefined();
+ }
- // ### use the standard builtin function, not the one that might be redefined in the proto
- ScopedString execString(scope, scope.engine->newString(QStringLiteral("exec")));
- ScopedFunctionObject exec(scope, scope.engine->regExpPrototype()->get(execString));
+ bool global = static_cast<RegExpObject *>(&callData->args[0])->global();
- ScopedCallData cData(scope, 1);
- cData->thisObject = rx;
- cData->args[0] = s;
- if (!global) {
- exec->call(scope, cData);
- return;
- }
+ qSwap(callData->thisObject, callData->args[0]);
+ if (!global)
+ return RegExpPrototype::method_exec(b, callData);
- ScopedString lastIndex(scope, scope.engine->newString(QStringLiteral("lastIndex")));
- rx->put(lastIndex, ScopedValue(scope, Primitive::fromInt32(0)));
+ // rx is now in thisObject
+ RegExpObject *rx = static_cast<RegExpObject *>(&callData->thisObject);
+ rx->setLastIndex(0);
ScopedArrayObject a(scope, scope.engine->newArrayObject());
- double previousLastIndex = 0;
+ int previousLastIndex = 0;
uint n = 0;
- ScopedValue matchStr(scope);
- ScopedValue index(scope);
while (1) {
- exec->call(scope, cData);
- if (scope.result.isNull())
+ Value result = Primitive::fromReturnedValue(RegExpPrototype::execFirstMatch(b, callData));
+ if (result.isNull())
break;
- assert(scope.result.isObject());
- index = rx->get(lastIndex, 0);
- double thisIndex = index->toInteger();
- if (previousLastIndex == thisIndex) {
- previousLastIndex = thisIndex + 1;
- rx->put(lastIndex, ScopedValue(scope, Primitive::fromDouble(previousLastIndex)));
+ int index = rx->lastIndex();
+ if (previousLastIndex == index) {
+ previousLastIndex = index + 1;
+ rx->setLastIndex(previousLastIndex);
} else {
- previousLastIndex = thisIndex;
+ previousLastIndex = index;
}
- matchStr = scope.result.objectValue()->getIndexed(0);
- a->arraySet(n, matchStr);
+ a->arraySet(n, result);
++n;
}
if (!n)
- scope.result = Encode::null();
+ return Encode::null();
else
- scope.result = a;
+ return a.asReturnedValue();
}
-void StringPrototype::method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_repeat(const BuiltinFunction *b, CallData *callData)
{
- QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
double repeats = callData->args[0].toInteger();
- if (repeats < 0 || qIsInf(repeats)) {
- scope.result = scope.engine->throwRangeError(QLatin1String("Invalid count value"));
- return;
- }
+ if (repeats < 0 || qIsInf(repeats))
+ return v4->throwRangeError(QLatin1String("Invalid count value"));
- scope.result = scope.engine->newString(value.repeated(int(repeats)));
+ return Encode(v4->newString(value.repeated(int(repeats))));
}
static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount)
@@ -513,7 +518,7 @@ static void appendReplacementString(QString *result, const QString &input, const
}
}
-void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_replace(const BuiltinFunction *b, CallData *callData)
{
QString string;
if (StringObject *thisString = callData->thisObject.as<StringObject>())
@@ -528,6 +533,7 @@ void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, Call
uint _matchOffsets[64];
uint *matchOffsets = _matchOffsets;
+ Scope scope(b);
ScopedValue searchValue(scope, callData->argument(0));
Scoped<RegExpObject> regExp(scope, searchValue);
if (regExp) {
@@ -571,14 +577,15 @@ void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, Call
}
QString result;
+ ScopedValue replacement(scope);
ScopedValue replaceValue(scope, callData->argument(1));
ScopedFunctionObject searchCallback(scope, replaceValue);
if (!!searchCallback) {
result.reserve(string.length() + 10*numStringMatches);
- ScopedCallData callData(scope, numCaptures + 2);
- callData->thisObject = Primitive::undefinedValue();
- int lastEnd = 0;
ScopedValue entry(scope);
+ JSCallData jsCallData(scope, numCaptures + 2);
+ *jsCallData->thisObject = Primitive::undefinedValue();
+ int lastEnd = 0;
for (int i = 0; i < numStringMatches; ++i) {
for (int k = 0; k < numCaptures; ++k) {
int idx = (i * numCaptures + k) * 2;
@@ -587,17 +594,17 @@ void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, Call
entry = Primitive::undefinedValue();
if (start != JSC::Yarr::offsetNoMatch && end != JSC::Yarr::offsetNoMatch)
entry = scope.engine->newString(string.mid(start, end - start));
- callData->args[k] = entry;
+ jsCallData->args[k] = entry;
}
uint matchStart = matchOffsets[i * numCaptures * 2];
Q_ASSERT(matchStart >= static_cast<uint>(lastEnd));
uint matchEnd = matchOffsets[i * numCaptures * 2 + 1];
- callData->args[numCaptures] = Primitive::fromUInt32(matchStart);
- callData->args[numCaptures + 1] = scope.engine->newString(string);
+ jsCallData->args[numCaptures] = Primitive::fromUInt32(matchStart);
+ jsCallData->args[numCaptures + 1] = scope.engine->newString(string);
- searchCallback->call(scope, callData);
+ replacement = searchCallback->call(jsCallData);
result += string.midRef(lastEnd, matchStart - lastEnd);
- result += scope.result.toQString();
+ result += replacement->toQString();
lastEnd = matchEnd;
}
result += string.midRef(lastEnd);
@@ -623,43 +630,49 @@ void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, Call
if (matchOffsets != _matchOffsets)
free(matchOffsets);
- scope.result = scope.engine->newString(result);
+ return Encode(scope.engine->newString(result));
}
-void StringPrototype::method_search(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_search(const BuiltinFunction *b, CallData *callData)
{
- QString string = getThisString(scope, callData);
- scope.result = callData->argument(0);
- CHECK_EXCEPTION();
+ Scope scope(b);
+ ScopedValue regExpObj(scope);
+ QString string = getThisString(scope.engine, callData);
+ regExpObj = callData->argument(0);
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
- Scoped<RegExpObject> regExp(scope, scope.result.as<RegExpObject>());
+ RegExpObject *regExp = regExpObj->as<RegExpObject>();
if (!regExp) {
- ScopedCallData callData(scope, 1);
- callData->args[0] = scope.result;
- scope.engine->regExpCtor()->construct(scope, callData);
- CHECK_EXCEPTION();
+ JSCallData jsCallData(scope, 1);
+ jsCallData->args[0] = regExpObj;
+ regExpObj = scope.engine->regExpCtor()->callAsConstructor(jsCallData);
+ if (scope.engine->hasException)
+ return QV4::Encode::undefined();
- regExp = scope.result.as<RegExpObject>();
+ regExp = regExpObj->as<RegExpObject>();
Q_ASSERT(regExp);
}
Scoped<RegExp> re(scope, regExp->value());
Q_ALLOCA_VAR(uint, matchOffsets, regExp->value()->captureCount() * 2 * sizeof(uint));
uint result = re->match(string, /*offset*/0, matchOffsets);
if (result == JSC::Yarr::offsetNoMatch)
- scope.result = Encode(-1);
+ return Encode(-1);
else
- scope.result = Encode(result);
+ return Encode(result);
}
-void StringPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_slice(const BuiltinFunction *b, CallData *callData)
{
- const QString text = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString text = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
const double length = text.length();
- double start = callData->argc ? callData->args[0].toInteger() : 0;
- double end = (callData->argc < 2 || callData->args[1].isUndefined())
+ double start = callData->argc() ? callData->args[0].toInteger() : 0;
+ double end = (callData->argc() < 2 || callData->args[1].isUndefined())
? length : callData->args[1].toInteger();
if (start < 0)
@@ -676,14 +689,17 @@ void StringPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallDa
const int intEnd = int(end);
int count = qMax(0, intEnd - intStart);
- scope.result = scope.engine->newString(text.mid(intStart, count));
+ return Encode(v4->newString(text.mid(intStart, count)));
}
-void StringPrototype::method_split(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_split(const BuiltinFunction *b, CallData *callData)
{
- QString text = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ QString text = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
+ Scope scope(v4);
ScopedValue separatorValue(scope, callData->argument(0));
ScopedValue limitValue(scope, callData->argument(1));
@@ -693,7 +709,7 @@ void StringPrototype::method_split(const BuiltinFunction *, Scope &scope, CallDa
if (limitValue->isUndefined()) {
ScopedString s(scope, scope.engine->newString(text));
array->push_back(s);
- RETURN_RESULT(array);
+ return array.asReturnedValue();
}
RETURN_RESULT(scope.engine->newString(text.left(limitValue->toInteger())));
}
@@ -701,7 +717,7 @@ void StringPrototype::method_split(const BuiltinFunction *, Scope &scope, CallDa
uint limit = limitValue->isUndefined() ? UINT_MAX : limitValue->toUInt32();
if (limit == 0)
- RETURN_RESULT(array);
+ return array.asReturnedValue();
Scoped<RegExpObject> re(scope, separatorValue);
if (re) {
@@ -742,7 +758,7 @@ void StringPrototype::method_split(const BuiltinFunction *, Scope &scope, CallDa
if (separator.isEmpty()) {
for (uint i = 0; i < qMin(limit, uint(text.length())); ++i)
array->push_back((s = scope.engine->newString(text.mid(i, 1))));
- RETURN_RESULT(array);
+ return array.asReturnedValue();
}
int start = 0;
@@ -756,43 +772,47 @@ void StringPrototype::method_split(const BuiltinFunction *, Scope &scope, CallDa
if (array->getLength() < limit && start != -1)
array->push_back((s = scope.engine->newString(text.mid(start))));
}
- RETURN_RESULT(array);
+ return array.asReturnedValue();
}
-void StringPrototype::method_startsWith(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_startsWith(const BuiltinFunction *b, CallData *callData)
{
- QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
QString searchString;
- if (callData->argc) {
+ if (callData->argc()) {
if (callData->args[0].as<RegExpObject>())
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
searchString = callData->args[0].toQString();
}
int pos = 0;
- if (callData->argc > 1)
+ if (callData->argc() > 1)
pos = (int) callData->args[1].toInteger();
if (pos == 0)
- RETURN_RESULT(Encode(value.startsWith(searchString)));
+ return Encode(value.startsWith(searchString));
QStringRef stringToSearch = value.midRef(pos);
RETURN_RESULT(Encode(stringToSearch.startsWith(searchString)));
}
-void StringPrototype::method_substr(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_substr(const BuiltinFunction *b, CallData *callData)
{
- const QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
double start = 0;
- if (callData->argc > 0)
+ if (callData->argc() > 0)
start = callData->args[0].toInteger();
double length = +qInf();
- if (callData->argc > 1)
+ if (callData->argc() > 1)
length = callData->args[1].toInteger();
double count = value.length();
@@ -803,25 +823,26 @@ void StringPrototype::method_substr(const BuiltinFunction *, Scope &scope, CallD
qint32 x = Primitive::toInt32(start);
qint32 y = Primitive::toInt32(length);
- scope.result = scope.engine->newString(value.mid(x, y));
+ return Encode(v4->newString(value.mid(x, y)));
}
-void StringPrototype::method_substring(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_substring(const BuiltinFunction *b, CallData *callData)
{
- QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
int length = value.length();
double start = 0;
double end = length;
- if (callData->argc > 0)
+ if (callData->argc() > 0)
start = callData->args[0].toInteger();
- ScopedValue endValue(scope, callData->argument(1));
- if (!endValue->isUndefined())
- end = endValue->toInteger();
+ if (callData->argc() > 1 && !callData->args[1].isUndefined())
+ end = callData->args[1].toInteger();
if (std::isnan(start) || start < 0)
start = 0;
@@ -843,50 +864,56 @@ void StringPrototype::method_substring(const BuiltinFunction *, Scope &scope, Ca
qint32 x = (int)start;
qint32 y = (int)(end - start);
- scope.result = scope.engine->newString(value.mid(x, y));
+ return Encode(v4->newString(value.mid(x, y)));
}
-void StringPrototype::method_toLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_toLowerCase(const BuiltinFunction *b, CallData *callData)
{
- QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
- scope.result = scope.engine->newString(value.toLower());
+ return Encode(v4->newString(value.toLower()));
}
-void StringPrototype::method_toLocaleLowerCase(const BuiltinFunction *b, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_toLocaleLowerCase(const BuiltinFunction *b, CallData *callData)
{
- method_toLowerCase(b, scope, callData);
+ return method_toLowerCase(b, callData);
}
-void StringPrototype::method_toUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_toUpperCase(const BuiltinFunction *b, CallData *callData)
{
- QString value = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ const QString value = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
- scope.result = scope.engine->newString(value.toUpper());
+ return Encode(v4->newString(value.toUpper()));
}
-void StringPrototype::method_toLocaleUpperCase(const BuiltinFunction *b, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_toLocaleUpperCase(const BuiltinFunction *b, CallData *callData)
{
- return method_toUpperCase(b, scope, callData);
+ return method_toUpperCase(b, callData);
}
-void StringPrototype::method_fromCharCode(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_fromCharCode(const BuiltinFunction *b, CallData *callData)
{
- QString str(callData->argc, Qt::Uninitialized);
+ QString str(callData->argc(), Qt::Uninitialized);
QChar *ch = str.data();
- for (int i = 0; i < callData->argc; ++i) {
+ for (int i = 0, ei = callData->argc(); i < ei; ++i) {
*ch = QChar(callData->args[i].toUInt16());
++ch;
}
- scope.result = scope.engine->newString(str);
+ return Encode(b->engine()->newString(str));
}
-void StringPrototype::method_trim(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue StringPrototype::method_trim(const BuiltinFunction *b, CallData *callData)
{
- QString s = getThisString(scope, callData);
- CHECK_EXCEPTION();
+ ExecutionEngine *v4 = b->engine();
+ QString s = getThisString(v4, callData);
+ if (v4->hasException)
+ return QV4::Encode::undefined();
const QChar *chars = s.constData();
int start, end;
@@ -899,5 +926,5 @@ void StringPrototype::method_trim(const BuiltinFunction *, Scope &scope, CallDat
break;
}
- scope.result = scope.engine->newString(QString(chars + start, end - start + 1));
+ return Encode(v4->newString(QString(chars + start, end - start + 1)));
}
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index ce046f4844..a76684384d 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -106,8 +106,8 @@ struct StringCtor: FunctionObject
{
V4_OBJECT2(StringCtor, FunctionObject)
- static void construct(const Managed *m, Scope &scope, CallData *callData);
- static void call(const Managed *, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
struct StringPrototype: StringObject
@@ -115,30 +115,30 @@ struct StringPrototype: StringObject
V4_PROTOTYPE(objectPrototype)
void init(ExecutionEngine *engine, Object *ctor);
- static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_charAt(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_charCodeAt(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_concat(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_endsWith(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_includes(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_match(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_replace(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_search(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_split(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_startsWith(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_substr(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_substring(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toLocaleLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toLocaleUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_fromCharCode(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_trim(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_charAt(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_charCodeAt(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_concat(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_endsWith(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_indexOf(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_includes(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_lastIndexOf(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_localeCompare(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_match(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_repeat(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_replace(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_search(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_slice(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_split(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_startsWith(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_substr(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_substring(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toLowerCase(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toLocaleLowerCase(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toUpperCase(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toLocaleUpperCase(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_fromCharCode(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_trim(const BuiltinFunction *, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index fe27d7c2d2..c1fbec70ea 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -39,6 +39,7 @@
#include "qv4typedarray_p.h"
#include "qv4arraybuffer_p.h"
#include "qv4string_p.h"
+#include "qv4jscall_p.h"
#include <cmath>
@@ -208,36 +209,32 @@ void Heap::TypedArrayCtor::init(QV4::ExecutionContext *scope, TypedArray::Type t
type = t;
}
-void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callData)
+ReturnedValue TypedArrayCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
{
- Scoped<TypedArrayCtor> that(scope, static_cast<const TypedArrayCtor *>(m));
+ Scope scope(f->engine());
+ const TypedArrayCtor *that = static_cast<const TypedArrayCtor *>(f);
- if (!callData->argc || !callData->args[0].isObject()) {
+ if (!argc || !argv[0].isObject()) {
// ECMA 6 22.2.1.1
- double l = callData->argc ? callData->args[0].toNumber() : 0;
- if (scope.engine->hasException) {
- scope.result = Encode::undefined();
- return;
- }
+ double l = argc ? argv[0].toNumber() : 0;
+ if (scope.engine->hasException)
+ return Encode::undefined();
uint len = (uint)l;
if (l != len)
scope.engine->throwRangeError(QStringLiteral("Non integer length for typed array."));
uint byteLength = len * operations[that->d()->type].bytesPerElement;
Scoped<ArrayBuffer> buffer(scope, scope.engine->newArrayBuffer(byteLength));
- if (scope.engine->hasException) {
- scope.result = Encode::undefined();
- return;
- }
+ if (scope.engine->hasException)
+ return Encode::undefined();
Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
array->d()->buffer.set(scope.engine, buffer->d());
array->d()->byteLength = byteLength;
array->d()->byteOffset = 0;
- scope.result = array.asReturnedValue();
- return;
+ return array.asReturnedValue();
}
- Scoped<TypedArray> typedArray(scope, callData->argument(0));
+ Scoped<TypedArray> typedArray(scope, argc ? argv[0] : Primitive::undefinedValue());
if (!!typedArray) {
// ECMA 6 22.2.1.2
Scoped<ArrayBuffer> buffer(scope, typedArray->d()->buffer);
@@ -247,10 +244,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
uint destByteLength = byteLength*destElementSize/srcElementSize;
Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(destByteLength));
- if (scope.engine->hasException) {
- scope.result = Encode::undefined();
- return;
- }
+ if (scope.engine->hasException)
+ return Encode::undefined();
Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
array->d()->buffer.set(scope.engine, newBuffer->d());
@@ -275,39 +270,30 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
}
}
- scope.result = array.asReturnedValue();
- return;
+ return array.asReturnedValue();
}
- Scoped<ArrayBuffer> buffer(scope, callData->argument(0));
+ Scoped<ArrayBuffer> buffer(scope, argc ? argv[0] : Primitive::undefinedValue());
if (!!buffer) {
// ECMA 6 22.2.1.4
- double dbyteOffset = callData->argc > 1 ? callData->args[1].toInteger() : 0;
+ double dbyteOffset = argc > 1 ? argv[1].toInteger() : 0;
uint byteOffset = (uint)dbyteOffset;
uint elementSize = operations[that->d()->type].bytesPerElement;
- if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->byteLength()) {
- scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset"));
- return;
- }
+ if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->byteLength())
+ return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset"));
uint byteLength;
- if (callData->argc < 3 || callData->args[2].isUndefined()) {
+ if (argc < 3 || argv[2].isUndefined()) {
byteLength = buffer->byteLength() - byteOffset;
- if (buffer->byteLength() < byteOffset || byteLength % elementSize) {
- scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
- return;
- }
+ if (buffer->byteLength() < byteOffset || byteLength % elementSize)
+ return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
} else {
- double l = qBound(0., callData->args[2].toInteger(), (double)UINT_MAX);
- if (scope.engine->hasException) {
- scope.result = Encode::undefined();
- return;
- }
+ double l = qBound(0., argv[2].toInteger(), (double)UINT_MAX);
+ if (scope.engine->hasException)
+ return Encode::undefined();
l *= elementSize;
- if (buffer->byteLength() - byteOffset < l) {
- scope.result = scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
- return;
- }
+ if (buffer->byteLength() - byteOffset < l)
+ return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
byteLength = (uint)l;
}
@@ -315,25 +301,20 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
array->d()->buffer.set(scope.engine, buffer->d());
array->d()->byteLength = byteLength;
array->d()->byteOffset = byteOffset;
- scope.result = array.asReturnedValue();
- return;
+ return array.asReturnedValue();
}
// ECMA 6 22.2.1.3
- ScopedObject o(scope, callData->argument(0));
+ ScopedObject o(scope, argc ? argv[0] : Primitive::undefinedValue());
uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length()))->toInteger(), (double)UINT_MAX);
- if (scope.engine->hasException) {
- scope.result = scope.engine->throwTypeError();
- return;
- }
+ if (scope.engine->hasException)
+ return scope.engine->throwTypeError();
uint elementSize = operations[that->d()->type].bytesPerElement;
Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(l * elementSize));
- if (scope.engine->hasException) {
- scope.result = Encode::undefined();
- return;
- }
+ if (scope.engine->hasException)
+ return Encode::undefined();
Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
array->d()->buffer.set(scope.engine, newBuffer->d());
@@ -346,21 +327,19 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
while (idx < l) {
val = o->getIndexed(idx);
array->d()->type->write(scope.engine, b, 0, val);
- if (scope.engine->hasException) {
- scope.result = Encode::undefined();
- return;
- }
+ if (scope.engine->hasException)
+ return Encode::undefined();
++idx;
b += elementSize;
}
- scope.result = array.asReturnedValue();
+ return array.asReturnedValue();
}
-void TypedArrayCtor::call(const Managed *that, Scope &scope, CallData *callData)
+ReturnedValue TypedArrayCtor::call(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
- construct(that, scope, callData);
+ return callAsConstructor(f, argv, argc);
}
void Heap::TypedArray::init(Type t)
@@ -406,15 +385,10 @@ bool TypedArray::putIndexed(Managed *m, uint index, const Value &value)
uint bytesPerElement = a->d()->type->bytesPerElement;
uint byteOffset = a->d()->byteOffset + index * bytesPerElement;
if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength())
- goto reject;
+ return false;
a->d()->type->write(scope.engine, a->d()->buffer->data->data(), byteOffset, value);
return true;
-
-reject:
- if (scope.engine->current->strictMode)
- scope.engine->throwTypeError();
- return false;
}
void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor)
@@ -435,52 +409,57 @@ void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor)
defineDefaultProperty(QStringLiteral("subarray"), method_subarray, 0);
}
-void TypedArrayPrototype::method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue TypedArrayPrototype::method_get_buffer(const BuiltinFunction *b, CallData *callData)
{
- Scoped<TypedArray> v(scope, callData->thisObject);
+ ExecutionEngine *v4 = b->engine();
+ TypedArray *v = callData->thisObject.as<TypedArray>();
if (!v)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
- scope.result = v->d()->buffer;
+ return v->d()->buffer->asReturnedValue();
}
-void TypedArrayPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue TypedArrayPrototype::method_get_byteLength(const BuiltinFunction *b, CallData *callData)
{
- Scoped<TypedArray> v(scope, callData->thisObject);
+ ExecutionEngine *v4 = b->engine();
+ TypedArray *v = callData->thisObject.as<TypedArray>();
if (!v)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
- scope.result = Encode(v->d()->byteLength);
+ return Encode(v->d()->byteLength);
}
-void TypedArrayPrototype::method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue TypedArrayPrototype::method_get_byteOffset(const BuiltinFunction *b, CallData *callData)
{
- Scoped<TypedArray> v(scope, callData->thisObject);
+ ExecutionEngine *v4 = b->engine();
+ TypedArray *v = callData->thisObject.as<TypedArray>();
if (!v)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
- scope.result = Encode(v->d()->byteOffset);
+ return Encode(v->d()->byteOffset);
}
-void TypedArrayPrototype::method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue TypedArrayPrototype::method_get_length(const BuiltinFunction *b, CallData *callData)
{
- Scoped<TypedArray> v(scope, callData->thisObject);
+ ExecutionEngine *v4 = b->engine();
+ TypedArray *v = callData->thisObject.as<TypedArray>();
if (!v)
- THROW_TYPE_ERROR();
+ return v4->throwTypeError();
- scope.result = Encode(v->d()->byteLength/v->d()->type->bytesPerElement);
+ return Encode(v->d()->byteLength/v->d()->type->bytesPerElement);
}
-void TypedArrayPrototype::method_set(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue TypedArrayPrototype::method_set(const BuiltinFunction *b, CallData *callData)
{
+ Scope scope(b);
Scoped<TypedArray> a(scope, callData->thisObject);
if (!a)
- THROW_TYPE_ERROR();
+ return scope.engine->throwTypeError();
Scoped<ArrayBuffer> buffer(scope, a->d()->buffer);
if (!buffer)
scope.engine->throwTypeError();
- double doffset = callData->argc >= 2 ? callData->args[1].toInteger() : 0;
+ double doffset = callData->argc() >= 2 ? callData->args[1].toInteger() : 0;
if (scope.engine->hasException)
RETURN_UNDEFINED();
@@ -494,12 +473,12 @@ void TypedArrayPrototype::method_set(const BuiltinFunction *, Scope &scope, Call
// src is a regular object
ScopedObject o(scope, callData->args[0].toObject(scope.engine));
if (scope.engine->hasException || !o)
- THROW_TYPE_ERROR();
+ return scope.engine->throwTypeError();
double len = ScopedValue(scope, o->get(scope.engine->id_length()))->toNumber();
uint l = (uint)len;
if (scope.engine->hasException || l != len)
- THROW_TYPE_ERROR();
+ return scope.engine->throwTypeError();
if (offset + l > a->length())
RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
@@ -521,7 +500,7 @@ void TypedArrayPrototype::method_set(const BuiltinFunction *, Scope &scope, Call
// src is a typed array
Scoped<ArrayBuffer> srcBuffer(scope, srcTypedArray->d()->buffer);
if (!srcBuffer)
- THROW_TYPE_ERROR();
+ return scope.engine->throwTypeError();
uint l = srcTypedArray->length();
if (offset + l > a->length())
@@ -559,24 +538,25 @@ void TypedArrayPrototype::method_set(const BuiltinFunction *, Scope &scope, Call
RETURN_UNDEFINED();
}
-void TypedArrayPrototype::method_subarray(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue TypedArrayPrototype::method_subarray(const BuiltinFunction *builtin, CallData *callData)
{
+ Scope scope(builtin);
Scoped<TypedArray> a(scope, callData->thisObject);
if (!a)
- THROW_TYPE_ERROR();
+ return scope.engine->throwTypeError();
Scoped<ArrayBuffer> buffer(scope, a->d()->buffer);
if (!buffer)
- THROW_TYPE_ERROR();
+ return scope.engine->throwTypeError();
int len = a->length();
- double b = callData->argc > 0 ? callData->args[0].toInteger() : 0;
+ double b = callData->argc() > 0 ? callData->args[0].toInteger() : 0;
if (b < 0)
b = len + b;
uint begin = (uint)qBound(0., b, (double)len);
- double e = callData->argc < 2 || callData->args[1].isUndefined() ? len : callData->args[1].toInteger();
+ double e = callData->argc() < 2 || callData->args[1].isUndefined() ? len : callData->args[1].toInteger();
if (e < 0)
e = len + e;
uint end = (uint)qBound(0., e, (double)len);
@@ -590,11 +570,11 @@ void TypedArrayPrototype::method_subarray(const BuiltinFunction *, Scope &scope,
ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor()));
if (!constructor)
- THROW_TYPE_ERROR();
+ return scope.engine->throwTypeError();
- ScopedCallData cData(scope, 3);
- cData->args[0] = buffer;
- cData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement);
- cData->args[2] = Encode(newLen);
- constructor->construct(scope, cData);
+ JSCallData jsCallData(scope, 3);
+ jsCallData->args[0] = buffer;
+ jsCallData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement);
+ jsCallData->args[2] = Encode(newLen);
+ return constructor->callAsConstructor(jsCallData);
}
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index a472dfa607..6fe53e68d5 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -141,8 +141,8 @@ struct TypedArrayCtor: FunctionObject
{
V4_OBJECT2(TypedArrayCtor, FunctionObject)
- static void construct(const Managed *m, Scope &scope, CallData *callData);
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
@@ -153,13 +153,13 @@ struct TypedArrayPrototype : Object
void init(ExecutionEngine *engine, TypedArrayCtor *ctor);
- static void method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_get_buffer(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_get_byteLength(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_get_byteOffset(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_get_length(const BuiltinFunction *, CallData *callData);
- static void method_set(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_subarray(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_set(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_subarray(const BuiltinFunction *, CallData *callData);
};
inline void
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index f41442df7a..e7aaa97e6b 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -75,39 +75,29 @@ int Value::toUInt16() const
return (unsigned short)number;
}
-bool Value::toBoolean() const
+bool Value::toBooleanImpl(Value val)
{
- if (isInteger() || isBoolean())
- return static_cast<bool>(int_32());
-
- if (isUndefined() || isNull())
- return false;
-
- if (isManaged()) {
+ if (val.isManagedOrUndefined()) {
+ Heap::Base *b = val.m();
+ if (!b)
+ return false;
#ifdef V4_BOOTSTRAP
Q_UNIMPLEMENTED();
#else
- if (String *s = stringValue())
- return s->toQString().length() > 0;
+ if (b->vtable()->isString)
+ return static_cast<Heap::String *>(b)->length() > 0;
#endif
return true;
}
// double
- return doubleValue() && !std::isnan(doubleValue());
+ double d = val.doubleValue();
+ return d && !std::isnan(d);
}
-double Value::toInteger() const
+double Value::toNumberImpl(Value val)
{
- if (integerCompatible())
- return int_32();
-
- return Primitive::toInteger(toNumber());
-}
-
-double Value::toNumberImpl() const
-{
- switch (type()) {
+ switch (val.type()) {
case QV4::Value::Undefined_Type:
return std::numeric_limits<double>::quiet_NaN();
case QV4::Value::Managed_Type:
@@ -115,12 +105,13 @@ double Value::toNumberImpl() const
Q_UNIMPLEMENTED();
Q_FALLTHROUGH();
#else
- if (String *s = stringValue())
+ if (String *s = val.stringValue())
return RuntimeHelpers::stringToNumber(s->toQString());
{
- Q_ASSERT(isObject());
- Scope scope(objectValue()->engine());
- ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, NUMBER_HINT));
+ Q_ASSERT(val.isObject());
+ Scope scope(val.objectValue()->engine());
+ ScopedValue protectThis(scope, val);
+ ScopedValue prim(scope, RuntimeHelpers::toPrimitive(val, NUMBER_HINT));
if (scope.engine->hasException)
return 0;
return prim->toNumber();
@@ -129,7 +120,7 @@ double Value::toNumberImpl() const
case QV4::Value::Null_Type:
case QV4::Value::Boolean_Type:
case QV4::Value::Integer_Type:
- return int_32();
+ return val.int_32();
default: // double
Q_UNREACHABLE();
}
@@ -236,83 +227,27 @@ bool Value::sameValue(Value other) const {
if (s && os)
return s->isEqualTo(os);
if (isInteger() && other.isDouble())
- return int_32() ? (double(int_32()) == other.doubleValue()) : (other._val == 0);
+ return int_32() ? (double(int_32()) == other.doubleValue())
+ : (other.doubleValue() == 0 && !std::signbit(other.doubleValue()));
if (isDouble() && other.isInteger())
- return other.int_32() ? (doubleValue() == double(other.int_32())) : (_val == 0);
+ return other.int_32() ? (doubleValue() == double(other.int_32()))
+ : (doubleValue() == 0 && !std::signbit(doubleValue()));
return false;
}
-
-int Primitive::toInt32(double number)
-{
- const double D32 = 4294967296.0;
- const double D31 = D32 / 2.0;
-
- if ((number >= -D31 && number < D31))
- return static_cast<int>(number);
-
-
- if (!std::isfinite(number))
- return 0;
-
- double d = ::floor(::fabs(number));
- if (std::signbit(number))
- d = -d;
-
- number = ::fmod(d , D32);
-
- if (number < -D31)
- number += D32;
- else if (number >= D31)
- number -= D32;
-
- return int(number);
-}
-
-unsigned int Primitive::toUInt32(double number)
-{
- const double D32 = 4294967296.0;
- if ((number >= 0 && number < D32))
- return static_cast<uint>(number);
-
- if (!std::isfinite(number))
- return +0;
-
- double d = ::floor(::fabs(number));
- if (std::signbit(number))
- d = -d;
-
- number = ::fmod(d , D32);
-
- if (number < 0)
- number += D32;
-
- return unsigned(number);
-}
-
-double Primitive::toInteger(double number)
-{
- if (std::isnan(number))
- return +0;
- else if (! number || std::isinf(number))
- return number;
- const double v = floor(fabs(number));
- return std::signbit(number) ? -v : v;
-}
-
#ifndef V4_BOOTSTRAP
-Heap::String *Value::toString(ExecutionEngine *e) const
+Heap::String *Value::toString(ExecutionEngine *e, Value val)
{
- if (String *s = stringValue())
+ if (String *s = val.stringValue())
return s->d();
- return RuntimeHelpers::convertToString(e, *this);
+ return RuntimeHelpers::convertToString(e, val);
}
-Heap::Object *Value::toObject(ExecutionEngine *e) const
+Heap::Object *Value::toObject(ExecutionEngine *e, Value val)
{
- if (Object *o = objectValue())
+ if (Object *o = val.objectValue())
return o->d();
- return RuntimeHelpers::convertToObject(e, *this);
+ return RuntimeHelpers::convertToObject(e, val);
}
uint Value::asArrayLength(bool *ok) const
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 17d0c32853..8497d47800 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -51,15 +51,12 @@
//
#include <limits.h>
+#include <cmath>
#include <QtCore/QString>
#include "qv4global_p.h"
#include <private/qv4heap_p.h>
-#if QT_POINTER_SIZE == 8
-#define QV4_USE_64_BIT_VALUE_ENCODING
-#endif
-
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -72,9 +69,7 @@ struct Q_QML_PRIVATE_EXPORT Value
{
private:
/*
- We use two different ways of encoding JS values. One for 32bit and one for 64bit systems.
-
- In both cases, we use 8 bytes for a value and a different variant of NaN boxing. A Double
+ We use 8 bytes for a value and a different variant of NaN boxing. A Double
NaN (actually -qNaN) is indicated by a number that has the top 13 bits set, and for a
signalling NaN it is the top 14 bits. The other values are usually set to 0 by the
processor, and are thus free for us to store other data. We keep pointers in there for
@@ -83,18 +78,14 @@ private:
only have 48 bits of addressable memory. (Note: we do leave the lower 49 bits available for
pointers.)
- On 32bit, we store doubles as doubles. All other values, have the high 32bits set to a value
- that will make the number a NaN. The Masks below are used for encoding the other types.
-
- On 64 bit, we xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will
+ We xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will
get encoded with bits 63-49 all set to 0. We then use bit 48 to distinguish between
managed/undefined (0), or Null/Int/Bool/Empty (1). So, storing a 49 bit pointer will leave
the top 15 bits 0, which is exactly the 'natural' representation of pointers. If bit 49 is
set, bit 48 indicates Empty (0) or integer-convertible (1). Then the 3 bit below that are
used to encode Null/Int/Bool.
- On both 32bit and 64bit, Undefined is encoded as a managed pointer with value 0. This is
- the same as a nullptr.
+ Undefined is encoded as a managed pointer with value 0. This is the same as a nullptr.
Specific bit-sequences:
0 = always 0
@@ -102,8 +93,6 @@ private:
x = stored value
a,b,c,d = specific bit values, see notes
- 64bit:
-
32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 |
66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value
------------------------------------------------------------------------+--------------
@@ -112,9 +101,9 @@ private:
a0000000 0000bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf
dddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double
00000000 00000010 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole)
- 00000000 00000011 10000000 00000000 00000000 00000000 00000000 00000000 | Null
- 00000000 00000011 01000000 00000000 00000000 00000000 00000000 0000000x | Bool
- 00000000 00000011 00100000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
+ 00000000 00000010 10000000 00000000 00000000 00000000 00000000 00000000 | Null
+ 00000000 00000011 00000000 00000000 00000000 00000000 00000000 0000000x | Bool
+ 00000000 00000011 10000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
Notes:
- a: xor-ed signbit, always 1 for NaN
@@ -128,31 +117,8 @@ private:
- Null, Bool, and Int have bit 48 set, indicating integer-convertible
- xoring _val with NaNEncodeMask will convert to a double in "natural" representation, where
any non double results in a NaN
-
- 32bit:
-
- 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 |
- 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value
- ------------------------------------------------------------------------+--------------
- 01111111 11111100 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined
- 01111111 11111100 00000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer)
- a1111111 1111bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf
- xddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double
- 01111111 11111110 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole)
- 01111111 11111111 10000000 00000000 00000000 00000000 00000000 00000000 | Null
- 01111111 11111111 01000000 00000000 00000000 00000000 00000000 0000000x | Bool
- 01111111 11111111 00100000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
-
- Notes:
- - the upper 32 bits are the tag, the lower 32 bits the value
- - Undefined has a nullptr in the value, Managed has a non-nullptr stored in the value
- - a: sign bit, always 0 for NaN
- - b,c: 00=inf, 01 = sNaN, 10 = qNaN, 11 = boxed value
- - d: stored double value, as long as not *all* of them are 1, because that's a boxed value
- (see above)
- - empty, Null, Bool, and Int have bit 63 set to 0, bits 62-50 set to 1 (same as undefined
- and managed), and bit 49 set to 1 (where undefined and managed have it set to 0)
- - Null, Bool, and Int have bit 48 set, indicating integer-convertible
+ - on 32bit we can use the fact that addresses are 32bits wide, so the tag part (bits 32 to
+ 63) are zero. No need to shift.
*/
quint64 _val;
@@ -172,8 +138,9 @@ public:
QML_NEARLY_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
QML_NEARLY_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); }
QML_NEARLY_ALWAYS_INLINE quint32 tag() const { return _val >> 32; }
+ QML_NEARLY_ALWAYS_INLINE void setTag(quint32 tag) { setTagValue(tag, value()); }
-#if defined(QV4_USE_64_BIT_VALUE_ENCODING)
+#if QT_POINTER_SIZE == 8
QML_NEARLY_ALWAYS_INLINE Heap::Base *m() const
{
Heap::Base *b;
@@ -184,7 +151,7 @@ public:
{
memcpy(&_val, &b, 8);
}
-#else // !QV4_USE_64_BIT_VALUE_ENCODING
+#elif QT_POINTER_SIZE == 4
QML_NEARLY_ALWAYS_INLINE Heap::Base *m() const
{
Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32));
@@ -199,6 +166,8 @@ public:
memcpy(&v, &b, 4);
setTagValue(Managed_Type_Internal, v);
}
+#else
+# error "unsupported pointer size"
#endif
QML_NEARLY_ALWAYS_INLINE int int_32() const
@@ -232,24 +201,37 @@ public:
return quint32(value());
}
+ // ### Fix for 32 bit (easiest solution is to set highest bit to 1 for mananged/undefined/integercompatible
+ // and use negative numbers here
+ enum QuickType {
+ QT_ManagedOrUndefined = 0,
+ QT_ManagedOrUndefined1 = 1,
+ QT_ManagedOrUndefined2 = 2,
+ QT_ManagedOrUndefined3 = 3,
+ QT_Empty = 4,
+ QT_Null = 5,
+ QT_Bool = 6,
+ QT_Int = 7
+ // all other values are doubles
+ };
+
enum Type {
- Undefined_Type,
- Managed_Type,
- Empty_Type,
- Integer_Type,
- Boolean_Type,
- Null_Type,
- Double_Type
+ Undefined_Type = 0,
+ Managed_Type = 1,
+ Empty_Type = 4,
+ Null_Type = 5,
+ Boolean_Type = 6,
+ Integer_Type = 7,
+ Double_Type = 8
};
inline Type type() const {
- if (isUndefined()) return Undefined_Type;
- if (isManaged()) return Managed_Type;
- if (isEmpty()) return Empty_Type;
- if (isInteger()) return Integer_Type;
- if (isBoolean()) return Boolean_Type;
- if (isNull()) return Null_Type;
- Q_ASSERT(isDouble()); return Double_Type;
+ int t = quickType();
+ if (t < QT_Empty)
+ return _val ? Managed_Type : Undefined_Type;
+ if (t > QT_Int)
+ return Double_Type;
+ return static_cast<Type>(t);
}
// Shared between 32-bit and 64-bit encoding
@@ -262,19 +244,18 @@ public:
enum {
IsDouble_Shift = 64-14,
IsManagedOrUndefined_Shift = 64-15,
- IsIntegerConvertible_Shift = 64-16,
- IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
- Managed_Type_Internal_64 = 0
+ IsIntegerConvertible_Shift = 64-15,
+ IsIntegerOrBool_Shift = 64-16,
+ QuickType_Shift = 64 - 17
};
static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
enum class ValueTypeInternal_64 {
- Empty = Immediate_Mask_64| 0,
- ConvertibleToInt = Immediate_Mask_64| 0x10000u, // bit 48
- Null = ConvertibleToInt | 0x08000u,
- Boolean = ConvertibleToInt | 0x04000u,
- Integer = ConvertibleToInt | 0x02000u
+ Empty = Immediate_Mask_64 | 0,
+ Null = Immediate_Mask_64 | 0x08000u,
+ Boolean = Immediate_Mask_64 | 0x10000u,
+ Integer = Immediate_Mask_64 | 0x18000u
};
// Used only by 32-bit encoding
@@ -285,50 +266,45 @@ public:
static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
enum class ValueTypeInternal_32 {
- Empty = Immediate_Mask_32| 0,
- ConvertibleToInt = Immediate_Mask_32| 0x10000u, // bit 48
- Null = ConvertibleToInt | 0x08000u,
- Boolean = ConvertibleToInt | 0x04000u,
- Integer = ConvertibleToInt | 0x02000u
+ Empty = Immediate_Mask_32 | 0,
+ Null = Immediate_Mask_32 | 0x08000u,
+ Boolean = Immediate_Mask_32 | 0x10000u,
+ Integer = Immediate_Mask_32 | 0x18000u
};
enum {
- Managed_Type_Internal_32 = NotDouble_Mask
+ Managed_Type_Internal = 0
};
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- enum {
- Managed_Type_Internal = Managed_Type_Internal_64
- };
- static const quint64 Immediate_Mask = Immediate_Mask_64;
using ValueTypeInternal = ValueTypeInternal_64;
-#else
- enum {
- Managed_Type_Internal = Managed_Type_Internal_32
- };
- static const quint64 Immediate_Mask = Immediate_Mask_32;
- using ValueTypeInternal = ValueTypeInternal_32;
-#endif
+
enum {
NaN_Mask = 0x7ff80000,
};
+ inline quint64 quickType() const { return (_val >> QuickType_Shift); }
+
// used internally in property
inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); }
inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); }
inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); }
inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); }
inline bool isNullOrUndefined() const { return isNull() || isUndefined(); }
- inline bool isNumber() const { return isDouble() || isInteger(); }
+ inline bool isNumber() const { return quickType() >= QT_Int; }
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
+#if /*QT_POINTER_SIZE ==*/ 8 // TODO: check if we need specialized versions for 32bit
inline bool isUndefined() const { return _val == 0; }
inline bool isDouble() const { return (_val >> IsDouble_Shift); }
- inline bool isManaged() const { return !isUndefined() && ((_val >> IsManagedOrUndefined_Shift) == 0); }
+ inline bool isManaged() const { return _val && ((_val >> IsManagedOrUndefined_Shift) == 0); }
inline bool isManagedOrUndefined() const { return ((_val >> IsManagedOrUndefined_Shift) == 0); }
+ inline bool isIntOrBool() const {
+ return (_val >> IsIntegerOrBool_Shift) == 3;
+ }
+
inline bool integerCompatible() const {
- return (_val >> IsIntegerConvertible_Shift) == 3;
+ Q_ASSERT(!isEmpty());
+ return (_val >> IsIntegerConvertible_Shift) == 1;
}
static inline bool integerCompatible(Value a, Value b) {
return a.integerCompatible() && b.integerCompatible();
@@ -342,9 +318,16 @@ public:
inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; }
inline bool isManaged() const { return tag() == Managed_Type_Internal && !isUndefined(); }
inline bool isManagedOrUndefined() const { return tag() == Managed_Type_Internal; }
- inline bool integerCompatible() const { return (tag() & quint32(ValueTypeInternal::ConvertibleToInt)) == quint32(ValueTypeInternal::ConvertibleToInt); }
+ inline bool integerCompatible() const {
+ Q_ASSERT(!isEmpty());
+ return (tag() >> (IsIntegerConvertible_Shift - 32)) == 1;
+ }
+ inline bool isIntOrBool() const {
+ return (tag() >> (IsIntegerOrBool_Shift - 32)) == 3;
+ }
+
static inline bool integerCompatible(Value a, Value b) {
- return ((a.tag() & b.tag()) & quint32(ValueTypeInternal::ConvertibleToInt)) == quint32(ValueTypeInternal::ConvertibleToInt);
+ return a.integerCompatible() && b.integerCompatible();
}
static inline bool bothDouble(Value a, Value b) {
return ((a.tag() | b.tag()) & NotDouble_Mask) != NotDouble_Mask;
@@ -354,22 +337,27 @@ public:
QML_NEARLY_ALWAYS_INLINE double doubleValue() const {
Q_ASSERT(isDouble());
double d;
- quint64 v = _val;
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- v ^= NaNEncodeMask;
+ Value v = *this;
+#if QT_POINTER_SIZE == 8
+ v._val ^= NaNEncodeMask;
+#else
+ v.setTag(v.tag() ^ (NaNEncodeMask >> 32));
#endif
- memcpy(&d, &v, 8);
+ memcpy(&d, &v._val, 8);
return d;
}
QML_NEARLY_ALWAYS_INLINE void setDouble(double d) {
memcpy(&_val, &d, 8);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
+#if QT_POINTER_SIZE == 8
_val ^= NaNEncodeMask;
+#else
+ setTag(tag() ^ (NaNEncodeMask >> 32));
#endif
Q_ASSERT(isDouble());
}
inline bool isString() const;
inline bool isObject() const;
+ inline bool isFunctionObject() const;
inline bool isInt32() {
if (tag() == quint32(ValueTypeInternal::Integer))
return true;
@@ -426,14 +414,27 @@ public:
inline int toInt32() const;
inline unsigned int toUInt32() const;
- bool toBoolean() const;
+ bool toBoolean() const {
+ if (integerCompatible())
+ return static_cast<bool>(int_32());
+
+ return toBooleanImpl(*this);
+ }
+ static bool toBooleanImpl(Value val);
double toInteger() const;
inline double toNumber() const;
- double toNumberImpl() const;
+ static double toNumberImpl(Value v);
+ double toNumberImpl() const { return toNumberImpl(*this); }
QString toQStringNoThrow() const;
QString toQString() const;
- Heap::String *toString(ExecutionEngine *e) const;
- Heap::Object *toObject(ExecutionEngine *e) const;
+ Heap::String *toString(ExecutionEngine *e) const {
+ return toString(e, *this);
+ }
+ static Heap::String *toString(ExecutionEngine *e, Value val);
+ Heap::Object *toObject(ExecutionEngine *e) const {
+ return toObject(e, *this);
+ }
+ static Heap::Object *toObject(ExecutionEngine *e, Value val);
inline bool isPrimitive() const;
inline bool tryIntegerConversion() {
@@ -520,6 +521,12 @@ inline bool Value::isObject() const
return b && b->vtable()->isObject;
}
+inline bool Value::isFunctionObject() const
+{
+ Heap::Base *b = heapObject();
+ return b && b->vtable()->isFunctionObject;
+}
+
inline bool Value::isPrimitive() const
{
return !isObject();
@@ -538,7 +545,7 @@ inline double Value::toNumber() const
#ifndef V4_BOOTSTRAP
inline uint Value::asArrayIndex() const
{
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
+#if QT_POINTER_SIZE == 8
if (!isNumber())
return UINT_MAX;
if (isInteger())
@@ -558,8 +565,8 @@ inline uint Value::asArrayIndex() const
inline bool Value::asArrayIndex(uint &idx) const
{
- if (!isDouble()) {
- if (isInteger() && int_32() >= 0) {
+ if (Q_LIKELY(!isDouble())) {
+ if (Q_LIKELY(isInteger() && int_32() >= 0)) {
idx = (uint)int_32();
return true;
}
@@ -593,9 +600,9 @@ struct Q_QML_PRIVATE_EXPORT Primitive : public Value
using Value::toInt32;
using Value::toUInt32;
- static double toInteger(double fromNumber);
- static int toInt32(double value);
- static unsigned int toUInt32(double value);
+ static double toInteger(double d);
+ static int toInt32(double d);
+ static unsigned int toUInt32(double d);
};
inline Primitive Primitive::undefinedValue()
@@ -658,6 +665,72 @@ inline Primitive Primitive::fromUInt32(uint i)
return v;
}
+struct Double {
+ quint64 d;
+
+ Double(double dbl) {
+ memcpy(&d, &dbl, sizeof(double));
+ }
+
+ int sign() const {
+ return (d >> 63) ? -1 : 1;
+ }
+
+ bool isDenormal() const {
+ return static_cast<int>((d << 1) >> 53) == 0;
+ }
+
+ int exponent() const {
+ return static_cast<int>((d << 1) >> 53) - 1023;
+ }
+
+ quint64 significant() const {
+ quint64 m = (d << 12) >> 12;
+ if (!isDenormal())
+ m |= (static_cast<quint64>(1) << 52);
+ return m;
+ }
+
+ static int toInt32(double d) {
+ int i = static_cast<int>(d);
+ if (i == d)
+ return i;
+ return Double(d).toInt32();
+ }
+
+ int toInt32() {
+ int e = exponent() - 52;
+ if (e < 0) {
+ if (e <= -53)
+ return 0;
+ return sign() * static_cast<int>(significant() >> -e);
+ } else {
+ if (e > 31)
+ return 0;
+ return sign() * (static_cast<int>(significant()) << e);
+ }
+ }
+};
+
+inline double Primitive::toInteger(double d)
+{
+ if (std::isnan(d))
+ return +0;
+ else if (!d || std::isinf(d))
+ return d;
+ return d >= 0 ? std::floor(d) : std::ceil(d);
+}
+
+inline int Primitive::toInt32(double value)
+{
+ return Double::toInt32(value);
+}
+
+inline unsigned int Primitive::toUInt32(double d)
+{
+ return static_cast<uint>(toInt32(d));
+}
+
struct Encode {
static ReturnedValue undefined() {
return Primitive::undefinedValue().rawValue();
@@ -666,33 +739,48 @@ struct Encode {
return Primitive::nullValue().rawValue();
}
- Encode(bool b) {
+ explicit Encode(bool b) {
val = Primitive::fromBoolean(b).rawValue();
}
- Encode(double d) {
+ explicit Encode(double d) {
val = Primitive::fromDouble(d).rawValue();
}
- Encode(int i) {
+ explicit Encode(int i) {
val = Primitive::fromInt32(i).rawValue();
}
- Encode(uint i) {
+ explicit Encode(uint i) {
val = Primitive::fromUInt32(i).rawValue();
}
- Encode(ReturnedValue v) {
+ explicit Encode(ReturnedValue v) {
val = v;
}
+ Encode(Value v) {
+ val = v.rawValue();
+ }
- Encode(Heap::Base *o) {
+ explicit Encode(Heap::Base *o) {
Q_ASSERT(o);
val = Value::fromHeapObject(o).asReturnedValue();
}
+ explicit Encode(Value *o) {
+ Q_ASSERT(o);
+ val = o->asReturnedValue();
+ }
+
+ static ReturnedValue smallestNumber(double d) {
+ if (static_cast<int>(d) == d && !(d == 0. && std::signbit(d)))
+ return Encode(static_cast<int>(d));
+ else
+ return Encode(d);
+ }
+
operator ReturnedValue() const {
return val;
}
quint64 val;
private:
- Encode(void *);
+ explicit Encode(void *);
};
template<typename T>
@@ -700,24 +788,29 @@ ReturnedValue value_convert(ExecutionEngine *e, const Value &v);
inline int Value::toInt32() const
{
- if (isInteger())
+ if (Q_LIKELY(integerCompatible()))
return int_32();
- double d = isNumber() ? doubleValue() : toNumberImpl();
-
- const double D32 = 4294967296.0;
- const double D31 = D32 / 2.0;
- if ((d >= -D31 && d < D31))
- return static_cast<int>(d);
+ if (Q_LIKELY(isDouble()))
+ return Double::toInt32(doubleValue());
- return Primitive::toInt32(d);
+ return Double::toInt32(toNumberImpl());
}
inline unsigned int Value::toUInt32() const
{
- return (unsigned int)toInt32();
+ return static_cast<unsigned int>(toInt32());
}
+inline double Value::toInteger() const
+{
+ if (integerCompatible())
+ return int_32();
+
+ return Primitive::toInteger(isDouble() ? doubleValue() : toNumberImpl());
+}
+
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index f2ff5d307e..00be90b3c2 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -113,17 +113,17 @@ void VariantPrototype::init()
defineDefaultProperty(engine()->id_toString(), method_toString, 0);
}
-void VariantPrototype::method_preserve(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue VariantPrototype::method_preserve(const BuiltinFunction *, CallData *callData)
{
- Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
+ VariantObject *o = callData->thisObject.as<QV4::VariantObject>();
if (o && o->d()->isScarce())
o->d()->addVmePropertyReference();
RETURN_UNDEFINED();
}
-void VariantPrototype::method_destroy(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue VariantPrototype::method_destroy(const BuiltinFunction *, CallData *callData)
{
- Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
+ VariantObject *o = callData->thisObject.as<QV4::VariantObject>();
if (o) {
if (o->d()->isScarce())
o->d()->addVmePropertyReference();
@@ -132,9 +132,10 @@ void VariantPrototype::method_destroy(const BuiltinFunction *, Scope &scope, Cal
RETURN_UNDEFINED();
}
-void VariantPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue VariantPrototype::method_toString(const BuiltinFunction *b, CallData *callData)
{
- Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
+ ExecutionEngine *v4 = b->engine();
+ VariantObject *o = callData->thisObject.as<QV4::VariantObject>();
if (!o)
RETURN_UNDEFINED();
QString result = o->d()->data().toString();
@@ -143,38 +144,33 @@ void VariantPrototype::method_toString(const BuiltinFunction *, Scope &scope, Ca
+ QLatin1String(o->d()->data().typeName())
+ QLatin1Char(')');
}
- scope.result = scope.engine->newString(result);
+ return Encode(v4->newString(result));
}
-void VariantPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
+ReturnedValue VariantPrototype::method_valueOf(const BuiltinFunction *b, CallData *callData)
{
- Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
+ VariantObject *o = callData->thisObject.as<QV4::VariantObject>();
if (o) {
QVariant v = o->d()->data();
switch (v.type()) {
case QVariant::Invalid:
- scope.result = Encode::undefined();
- return;
+ return Encode::undefined();
case QVariant::String:
- scope.result = scope.engine->newString(v.toString());
- return;
+ return Encode(b->engine()->newString(v.toString()));
case QVariant::Int:
- scope.result = Encode(v.toInt());
- return;
+ return Encode(v.toInt());
case QVariant::Double:
case QVariant::UInt:
- scope.result = Encode(v.toDouble());
- return;
+ return Encode(v.toDouble());
case QVariant::Bool:
- scope.result = Encode(v.toBool());
- return;
+ return Encode(v.toBool());
default:
if (QMetaType::typeFlags(v.userType()) & QMetaType::IsEnumeration)
RETURN_RESULT(Encode(v.toInt()));
break;
}
}
- scope.result = callData->thisObject;
+ return callData->thisObject.asReturnedValue();
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index a7c6fa320c..07b3310e91 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -108,10 +108,10 @@ public:
V4_PROTOTYPE(objectPrototype)
void init();
- static void method_preserve(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_destroy(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static ReturnedValue method_preserve(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_destroy(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_toString(const BuiltinFunction *, CallData *callData);
+ static ReturnedValue method_valueOf(const BuiltinFunction *, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 5749d0aef3..282f71fb2e 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -53,19 +53,14 @@
#include <private/qv4regexp_p.h>
#include <private/qv4regexpobject_p.h>
#include <private/qv4string_p.h>
+#include <private/qv4profiling_p.h>
+#include <private/qv4jscall_p.h>
+#include <private/qqmljavascriptexpression_p.h>
#include <iostream>
#include "qv4alloca_p.h"
-#undef DO_TRACE_INSTR // define to enable instruction tracing
-
-#ifdef DO_TRACE_INSTR
-# define TRACE_INSTR(I) qDebug("executing a %s\n", #I);
-# define TRACE(n, str, ...) { char buf[4096]; snprintf(buf, 4096, str, __VA_ARGS__); qDebug(" %s : %s", #n, buf); }
-#else
-# define TRACE_INSTR(I)
-# define TRACE(n, str, ...)
-#endif // DO_TRACE_INSTR
+#undef COUNT_INSTRUCTIONS
extern "C" {
@@ -146,7 +141,7 @@ Q_QML_EXPORT int qt_v4DebuggerHook(const char *json);
#ifndef QT_NO_QML_DEBUGGER
static int qt_v4BreakpointCount = 0;
-static bool qt_v4IsDebugging = true;
+static bool qt_v4IsDebugging = false;
static bool qt_v4IsStepping = false;
class Breakpoint
@@ -169,14 +164,6 @@ public:
static QVector<Breakpoint> qt_v4Breakpoints;
static Breakpoint qt_v4LastStop;
-static QV4::Function *qt_v4ExtractFunction(QV4::ExecutionContext *context)
-{
- if (QV4::Function *function = context->getFunction())
- return function;
- else
- return context->engine()->globalCode;
-}
-
static void qt_v4TriggerBreakpoint(const Breakpoint &bp, QV4::Function *function)
{
qt_v4LastStop = bp;
@@ -223,6 +210,7 @@ int qt_v4DebuggerHook(const char *json)
bp.fullName = ob.value(QLatin1String("fullName")).toString();
bp.condition = ob.value(QLatin1String("condition")).toString();
qt_v4Breakpoints.append(bp);
+ qt_v4IsDebugging = true;
return bp.bpNumber;
}
@@ -231,6 +219,7 @@ int qt_v4DebuggerHook(const char *json)
QString fullName = ob.value(QLatin1String("fullName")).toString();
if (qt_v4Breakpoints.last().matches(fullName, lineNumber)) {
qt_v4Breakpoints.removeLast();
+ qt_v4IsDebugging = !qt_v4Breakpoints.isEmpty();
return Success;
}
for (int i = 0; i + 1 < qt_v4Breakpoints.size(); ++i) {
@@ -251,13 +240,13 @@ int qt_v4DebuggerHook(const char *json)
return -NoSuchCommand; // Failure.
}
-static void qt_v4CheckForBreak(QV4::ExecutionContext *context)
+Q_NEVER_INLINE static void qt_v4CheckForBreak(QV4::CppStackFrame *frame)
{
if (!qt_v4IsStepping && !qt_v4Breakpoints.size())
return;
- const int lineNumber = context->d()->lineNumber;
- QV4::Function *function = qt_v4ExtractFunction(context);
+ const int lineNumber = frame->lineNumber();
+ QV4::Function *function = frame->v4Function;
QString engineName = function->sourceFile();
if (engineName.isEmpty())
@@ -287,74 +276,64 @@ static void qt_v4CheckForBreak(QV4::ExecutionContext *context)
}
}
+Q_NEVER_INLINE static void debug_slowPath(QV4::ExecutionEngine *engine)
+{
+ QV4::Debugging::Debugger *debugger = engine->debugger();
+ if (debugger && debugger->pauseAtNextOpportunity())
+ debugger->maybeBreakAtInstruction();
+ if (qt_v4IsDebugging)
+ qt_v4CheckForBreak(engine->currentStackFrame);
+}
+
#endif // QT_NO_QML_DEBUGGER
// End of debugger interface
using namespace QV4;
using namespace QV4::Moth;
-#define MOTH_BEGIN_INSTR_COMMON(I) { \
- const InstrMeta<(int)Instr::I>::DataType &instr = InstrMeta<(int)Instr::I>::data(*genericInstr); \
- code += InstrMeta<(int)Instr::I>::Size; \
- Q_UNUSED(instr); \
- TRACE_INSTR(I)
-
-#ifdef MOTH_THREADED_INTERPRETER
-
-# define MOTH_BEGIN_INSTR(I) op_##I: \
- MOTH_BEGIN_INSTR_COMMON(I)
-
-# define MOTH_END_INSTR(I) } \
- genericInstr = reinterpret_cast<const Instr *>(code); \
- goto *jumpTable[genericInstr->common.instructionType]; \
-
-#else
-
-# define MOTH_BEGIN_INSTR(I) \
- case Instr::I: \
- MOTH_BEGIN_INSTR_COMMON(I)
-
-# define MOTH_END_INSTR(I) } \
- continue;
-
-#endif
-
-#ifdef DO_TRACE_INSTR
-Param traceParam(const Param &param)
-{
- if (param.isConstant()) {
- qDebug(" constant\n");
- } else if (param.isArgument()) {
- qDebug(" argument %d@%d\n", param.index, param.scope);
- } else if (param.isLocal()) {
- qDebug(" local %d\n", param.index);
- } else if (param.isTemp()) {
- qDebug(" temp %d\n", param.index);
- } else if (param.isScopedLocal()) {
- qDebug(" temp %d@%d\n", param.index, param.scope);
- } else {
- Q_ASSERT(!"INVALID");
+#ifdef COUNT_INSTRUCTIONS
+static struct InstrCount {
+ InstrCount() {
+ fprintf(stderr, "Counting instructions...\n");
+ for (int i = 0; i < MOTH_NUM_INSTRUCTIONS(); ++i)
+ hits[i] = 0;
+ }
+ ~InstrCount() {
+ fprintf(stderr, "Instruction count:\n");
+#define BLAH(I) \
+ fprintf(stderr, "%llu : %s\n", hits[int(Instr::Type::I)], #I);
+ FOR_EACH_MOTH_INSTR(BLAH)
+ #undef BLAH
+ }
+ quint64 hits[MOTH_NUM_INSTRUCTIONS()];
+ void hit(Instr::Type i) { hits[int(i)]++; }
+} instrCount;
+#endif // COUNT_INSTRUCTIONS
+
+#define MOTH_BEGIN_INSTR_COMMON(instr) \
+ { \
+ INSTR_##instr(MOTH_DECODE)
+
+#ifdef COUNT_INSTRUCTIONS
+# define MOTH_BEGIN_INSTR(instr) \
+ MOTH_BEGIN_INSTR_COMMON(instr) \
+ instrCount.hit(Instr::Type::instr);
+#else // !COUNT_INSTRUCTIONS
+# define MOTH_BEGIN_INSTR(instr) \
+ MOTH_BEGIN_INSTR_COMMON(instr)
+#endif // COUNT_INSTRUCTIONS
+
+#ifdef MOTH_COMPUTED_GOTO
+#define MOTH_END_INSTR(instr) \
+ MOTH_DISPATCH() \
+ }
+#else // !MOTH_COMPUTED_GOTO
+#define MOTH_END_INSTR(instr) \
+ continue; \
}
- return param;
-}
-# define VALUE(param) (*VALUEPTR(param))
-# define VALUEPTR(param) (scopes[traceParam(param).scope].values + param.index)
-#else
-# define VALUE(param) (*VALUEPTR(param))
-# define VALUEPTR(param) (scopes[param.scope].values + param.index)
#endif
-// ### add write barrier here
-#define STOREVALUE(param, value) { \
- QV4::ReturnedValue tmp = (value); \
- if (engine->hasException) \
- goto catchException; \
- if (Q_LIKELY(!engine->writeBarrierActive || !scopes[param.scope].base)) { \
- VALUE(param) = tmp; \
- } else { \
- QV4::WriteBarrier::write(engine, scopes[param.scope].base, VALUEPTR(param), QV4::Value::fromReturnedValue(tmp)); \
- } \
-}
+#define STACK_VALUE(temp) stack[temp]
// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro
#ifdef CHECK_EXCEPTION
@@ -364,617 +343,971 @@ Param traceParam(const Param &param)
if (engine->hasException) \
goto catchException
-QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
+static inline Heap::CallContext *getScope(Value *stack, int level)
{
-#ifdef DO_TRACE_INSTR
- qDebug("Starting VME with context=%p and code=%p", context, code);
-#endif // DO_TRACE_INSTR
-
- qt_v4ResolvePendingBreakpointsHook();
-
-#ifdef MOTH_THREADED_INTERPRETER
-#define MOTH_INSTR_ADDR(I, FMT) &&op_##I,
- static void *jumpTable[] = {
- FOR_EACH_MOTH_INSTR(MOTH_INSTR_ADDR)
- };
-#undef MOTH_INSTR_ADDR
-#endif
-
- QV4::Value *stack = 0;
- unsigned stackSize = 0;
-
- const uchar *exceptionHandler = 0;
+ Heap::ExecutionContext *scope = static_cast<ExecutionContext &>(stack[CallData::Context]).d();
+ while (level > 0) {
+ --level;
+ scope = scope->outer;
+ }
+ Q_ASSERT(scope);
+ return static_cast<Heap::CallContext *>(scope);
+}
- QV4::Scope scope(engine);
- engine->current->lineNumber = -1;
+static inline const QV4::Value &constant(Function *function, int index)
+{
+ return function->compilationUnit->constants[index];
+}
-#ifdef DO_TRACE_INSTR
- qDebug("Starting VME with context=%p and code=%p", context, code);
-#endif // DO_TRACE_INSTR
- // setup lookup scopes
- int scopeDepth = 0;
- {
- QV4::Heap::ExecutionContext *scope = engine->current;
- while (scope) {
- ++scopeDepth;
- scope = scope->outer;
- }
+static bool compareEqual(Value lhs, Value rhs)
+{
+ redo:
+ if (lhs.asReturnedValue() == rhs.asReturnedValue())
+ return !lhs.isNaN();
+
+ int lt = lhs.quickType();
+ int rt = rhs.quickType();
+ if (rt < lt) {
+ qSwap(lhs, rhs);
+ qSwap(lt, rt);
}
- struct Scopes {
- QV4::Value *values;
- QV4::Heap::Base *base; // non 0 if a write barrier is required
- };
- Q_ALLOCA_VAR(Scopes, scopes, sizeof(Scopes)*(2 + 2*scopeDepth));
- {
- scopes[0] = { const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->constants), 0 };
- // stack gets setup in push instruction
- scopes[1] = { 0, 0 };
- QV4::Heap::ExecutionContext *scope = engine->current;
- int i = 0;
- while (scope) {
- if (scope->type == QV4::Heap::ExecutionContext::Type_SimpleCallContext) {
- QV4::Heap::SimpleCallContext *cc = static_cast<QV4::Heap::SimpleCallContext *>(scope);
- scopes[2*i + 2] = { cc->callData->args, 0 };
- scopes[2*i + 3] = { 0, 0 };
- } else if (scope->type == QV4::Heap::ExecutionContext::Type_CallContext) {
- QV4::Heap::CallContext *cc = static_cast<QV4::Heap::CallContext *>(scope);
- scopes[2*i + 2] = { cc->callData->args, cc };
- scopes[2*i + 3] = { cc->locals.values, cc };
+ switch (lt) {
+ case Value::QT_ManagedOrUndefined:
+ if (lhs.isUndefined())
+ return rhs.isNullOrUndefined();
+ Q_FALLTHROUGH();
+ case Value::QT_ManagedOrUndefined1:
+ case Value::QT_ManagedOrUndefined2:
+ case Value::QT_ManagedOrUndefined3:
+ // LHS: Managed
+ switch (rt) {
+ case Value::QT_ManagedOrUndefined:
+ if (rhs.isUndefined())
+ return false;
+ Q_FALLTHROUGH();
+ case Value::QT_ManagedOrUndefined1:
+ case Value::QT_ManagedOrUndefined2:
+ case Value::QT_ManagedOrUndefined3: {
+ // RHS: Managed
+ Heap::Base *l = lhs.m();
+ Heap::Base *r = rhs.m();
+ Q_ASSERT(l);
+ Q_ASSERT(r);
+ if (l->vtable()->isString == r->vtable()->isString)
+ return static_cast<QV4::Managed &>(lhs).isEqualTo(&static_cast<QV4::Managed &>(rhs));
+ if (l->vtable()->isString) {
+ rhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(rhs), PREFERREDTYPE_HINT));
+ break;
} else {
- scopes[2*i + 2] = { 0, 0 };
- scopes[2*i + 3] = { 0, 0 };
+ Q_ASSERT(r->vtable()->isString);
+ lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT));
+ break;
}
- ++i;
- scope = scope->outer;
+ return false;
+ }
+ case Value::QT_Empty:
+ Q_UNREACHABLE();
+ case Value::QT_Null:
+ return false;
+ case Value::QT_Bool:
+ case Value::QT_Int:
+ rhs = Primitive::fromDouble(rhs.int_32());
+ // fall through
+ default: // double
+ if (lhs.m()->vtable()->isString)
+ return RuntimeHelpers::toNumber(lhs) == rhs.doubleValue();
+ else
+ lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT));
}
+ goto redo;
+ case Value::QT_Empty:
+ Q_UNREACHABLE();
+ case Value::QT_Null:
+ return rhs.isNull();
+ case Value::QT_Bool:
+ case Value::QT_Int:
+ switch (rt) {
+ case Value::QT_ManagedOrUndefined:
+ case Value::QT_ManagedOrUndefined1:
+ case Value::QT_ManagedOrUndefined2:
+ case Value::QT_ManagedOrUndefined3:
+ case Value::QT_Empty:
+ case Value::QT_Null:
+ Q_UNREACHABLE();
+ case Value::QT_Bool:
+ case Value::QT_Int:
+ return lhs.int_32() == rhs.int_32();
+ default: // double
+ return lhs.int_32() == rhs.doubleValue();
+ }
+ default: // double
+ Q_ASSERT(rhs.isDouble());
+ return lhs.doubleValue() == rhs.doubleValue();
}
+}
+static bool compareEqualInt(Value &accumulator, Value lhs, int rhs)
+{
+ redo:
+ switch (lhs.quickType()) {
+ case Value::QT_ManagedOrUndefined:
+ if (lhs.isUndefined())
+ return false;
+ Q_FALLTHROUGH();
+ case Value::QT_ManagedOrUndefined1:
+ case Value::QT_ManagedOrUndefined2:
+ case Value::QT_ManagedOrUndefined3:
+ // LHS: Managed
+ if (lhs.m()->vtable()->isString)
+ return RuntimeHelpers::stringToNumber(static_cast<String &>(lhs).toQString()) == rhs;
+ accumulator = lhs;
+ lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(accumulator), PREFERREDTYPE_HINT));
+ goto redo;
+ case Value::QT_Empty:
+ Q_UNREACHABLE();
+ case Value::QT_Null:
+ return false;
+ case Value::QT_Bool:
+ case Value::QT_Int:
+ return lhs.int_32() == rhs;
+ default: // double
+ return lhs.doubleValue() == rhs;
+ }
+}
+
+#define STORE_IP() frame.instructionPointer = code;
+#define STORE_ACC() accumulator = acc;
+#define ACC Primitive::fromReturnedValue(acc)
+#define VALUE_TO_INT(i, val) \
+ int i; \
+ do { \
+ if (Q_LIKELY(val.integerCompatible())) { \
+ i = val.int_32(); \
+ } else { \
+ double d; \
+ if (val.isDouble()) \
+ d = val.doubleValue(); \
+ else { \
+ d = val.toNumberImpl(); \
+ CHECK_EXCEPTION; \
+ } \
+ i = Double::toInt32(d); \
+ } \
+ } while (false)
+
+QV4::ReturnedValue VME::exec(CallData *callData, QV4::Function *function)
+{
+ qt_v4ResolvePendingBreakpointsHook();
+
+ MOTH_JUMP_TABLE;
+
+ ExecutionEngine *engine = function->internalClass->engine;
+ CHECK_STACK_LIMITS(engine);
+ Profiling::FunctionCallProfiler profiler(engine, function);
+ Q_UNUSED(profiler)
+
+ Value *jsStackTop = engine->jsStackTop;
+
+ Q_ASSERT(engine->jsStackTop == callData->args + callData->argc());
+ Value *stack = reinterpret_cast<Value *>(callData);
+ int stackSpaceToAdd = int(function->compiledFunction->nRegisters) - callData->argc();
+ if (stackSpaceToAdd > 0) {
+ // clear out remaining arguments and local registers
+ for (int i = 0; i < stackSpaceToAdd; ++i)
+ engine->jsStackTop[i] = Encode::undefined();
+ engine->jsStackTop += stackSpaceToAdd;
+ }
+
+ CppStackFrame frame;
+ frame.parent = engine->currentStackFrame;
+ frame.v4Function = function;
+ frame.instructionPointer = function->codeData;
+ frame.jsFrame = callData;
+ engine->currentStackFrame = &frame;
+
+ const uchar *exceptionHandler = 0;
+
+ QV4::Value &accumulator = frame.jsFrame->accumulator;
+ QV4::ReturnedValue acc = Encode::undefined();
+
+ if (QV4::Debugging::Debugger *debugger = engine->debugger())
+ debugger->enteringFunction();
+
+ const uchar *code = function->codeData;
for (;;) {
- const Instr *genericInstr = reinterpret_cast<const Instr *>(code);
-#ifdef MOTH_THREADED_INTERPRETER
- goto *jumpTable[genericInstr->common.instructionType];
-#else
- switch (genericInstr->common.instructionType) {
-#endif
+ MOTH_DISPATCH()
+ Q_UNREACHABLE(); // only reached when the dispatch doesn't jump somewhere
+
+ MOTH_BEGIN_INSTR(LoadConst)
+ acc = constant(function, index).asReturnedValue();
+ MOTH_END_INSTR(LoadConst)
+
+ MOTH_BEGIN_INSTR(LoadNull)
+ acc = Encode::null();
+ MOTH_END_INSTR(LoadNull)
- MOTH_BEGIN_INSTR(Move)
- VALUE(instr.result) = VALUE(instr.source);
- MOTH_END_INSTR(Move)
+ MOTH_BEGIN_INSTR(LoadZero)
+ acc = Encode(static_cast<int>(0));
+ MOTH_END_INSTR(LoadZero)
+
+ MOTH_BEGIN_INSTR(LoadTrue)
+ acc = Encode(true);
+ MOTH_END_INSTR(LoadTrue)
+
+ MOTH_BEGIN_INSTR(LoadFalse)
+ acc = Encode(false);
+ MOTH_END_INSTR(LoadFalse)
+
+ MOTH_BEGIN_INSTR(LoadUndefined)
+ acc = Encode::undefined();
+ MOTH_END_INSTR(LoadUndefined)
+
+ MOTH_BEGIN_INSTR(LoadInt)
+ acc = Encode(value);
+ MOTH_END_INSTR(LoadInt)
MOTH_BEGIN_INSTR(MoveConst)
- VALUE(instr.result) = instr.source;
+ STACK_VALUE(destTemp) = constant(function, constIndex);
MOTH_END_INSTR(MoveConst)
- MOTH_BEGIN_INSTR(SwapTemps)
- qSwap(VALUE(instr.left), VALUE(instr.right));
- MOTH_END_INSTR(MoveTemp)
+ MOTH_BEGIN_INSTR(LoadReg)
+ acc = STACK_VALUE(reg).asReturnedValue();
+ MOTH_END_INSTR(LoadReg)
+
+ MOTH_BEGIN_INSTR(StoreReg)
+ STACK_VALUE(reg) = acc;
+ MOTH_END_INSTR(StoreReg)
+
+ MOTH_BEGIN_INSTR(MoveReg)
+ STACK_VALUE(destReg) = STACK_VALUE(srcReg);
+ MOTH_END_INSTR(MoveReg)
+
+ MOTH_BEGIN_INSTR(LoadLocal)
+ auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
+ acc = cc->locals[index].asReturnedValue();
+ MOTH_END_INSTR(LoadLocal)
+
+ MOTH_BEGIN_INSTR(StoreLocal)
+ CHECK_EXCEPTION;
+ auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
+ QV4::WriteBarrier::write(engine, cc, cc->locals.values + index, ACC);
+ MOTH_END_INSTR(StoreLocal)
+
+ MOTH_BEGIN_INSTR(LoadScopedLocal)
+ auto cc = getScope(stack, scope);
+ acc = cc->locals[index].asReturnedValue();
+ MOTH_END_INSTR(LoadScopedLocal)
+
+ MOTH_BEGIN_INSTR(StoreScopedLocal)
+ CHECK_EXCEPTION;
+ auto cc = getScope(stack, scope);
+ QV4::WriteBarrier::write(engine, cc, cc->locals.values + index, ACC);
+ MOTH_END_INSTR(StoreScopedLocal)
MOTH_BEGIN_INSTR(LoadRuntimeString)
-// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
- VALUE(instr.result) = engine->current->compilationUnit->runtimeStrings[instr.stringId];
+ acc = function->compilationUnit->runtimeStrings[stringId]->asReturnedValue();
MOTH_END_INSTR(LoadRuntimeString)
MOTH_BEGIN_INSTR(LoadRegExp)
-// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
- Heap::RegExpObject *ro = engine->newRegExpObject(
- static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)
- ->runtimeRegularExpressions[instr.regExpId].as<RegExp>());
- VALUE(instr.result) = ro;
+ acc = Runtime::method_regexpLiteral(engine, regExpId);
MOTH_END_INSTR(LoadRegExp)
MOTH_BEGIN_INSTR(LoadClosure)
- STOREVALUE(instr.result, Runtime::method_closure(engine, instr.value));
+ acc = Runtime::method_closure(engine, value);
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
- TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData());
- STOREVALUE(instr.result, Runtime::method_getActivationProperty(engine, instr.name));
+ STORE_IP();
+ acc = Runtime::method_loadName(engine, name);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(LoadName)
- MOTH_BEGIN_INSTR(GetGlobalLookup)
- QV4::Lookup *l = engine->current->lookups + instr.index;
- STOREVALUE(instr.result, l->globalGetter(l, engine));
- MOTH_END_INSTR(GetGlobalLookup)
+ MOTH_BEGIN_INSTR(LoadGlobalLookup)
+ QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
+ acc = l->globalGetter(l, engine);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(LoadGlobalLookup)
+
+ MOTH_BEGIN_INSTR(StoreNameStrict)
+ STORE_IP();
+ STORE_ACC();
+ Runtime::method_storeNameStrict(engine, name, accumulator);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(StoreNameSloppy)
- MOTH_BEGIN_INSTR(StoreName)
- TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData());
- Runtime::method_setActivationProperty(engine, instr.name, VALUE(instr.source));
+ MOTH_BEGIN_INSTR(StoreNameSloppy)
+ STORE_IP();
+ STORE_ACC();
+ Runtime::method_storeNameSloppy(engine, name, accumulator);
CHECK_EXCEPTION;
- MOTH_END_INSTR(StoreName)
+ MOTH_END_INSTR(StoreNameSloppy)
MOTH_BEGIN_INSTR(LoadElement)
- STOREVALUE(instr.result, Runtime::method_getElement(engine, VALUE(instr.base), VALUE(instr.index)));
+ STORE_IP();
+ acc = Runtime::method_loadElement(engine, STACK_VALUE(base), STACK_VALUE(index));
+ CHECK_EXCEPTION;
MOTH_END_INSTR(LoadElement)
- MOTH_BEGIN_INSTR(LoadElementLookup)
- QV4::Lookup *l = engine->current->lookups + instr.lookup;
- STOREVALUE(instr.result, l->indexedGetter(l, engine, VALUE(instr.base), VALUE(instr.index)));
- MOTH_END_INSTR(LoadElementLookup)
+ MOTH_BEGIN_INSTR(LoadElementA)
+ STORE_IP();
+ STORE_ACC();
+ acc = Runtime::method_loadElement(engine, STACK_VALUE(base), accumulator);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(LoadElementA)
MOTH_BEGIN_INSTR(StoreElement)
- Runtime::method_setElement(engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
+ STORE_IP();
+ STORE_ACC();
+ if (!Runtime::method_storeElement(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator) && function->isStrict())
+ engine->throwTypeError();
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElement)
- MOTH_BEGIN_INSTR(StoreElementLookup)
- QV4::Lookup *l = engine->current->lookups + instr.lookup;
- l->indexedSetter(l, engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
- CHECK_EXCEPTION;
- MOTH_END_INSTR(StoreElementLookup)
-
MOTH_BEGIN_INSTR(LoadProperty)
- STOREVALUE(instr.result, Runtime::method_getProperty(engine, VALUE(instr.base), instr.name));
+ STORE_IP();
+ acc = Runtime::method_loadProperty(engine, STACK_VALUE(base), name);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(LoadProperty)
+ MOTH_BEGIN_INSTR(LoadPropertyA)
+ STORE_IP();
+ STORE_ACC();
+ acc = Runtime::method_loadProperty(engine, accumulator, name);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(LoadPropertyA)
+
MOTH_BEGIN_INSTR(GetLookup)
- QV4::Lookup *l = engine->current->lookups + instr.index;
- STOREVALUE(instr.result, l->getter(l, engine, VALUE(instr.base)));
+ STORE_IP();
+ QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
+ acc = l->getter(l, engine, STACK_VALUE(base));
+ CHECK_EXCEPTION;
MOTH_END_INSTR(GetLookup)
+ MOTH_BEGIN_INSTR(GetLookupA)
+ STORE_IP();
+ STORE_ACC();
+ QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
+ acc = l->getter(l, engine, accumulator);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(GetLookupA)
+
MOTH_BEGIN_INSTR(StoreProperty)
- Runtime::method_setProperty(engine, VALUE(instr.base), instr.name, VALUE(instr.source));
+ STORE_IP();
+ STORE_ACC();
+ if (!Runtime::method_storeProperty(engine, STACK_VALUE(base), name, accumulator) && function->isStrict())
+ engine->throwTypeError();
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreProperty)
MOTH_BEGIN_INSTR(SetLookup)
- QV4::Lookup *l = engine->current->lookups + instr.index;
- l->setter(l, engine, VALUE(instr.base), VALUE(instr.source));
+ STORE_IP();
+ STORE_ACC();
+ QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
+ if (!l->setter(l, engine, STACK_VALUE(base), accumulator) && function->isStrict())
+ engine->throwTypeError();
CHECK_EXCEPTION;
MOTH_END_INSTR(SetLookup)
- MOTH_BEGIN_INSTR(StoreQObjectProperty)
- Runtime::method_setQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
- CHECK_EXCEPTION;
- MOTH_END_INSTR(StoreQObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadQObjectProperty)
- STOREVALUE(instr.result, Runtime::method_getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
- MOTH_END_INSTR(LoadQObjectProperty)
-
MOTH_BEGIN_INSTR(StoreScopeObjectProperty)
- Runtime::method_setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
+ STORE_ACC();
+ Runtime::method_storeQmlScopeObjectProperty(engine, STACK_VALUE(base), propertyIndex, accumulator);
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreScopeObjectProperty)
MOTH_BEGIN_INSTR(LoadScopeObjectProperty)
- STOREVALUE(instr.result, Runtime::method_getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
+ STORE_IP();
+ acc = Runtime::method_loadQmlScopeObjectProperty(engine, STACK_VALUE(base), propertyIndex, captureRequired);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(LoadScopeObjectProperty)
MOTH_BEGIN_INSTR(StoreContextObjectProperty)
- Runtime::method_setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source));
+ STORE_IP();
+ STORE_ACC();
+ Runtime::method_storeQmlContextObjectProperty(engine, STACK_VALUE(base), propertyIndex, accumulator);
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreContextObjectProperty)
MOTH_BEGIN_INSTR(LoadContextObjectProperty)
- STOREVALUE(instr.result, Runtime::method_getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
+ STORE_IP();
+ acc = Runtime::method_loadQmlContextObjectProperty(engine, STACK_VALUE(base), propertyIndex, captureRequired);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(LoadContextObjectProperty)
MOTH_BEGIN_INSTR(LoadIdObject)
- STOREVALUE(instr.result, Runtime::method_getQmlIdObject(engine, VALUE(instr.base), instr.index));
+ STORE_IP();
+ acc = Runtime::method_loadQmlIdObject(engine, STACK_VALUE(base), index);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(LoadIdObject)
- MOTH_BEGIN_INSTR(LoadAttachedQObjectProperty)
- STOREVALUE(instr.result, Runtime::method_getQmlAttachedProperty(engine, instr.attachedPropertiesId, instr.propertyIndex));
- MOTH_END_INSTR(LoadAttachedQObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadSingletonQObjectProperty)
- STOREVALUE(instr.result, Runtime::method_getQmlSingletonQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired));
- MOTH_END_INSTR(LoadSingletonQObjectProperty)
-
- MOTH_BEGIN_INSTR(Push)
- TRACE(inline, "stack size: %u", instr.value);
- stackSize = instr.value;
- stack = scope.alloc(stackSize);
- scopes[1].values = stack;
- MOTH_END_INSTR(Push)
-
MOTH_BEGIN_INSTR(CallValue)
-#if 0 //def DO_TRACE_INSTR
- if (Debugging::Debugger *debugger = context->engine()->debugger) {
- if (QV4::FunctionObject *o = (VALUE(instr.dest)).asFunctionObject()) {
- if (Debugging::FunctionDebugInfo *info = debugger->debugInfo(o)) {
- QString n = debugger->name(o);
- std::cerr << "*** Call to \"" << (n.isNull() ? "<no name>" : qPrintable(n)) << "\" defined @" << info->startLine << ":" << info->startColumn << std::endl;
- }
- }
- }
-#endif // DO_TRACE_INSTR
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::method_callValue(engine, VALUE(instr.dest), callData));
+ STORE_IP();
+ STORE_ACC();
+ acc = Runtime::method_callValue(engine, accumulator, stack + argv, argc);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallProperty)
- TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData());
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::method_callProperty(engine, instr.name, callData));
+ STORE_IP();
+ acc = Runtime::method_callProperty(engine, stack + base, name, stack + argv, argc);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::method_callPropertyLookup(engine, instr.lookupIndex, callData));
+ STORE_IP();
+ acc = Runtime::method_callPropertyLookup(engine, stack + base, lookupIndex, stack + argv, argc);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(CallPropertyLookup)
- MOTH_BEGIN_INSTR(CallScopeObjectProperty)
- TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData());
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::method_callQmlScopeObjectProperty(engine, instr.index, callData));
- MOTH_END_INSTR(CallScopeObjectProperty)
-
- MOTH_BEGIN_INSTR(CallContextObjectProperty)
- TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData());
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::method_callQmlContextObjectProperty(engine, instr.index, callData));
- MOTH_END_INSTR(CallContextObjectProperty)
-
MOTH_BEGIN_INSTR(CallElement)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::method_callElement(engine, VALUE(instr.index), callData));
+ STORE_IP();
+ acc = Runtime::method_callElement(engine, stack + base, STACK_VALUE(index), stack + argv, argc);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(CallElement)
- MOTH_BEGIN_INSTR(CallActivationProperty)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::method_callActivationProperty(engine, instr.name, callData));
- MOTH_END_INSTR(CallActivationProperty)
+ MOTH_BEGIN_INSTR(CallName)
+ STORE_IP();
+ acc = Runtime::method_callName(engine, name, stack + argv, argc);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(CallName)
+
+ MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
+ STORE_IP();
+ acc = Runtime::method_callPossiblyDirectEval(engine, stack + argv, argc);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::method_callGlobalLookup(engine, instr.index, callData));
+ STORE_IP();
+ acc = Runtime::method_callGlobalLookup(engine, index, stack + argv, argc);
+ CHECK_EXCEPTION;
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(SetExceptionHandler)
- exceptionHandler = instr.offset ? ((const uchar *)&instr.offset) + instr.offset : 0;
+ exceptionHandler = offset ? code + offset : nullptr;
MOTH_END_INSTR(SetExceptionHandler)
- MOTH_BEGIN_INSTR(CallBuiltinThrow)
- Runtime::method_throwException(engine, VALUE(instr.arg));
+ MOTH_BEGIN_INSTR(ThrowException)
+ STORE_IP();
+ STORE_ACC();
+ Runtime::method_throwException(engine, accumulator);
+ goto catchException;
+ MOTH_END_INSTR(ThrowException)
+
+ MOTH_BEGIN_INSTR(GetException)
+ acc = engine->hasException ? engine->exceptionValue->asReturnedValue() : Primitive::emptyValue().asReturnedValue();
+ engine->hasException = false;
+ MOTH_END_INSTR(HasException)
+
+ MOTH_BEGIN_INSTR(SetException)
+ *engine->exceptionValue = acc;
+ engine->hasException = true;
+ MOTH_END_INSTR(SetException)
+
+ MOTH_BEGIN_INSTR(PushCatchContext)
+ STACK_VALUE(reg) = STACK_VALUE(CallData::Context);
+ ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
+ STACK_VALUE(CallData::Context) = Runtime::method_createCatchContext(c, name);
+ MOTH_END_INSTR(PushCatchContext)
+
+ MOTH_BEGIN_INSTR(CreateCallContext)
+ Heap::ExecutionContext *ctx = static_cast<Heap::ExecutionContext *>(stack[CallData::Context].m());
+ stack[CallData::Context] = ExecutionContext::newCallContext(ctx, function, reinterpret_cast<CallData *>(stack));
+ MOTH_END_INSTR(CreateCallContext)
+
+ MOTH_BEGIN_INSTR(PushWithContext)
+ STORE_IP();
+ STORE_ACC();
+ accumulator = accumulator.toObject(engine);
CHECK_EXCEPTION;
- MOTH_END_INSTR(CallBuiltinThrow)
+ STACK_VALUE(reg) = STACK_VALUE(CallData::Context);
+ ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
+ STACK_VALUE(CallData::Context) = Runtime::method_createWithContext(c, accumulator);
+ MOTH_END_INSTR(PushWithContext)
+
+ MOTH_BEGIN_INSTR(PopContext)
+ STACK_VALUE(CallData::Context) = STACK_VALUE(reg);
+ MOTH_END_INSTR(PopContext)
+
+ MOTH_BEGIN_INSTR(ForeachIteratorObject)
+ STORE_ACC();
+ acc = Runtime::method_foreachIterator(engine, accumulator);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(ForeachIteratorObject)
- MOTH_BEGIN_INSTR(CallBuiltinUnwindException)
- STOREVALUE(instr.result, Runtime::method_unwindException(engine));
- MOTH_END_INSTR(CallBuiltinUnwindException)
+ MOTH_BEGIN_INSTR(ForeachNextPropertyName)
+ STORE_ACC();
+ acc = Runtime::method_foreachNextPropertyName(accumulator);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(ForeachNextPropertyName)
+
+ MOTH_BEGIN_INSTR(DeleteMember)
+ if (!Runtime::method_deleteMember(engine, STACK_VALUE(base), member)) {
+ if (function->isStrict()) {
+ STORE_IP();
+ engine->throwTypeError();
+ goto catchException;
+ }
+ acc = Encode(false);
+ } else {
+ acc = Encode(true);
+ }
+ MOTH_END_INSTR(DeleteMember)
+
+ MOTH_BEGIN_INSTR(DeleteSubscript)
+ if (!Runtime::method_deleteElement(engine, STACK_VALUE(base), STACK_VALUE(index))) {
+ if (function->isStrict()) {
+ STORE_IP();
+ engine->throwTypeError();
+ goto catchException;
+ }
+ acc = Encode(false);
+ } else {
+ acc = Encode(true);
+ }
+ MOTH_END_INSTR(DeleteSubscript)
+
+ MOTH_BEGIN_INSTR(DeleteName)
+ if (!Runtime::method_deleteName(engine, name)) {
+ if (function->isStrict()) {
+ STORE_IP();
+ QString n = function->compilationUnit->runtimeStrings[name]->toQString();
+ engine->throwSyntaxError(QStringLiteral("Can't delete property %1").arg(n));
+ goto catchException;
+ }
+ acc = Encode(false);
+ } else {
+ acc = Encode(true);
+ }
+ MOTH_END_INSTR(DeleteName)
+
+ MOTH_BEGIN_INSTR(TypeofName)
+ acc = Runtime::method_typeofName(engine, name);
+ MOTH_END_INSTR(TypeofName)
+
+ MOTH_BEGIN_INSTR(TypeofValue)
+ STORE_ACC();
+ acc = Runtime::method_typeofValue(engine, accumulator);
+ MOTH_END_INSTR(TypeofValue)
+
+ MOTH_BEGIN_INSTR(DeclareVar)
+ Runtime::method_declareVar(engine, isDeletable, varName);
+ MOTH_END_INSTR(DeclareVar)
+
+ MOTH_BEGIN_INSTR(DefineArray)
+ QV4::Value *arguments = stack + args;
+ acc = Runtime::method_arrayLiteral(engine, arguments, argc);
+ MOTH_END_INSTR(DefineArray)
+
+ MOTH_BEGIN_INSTR(DefineObjectLiteral)
+ QV4::Value *arguments = stack + args;
+ acc = Runtime::method_objectLiteral(engine, arguments, internalClassId, arrayValueCount, arrayGetterSetterCountAndFlags);
+ MOTH_END_INSTR(DefineObjectLiteral)
+
+ MOTH_BEGIN_INSTR(CreateMappedArgumentsObject)
+ acc = Runtime::method_createMappedArgumentsObject(engine);
+ MOTH_END_INSTR(CreateMappedArgumentsObject)
+
+ MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject)
+ acc = Runtime::method_createUnmappedArgumentsObject(engine);
+ MOTH_END_INSTR(CreateUnmappedArgumentsObject)
+
+ MOTH_BEGIN_INSTR(ConvertThisToObject)
+ Value *t = &stack[CallData::This];
+ if (!t->isObject()) {
+ if (t->isNullOrUndefined()) {
+ *t = engine->globalObject->asReturnedValue();
+ } else {
+ *t = t->toObject(engine)->asReturnedValue();
+ CHECK_EXCEPTION;
+ }
+ }
+ MOTH_END_INSTR(ConvertThisToObject)
- MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope)
- Runtime::method_pushCatchScope(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
- MOTH_END_INSTR(CallBuiltinPushCatchScope)
-
- MOTH_BEGIN_INSTR(CallBuiltinPushScope)
- Runtime::method_pushWithScope(VALUE(instr.arg), static_cast<QV4::NoThrowEngine*>(engine));
- CHECK_EXCEPTION;
- MOTH_END_INSTR(CallBuiltinPushScope)
-
- MOTH_BEGIN_INSTR(CallBuiltinPopScope)
- Runtime::method_popScope(static_cast<QV4::NoThrowEngine*>(engine));
- MOTH_END_INSTR(CallBuiltinPopScope)
-
- MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject)
- STOREVALUE(instr.result, Runtime::method_foreachIterator(engine, VALUE(instr.arg)));
- MOTH_END_INSTR(CallBuiltinForeachIteratorObject)
-
- MOTH_BEGIN_INSTR(CallBuiltinForeachNextPropertyName)
- STOREVALUE(instr.result, Runtime::method_foreachNextPropertyName(VALUE(instr.arg)));
- MOTH_END_INSTR(CallBuiltinForeachNextPropertyName)
-
- MOTH_BEGIN_INSTR(CallBuiltinDeleteMember)
- STOREVALUE(instr.result, Runtime::method_deleteMember(engine, VALUE(instr.base), instr.member));
- MOTH_END_INSTR(CallBuiltinDeleteMember)
-
- MOTH_BEGIN_INSTR(CallBuiltinDeleteSubscript)
- STOREVALUE(instr.result, Runtime::method_deleteElement(engine, VALUE(instr.base), VALUE(instr.index)));
- MOTH_END_INSTR(CallBuiltinDeleteSubscript)
-
- MOTH_BEGIN_INSTR(CallBuiltinDeleteName)
- STOREVALUE(instr.result, Runtime::method_deleteName(engine, instr.name));
- MOTH_END_INSTR(CallBuiltinDeleteName)
-
- MOTH_BEGIN_INSTR(CallBuiltinTypeofScopeObjectProperty)
- STOREVALUE(instr.result, Runtime::method_typeofScopeObjectProperty(engine, VALUE(instr.base), instr.index));
- MOTH_END_INSTR(CallBuiltinTypeofMember)
-
- MOTH_BEGIN_INSTR(CallBuiltinTypeofContextObjectProperty)
- STOREVALUE(instr.result, Runtime::method_typeofContextObjectProperty(engine, VALUE(instr.base), instr.index));
- MOTH_END_INSTR(CallBuiltinTypeofMember)
-
- MOTH_BEGIN_INSTR(CallBuiltinTypeofMember)
- STOREVALUE(instr.result, Runtime::method_typeofMember(engine, VALUE(instr.base), instr.member));
- MOTH_END_INSTR(CallBuiltinTypeofMember)
-
- MOTH_BEGIN_INSTR(CallBuiltinTypeofSubscript)
- STOREVALUE(instr.result, Runtime::method_typeofElement(engine, VALUE(instr.base), VALUE(instr.index)));
- MOTH_END_INSTR(CallBuiltinTypeofSubscript)
-
- MOTH_BEGIN_INSTR(CallBuiltinTypeofName)
- STOREVALUE(instr.result, Runtime::method_typeofName(engine, instr.name));
- MOTH_END_INSTR(CallBuiltinTypeofName)
-
- MOTH_BEGIN_INSTR(CallBuiltinTypeofValue)
- STOREVALUE(instr.result, Runtime::method_typeofValue(engine, VALUE(instr.value)));
- MOTH_END_INSTR(CallBuiltinTypeofValue)
-
- MOTH_BEGIN_INSTR(CallBuiltinDeclareVar)
- Runtime::method_declareVar(engine, instr.isDeletable, instr.varName);
- MOTH_END_INSTR(CallBuiltinDeclareVar)
-
- MOTH_BEGIN_INSTR(CallBuiltinDefineArray)
- Q_ASSERT(instr.args + instr.argc <= stackSize);
- QV4::Value *args = stack + instr.args;
- STOREVALUE(instr.result, Runtime::method_arrayLiteral(engine, args, instr.argc));
- MOTH_END_INSTR(CallBuiltinDefineArray)
-
- MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral)
- QV4::Value *args = stack + instr.args;
- STOREVALUE(instr.result, Runtime::method_objectLiteral(engine, args, instr.internalClassId, instr.arrayValueCount, instr.arrayGetterSetterCountAndFlags));
- MOTH_END_INSTR(CallBuiltinDefineObjectLiteral)
-
- MOTH_BEGIN_INSTR(CallBuiltinSetupArgumentsObject)
- STOREVALUE(instr.result, Runtime::method_setupArgumentsObject(engine));
- MOTH_END_INSTR(CallBuiltinSetupArgumentsObject)
-
- MOTH_BEGIN_INSTR(CallBuiltinConvertThisToObject)
- Runtime::method_convertThisToObject(engine);
- CHECK_EXCEPTION;
- MOTH_END_INSTR(CallBuiltinConvertThisToObject)
-
- MOTH_BEGIN_INSTR(CreateValue)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::method_constructValue(engine, VALUE(instr.func), callData));
- MOTH_END_INSTR(CreateValue)
-
- MOTH_BEGIN_INSTR(CreateProperty)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::method_constructProperty(engine, instr.name, callData));
- MOTH_END_INSTR(CreateProperty)
-
- MOTH_BEGIN_INSTR(ConstructPropertyLookup)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = VALUE(instr.base);
- STOREVALUE(instr.result, Runtime::method_constructPropertyLookup(engine, instr.index, callData));
- MOTH_END_INSTR(ConstructPropertyLookup)
-
- MOTH_BEGIN_INSTR(CreateActivationProperty)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::method_constructActivationProperty(engine, instr.name, callData));
- MOTH_END_INSTR(CreateActivationProperty)
-
- MOTH_BEGIN_INSTR(ConstructGlobalLookup)
- Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
- QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = quint32(Value::ValueTypeInternal::Integer);
- callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, Runtime::method_constructGlobalLookup(engine, instr.index, callData));
- MOTH_END_INSTR(ConstructGlobalLookup)
+ MOTH_BEGIN_INSTR(Construct)
+ STORE_IP();
+ acc = Runtime::method_construct(engine, STACK_VALUE(func), stack + argv, argc);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(Construct)
MOTH_BEGIN_INSTR(Jump)
- code = ((const uchar *)&instr.offset) + instr.offset;
+ code += offset;
MOTH_END_INSTR(Jump)
- MOTH_BEGIN_INSTR(JumpEq)
- bool cond = VALUEPTR(instr.condition)->toBoolean();
- TRACE(condition, "%s", cond ? "TRUE" : "FALSE");
- if (cond)
- code = ((const uchar *)&instr.offset) + instr.offset;
- MOTH_END_INSTR(JumpEq)
+ MOTH_BEGIN_INSTR(JumpTrue)
+ //### store a type hint, and if the input is a bool, do:
+ // ((acc & 1) == 1)
+ // because if(1) will end up here with an integer in the accumulator
+ if ((ACC.integerCompatible() && ACC.int_32()) || ACC.toBoolean())
+ code += offset;
+ MOTH_END_INSTR(JumpTrue)
+
+ MOTH_BEGIN_INSTR(JumpFalse)
+ //### see comment for JumpTrue
+ if ((ACC.integerCompatible() && !ACC.int_32()) || !ACC.toBoolean())
+ code += offset;
+ MOTH_END_INSTR(JumpFalse)
+
+ MOTH_BEGIN_INSTR(CmpEqNull)
+ acc = Encode(ACC.isNullOrUndefined());
+ MOTH_END_INSTR(CmpEqNull)
+
+ MOTH_BEGIN_INSTR(CmpNeNull)
+ acc = Encode(!ACC.isNullOrUndefined());
+ MOTH_END_INSTR(CmpNeNull)
+
+ MOTH_BEGIN_INSTR(CmpEqInt)
+ if (ACC.isIntOrBool()) {
+ acc = Encode(ACC.int_32() == lhs);
+ } else {
+ STORE_ACC();
+ acc = Encode(compareEqualInt(accumulator, ACC, lhs));
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(CmpEqInt)
+
+ MOTH_BEGIN_INSTR(CmpNeInt)
+ if (ACC.isIntOrBool()) {
+ acc = Encode(bool(ACC.int_32() != lhs));
+ } else {
+ STORE_ACC();
+ acc = Encode(!compareEqualInt(accumulator, ACC, lhs));
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(CmpNeInt)
+
+ MOTH_BEGIN_INSTR(CmpEq)
+ const Value left = STACK_VALUE(lhs);
+ if (Q_LIKELY(left.asReturnedValue() == ACC.asReturnedValue())) {
+ acc = Encode(!ACC.isNaN());
+ } else if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
+ acc = Encode(left.int_32() == ACC.int_32());
+ } else {
+ STORE_ACC();
+ acc = Encode(compareEqual(left, accumulator));
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(CmpEq)
+
+ MOTH_BEGIN_INSTR(CmpNe)
+ const Value left = STACK_VALUE(lhs);
+ if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
+ acc = Encode(bool(left.int_32() != ACC.int_32()));
+ } else {
+ STORE_ACC();
+ acc = Encode(!compareEqual(left, accumulator));
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(CmpNe)
+
+ MOTH_BEGIN_INSTR(CmpGt)
+ const Value left = STACK_VALUE(lhs);
+ if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
+ acc = Encode(left.int_32() > ACC.int_32());
+ } else if (left.isNumber() && ACC.isNumber()) {
+ acc = Encode(left.asDouble() > ACC.asDouble());
+ } else {
+ STORE_ACC();
+ acc = Encode(bool(Runtime::method_compareGreaterThan(left, accumulator)));
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(CmpGt)
+
+ MOTH_BEGIN_INSTR(CmpGe)
+ const Value left = STACK_VALUE(lhs);
+ if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
+ acc = Encode(left.int_32() >= ACC.int_32());
+ } else if (left.isNumber() && ACC.isNumber()) {
+ acc = Encode(left.asDouble() >= ACC.asDouble());
+ } else {
+ STORE_ACC();
+ acc = Encode(bool(Runtime::method_compareGreaterEqual(left, accumulator)));
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(CmpGe)
+
+ MOTH_BEGIN_INSTR(CmpLt)
+ const Value left = STACK_VALUE(lhs);
+ if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
+ acc = Encode(left.int_32() < ACC.int_32());
+ } else if (left.isNumber() && ACC.isNumber()) {
+ acc = Encode(left.asDouble() < ACC.asDouble());
+ } else {
+ STORE_ACC();
+ acc = Encode(bool(Runtime::method_compareLessThan(left, accumulator)));
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(CmpLt)
+
+ MOTH_BEGIN_INSTR(CmpLe)
+ const Value left = STACK_VALUE(lhs);
+ if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
+ acc = Encode(left.int_32() <= ACC.int_32());
+ } else if (left.isNumber() && ACC.isNumber()) {
+ acc = Encode(left.asDouble() <= ACC.asDouble());
+ } else {
+ STORE_ACC();
+ acc = Encode(bool(Runtime::method_compareLessEqual(left, accumulator)));
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(CmpLe)
+
+ MOTH_BEGIN_INSTR(CmpStrictEqual)
+ if (STACK_VALUE(lhs).rawValue() == ACC.rawValue() && !ACC.isNaN()) {
+ acc = Encode(true);
+ } else {
+ STORE_ACC();
+ acc = Encode(bool(RuntimeHelpers::strictEqual(STACK_VALUE(lhs), accumulator)));
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(CmpStrictEqual)
+
+ MOTH_BEGIN_INSTR(CmpStrictNotEqual)
+ if (STACK_VALUE(lhs).rawValue() != ACC.rawValue() || ACC.isNaN()) {
+ STORE_ACC();
+ acc = Encode(!RuntimeHelpers::strictEqual(STACK_VALUE(lhs), accumulator));
+ CHECK_EXCEPTION;
+ } else {
+ acc = Encode(false);
+ }
+ MOTH_END_INSTR(CmpStrictNotEqual)
- MOTH_BEGIN_INSTR(JumpNe)
- bool cond = VALUEPTR(instr.condition)->toBoolean();
- TRACE(condition, "%s", cond ? "TRUE" : "FALSE");
- if (!cond)
- code = ((const uchar *)&instr.offset) + instr.offset;
- MOTH_END_INSTR(JumpNe)
+ MOTH_BEGIN_INSTR(CmpIn)
+ STORE_ACC();
+ acc = Runtime::method_in(engine, STACK_VALUE(lhs), accumulator);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(CmpIn)
+
+ MOTH_BEGIN_INSTR(CmpInstanceOf)
+ STORE_ACC();
+ acc = Runtime::method_instanceof(engine, STACK_VALUE(lhs), accumulator);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(CmpInstanceOf)
+
+ MOTH_BEGIN_INSTR(JumpStrictNotEqualStackSlotInt)
+ if (STACK_VALUE(lhs).int_32() != rhs || STACK_VALUE(lhs).isUndefined())
+ code += offset;
+ MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt)
+
+ MOTH_BEGIN_INSTR(JumpStrictEqualStackSlotInt)
+ if (STACK_VALUE(lhs).int_32() == rhs && !STACK_VALUE(lhs).isUndefined())
+ code += offset;
+ MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt)
MOTH_BEGIN_INSTR(UNot)
- STOREVALUE(instr.result, Runtime::method_uNot(VALUE(instr.source)));
+ if (ACC.integerCompatible()) {
+ acc = Encode(!static_cast<bool>(ACC.int_32()));
+ } else {
+ acc = Encode(!Value::toBooleanImpl(ACC));
+ }
MOTH_END_INSTR(UNot)
- MOTH_BEGIN_INSTR(UNotBool)
- bool b = VALUE(instr.source).booleanValue();
- VALUE(instr.result) = QV4::Encode(!b);
- MOTH_END_INSTR(UNotBool)
-
MOTH_BEGIN_INSTR(UPlus)
- STOREVALUE(instr.result, Runtime::method_uPlus(VALUE(instr.source)));
+ if (Q_UNLIKELY(!ACC.isNumber())) {
+ acc = Encode(ACC.toNumberImpl());
+ CHECK_EXCEPTION;
+ }
MOTH_END_INSTR(UPlus)
MOTH_BEGIN_INSTR(UMinus)
- STOREVALUE(instr.result, Runtime::method_uMinus(VALUE(instr.source)));
+ if (Q_LIKELY(ACC.integerCompatible())) {
+ int a = ACC.int_32();
+ if (a == 0 || a == std::numeric_limits<int>::min()) {
+ acc = Encode(-static_cast<double>(a));
+ } else {
+ acc = sub_int32(0, ACC.int_32());
+ }
+ } else if (ACC.isDouble()) {
+ acc ^= (1ull << 63); // simply flip sign bit
+ } else {
+ acc = Encode(-ACC.toNumberImpl());
+ CHECK_EXCEPTION;
+ }
MOTH_END_INSTR(UMinus)
MOTH_BEGIN_INSTR(UCompl)
- STOREVALUE(instr.result, Runtime::method_complement(VALUE(instr.source)));
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(~a);
MOTH_END_INSTR(UCompl)
- MOTH_BEGIN_INSTR(UComplInt)
- VALUE(instr.result) = QV4::Encode((int)~VALUE(instr.source).integerValue());
- MOTH_END_INSTR(UComplInt)
-
MOTH_BEGIN_INSTR(Increment)
- STOREVALUE(instr.result, Runtime::method_increment(VALUE(instr.source)));
+ if (Q_LIKELY(ACC.integerCompatible())) {
+ acc = add_int32(ACC.int_32(), 1);
+ } else if (ACC.isDouble()) {
+ acc = QV4::Encode(ACC.doubleValue() + 1.);
+ } else {
+ acc = Encode(ACC.toNumberImpl() + 1.);
+ CHECK_EXCEPTION;
+ }
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
- STOREVALUE(instr.result, Runtime::method_decrement(VALUE(instr.source)));
+ if (Q_LIKELY(ACC.integerCompatible())) {
+ acc = sub_int32(ACC.int_32(), 1);
+ } else if (ACC.isDouble()) {
+ acc = QV4::Encode(ACC.doubleValue() - 1.);
+ } else {
+ acc = Encode(ACC.toNumberImpl() - 1.);
+ CHECK_EXCEPTION;
+ }
MOTH_END_INSTR(Decrement)
- MOTH_BEGIN_INSTR(Binop)
- QV4::Runtime::BinaryOperation op = *reinterpret_cast<QV4::Runtime::BinaryOperation *>(reinterpret_cast<char *>(&engine->runtime.runtimeMethods[instr.alu]));
- STOREVALUE(instr.result, op(VALUE(instr.lhs), VALUE(instr.rhs)));
- MOTH_END_INSTR(Binop)
-
MOTH_BEGIN_INSTR(Add)
- STOREVALUE(instr.result, Runtime::method_add(engine, VALUE(instr.lhs), VALUE(instr.rhs)));
+ const Value left = STACK_VALUE(lhs);
+ if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
+ acc = add_int32(left.int_32(), ACC.int_32());
+ } else if (left.isNumber() && ACC.isNumber()) {
+ acc = Encode(left.asDouble() + ACC.asDouble());
+ } else {
+ STORE_ACC();
+ acc = Runtime::method_add(engine, left, accumulator);
+ CHECK_EXCEPTION;
+ }
MOTH_END_INSTR(Add)
+ MOTH_BEGIN_INSTR(Sub)
+ const Value left = STACK_VALUE(lhs);
+ if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
+ acc = sub_int32(left.int_32(), ACC.int_32());
+ } else if (left.isNumber() && ACC.isNumber()) {
+ acc = Encode(left.asDouble() - ACC.asDouble());
+ } else {
+ STORE_ACC();
+ acc = Runtime::method_sub(left, accumulator);
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(Sub)
+
+ MOTH_BEGIN_INSTR(Mul)
+ const Value left = STACK_VALUE(lhs);
+ if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
+ acc = mul_int32(left.int_32(), ACC.int_32());
+ } else if (left.isNumber() && ACC.isNumber()) {
+ acc = Encode(left.asDouble() * ACC.asDouble());
+ } else {
+ STORE_ACC();
+ acc = Runtime::method_mul(left, accumulator);
+ CHECK_EXCEPTION;
+ }
+ MOTH_END_INSTR(Mul)
+
+ MOTH_BEGIN_INSTR(Div)
+ STORE_ACC();
+ acc = Runtime::method_div(STACK_VALUE(lhs), accumulator);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(Div)
+
+ MOTH_BEGIN_INSTR(Mod)
+ STORE_ACC();
+ acc = Runtime::method_mod(STACK_VALUE(lhs), accumulator);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(Mod)
+
MOTH_BEGIN_INSTR(BitAnd)
- STOREVALUE(instr.result, Runtime::method_bitAnd(VALUE(instr.lhs), VALUE(instr.rhs)));
+ VALUE_TO_INT(l, STACK_VALUE(lhs));
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(l & a);
MOTH_END_INSTR(BitAnd)
MOTH_BEGIN_INSTR(BitOr)
- STOREVALUE(instr.result, Runtime::method_bitOr(VALUE(instr.lhs), VALUE(instr.rhs)));
+ VALUE_TO_INT(l, STACK_VALUE(lhs));
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(l | a);
MOTH_END_INSTR(BitOr)
MOTH_BEGIN_INSTR(BitXor)
- STOREVALUE(instr.result, Runtime::method_bitXor(VALUE(instr.lhs), VALUE(instr.rhs)));
+ VALUE_TO_INT(l, STACK_VALUE(lhs));
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(l ^ a);
MOTH_END_INSTR(BitXor)
+ MOTH_BEGIN_INSTR(UShr)
+ uint l = STACK_VALUE(lhs).toUInt32();
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(l >> uint(a & 0x1f));
+ MOTH_END_INSTR(UShr)
+
MOTH_BEGIN_INSTR(Shr)
- STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() >> (VALUEPTR(instr.rhs)->toInt32() & 0x1f))));
+ VALUE_TO_INT(l, STACK_VALUE(lhs));
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(l >> (a & 0x1f));
MOTH_END_INSTR(Shr)
MOTH_BEGIN_INSTR(Shl)
- STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() << (VALUEPTR(instr.rhs)->toInt32() & 0x1f))));
+ VALUE_TO_INT(l, STACK_VALUE(lhs));
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(l << (a & 0x1f));
MOTH_END_INSTR(Shl)
MOTH_BEGIN_INSTR(BitAndConst)
- int lhs = VALUEPTR(instr.lhs)->toInt32();
- STOREVALUE(instr.result, QV4::Encode((int)(lhs & instr.rhs)));
- MOTH_END_INSTR(BitAnd)
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(a & rhs);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(BitAndConst)
MOTH_BEGIN_INSTR(BitOrConst)
- int lhs = VALUEPTR(instr.lhs)->toInt32();
- STOREVALUE(instr.result, QV4::Encode((int)(lhs | instr.rhs)));
- MOTH_END_INSTR(BitOr)
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(a | rhs);
+ MOTH_END_INSTR(BitOrConst)
MOTH_BEGIN_INSTR(BitXorConst)
- int lhs = VALUEPTR(instr.lhs)->toInt32();
- STOREVALUE(instr.result, QV4::Encode((int)(lhs ^ instr.rhs)));
- MOTH_END_INSTR(BitXor)
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(a ^ rhs);
+ MOTH_END_INSTR(BitXorConst)
+
+ MOTH_BEGIN_INSTR(UShrConst)
+ acc = Encode(ACC.toUInt32() >> uint(rhs));
+ MOTH_END_INSTR(UShrConst)
MOTH_BEGIN_INSTR(ShrConst)
- STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() >> instr.rhs)));
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(a >> rhs);
MOTH_END_INSTR(ShrConst)
MOTH_BEGIN_INSTR(ShlConst)
- STOREVALUE(instr.result, QV4::Encode((int)(VALUEPTR(instr.lhs)->toInt32() << instr.rhs)));
+ VALUE_TO_INT(a, ACC);
+ acc = Encode(a << rhs);
MOTH_END_INSTR(ShlConst)
- MOTH_BEGIN_INSTR(Mul)
- STOREVALUE(instr.result, Runtime::method_mul(VALUE(instr.lhs), VALUE(instr.rhs)));
- MOTH_END_INSTR(Mul)
-
- MOTH_BEGIN_INSTR(Sub)
- STOREVALUE(instr.result, Runtime::method_sub(VALUE(instr.lhs), VALUE(instr.rhs)));
- MOTH_END_INSTR(Sub)
-
- MOTH_BEGIN_INSTR(BinopContext)
- QV4::Runtime::BinaryOperationContext op = *reinterpret_cast<QV4::Runtime::BinaryOperationContext *>(reinterpret_cast<char *>(&engine->runtime.runtimeMethods[instr.alu]));
- STOREVALUE(instr.result, op(engine, VALUE(instr.lhs), VALUE(instr.rhs)));
- MOTH_END_INSTR(BinopContext)
-
MOTH_BEGIN_INSTR(Ret)
-// TRACE(Ret, "returning value %s", result.toString(context)->toQString().toUtf8().constData());
- return VALUE(instr.result).asReturnedValue();
+ goto functionExit;
MOTH_END_INSTR(Ret)
#ifndef QT_NO_QML_DEBUGGER
MOTH_BEGIN_INSTR(Debug)
- engine->current->lineNumber = instr.lineNumber;
- QV4::Debugging::Debugger *debugger = engine->debugger();
- if (debugger && debugger->pauseAtNextOpportunity())
- debugger->maybeBreakAtInstruction();
- if (qt_v4IsDebugging)
- qt_v4CheckForBreak(engine->currentContext);
+ STORE_IP();
+ debug_slowPath(engine);
MOTH_END_INSTR(Debug)
-
- MOTH_BEGIN_INSTR(Line)
- engine->current->lineNumber = instr.lineNumber;
- if (qt_v4IsDebugging)
- qt_v4CheckForBreak(engine->currentContext);
- MOTH_END_INSTR(Line)
#endif // QT_NO_QML_DEBUGGER
- MOTH_BEGIN_INSTR(LoadThis)
- VALUE(instr.result) = engine->currentContext->thisObject();
- MOTH_END_INSTR(LoadThis)
-
MOTH_BEGIN_INSTR(LoadQmlContext)
- VALUE(instr.result) = Runtime::method_getQmlContext(static_cast<QV4::NoThrowEngine*>(engine));
+ STACK_VALUE(result) = Runtime::method_loadQmlContext(static_cast<QV4::NoThrowEngine*>(engine));
MOTH_END_INSTR(LoadQmlContext)
MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
- VALUE(instr.result) = Runtime::method_getQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine));
+ STACK_VALUE(result) = Runtime::method_loadQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine));
MOTH_END_INSTR(LoadQmlImportedScripts)
MOTH_BEGIN_INSTR(LoadQmlSingleton)
- VALUE(instr.result) = Runtime::method_getQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), instr.name);
+ acc = Runtime::method_loadQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), name);
MOTH_END_INSTR(LoadQmlSingleton)
-#ifdef MOTH_THREADED_INTERPRETER
- // nothing to do
-#else
- default:
- qFatal("QQmlJS::Moth::VME: Internal error - unknown instruction %d", genericInstr->common.instructionType);
- break;
- }
-#endif
-
- Q_ASSERT(false);
catchException:
Q_ASSERT(engine->hasException);
- if (!exceptionHandler)
- return QV4::Encode::undefined();
+ if (!exceptionHandler) {
+ acc = Encode::undefined();
+ goto functionExit;
+ }
code = exceptionHandler;
}
-}
-QV4::ReturnedValue VME::exec(ExecutionEngine *engine, const uchar *code)
-{
- VME vme;
- QV4::Debugging::Debugger *debugger = engine->debugger();
- if (debugger)
- debugger->enteringFunction();
- QV4::ReturnedValue retVal = vme.run(engine, code);
- if (debugger)
- debugger->leavingFunction(retVal);
- return retVal;
+functionExit:
+ if (QV4::Debugging::Debugger *debugger = engine->debugger())
+ debugger->leavingFunction(ACC.asReturnedValue());
+ engine->currentStackFrame = frame.parent;
+ engine->jsStackTop = jsStackTop;
+
+ return acc;
}
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index 8d46207f2b..3a1e7b6637 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -65,10 +65,7 @@ namespace Moth {
class VME
{
public:
- static QV4::ReturnedValue exec(QV4::ExecutionEngine *, const uchar *);
-
-private:
- QV4::ReturnedValue run(QV4::ExecutionEngine *, const uchar *code);
+ static QV4::ReturnedValue exec(CallData *callData, QV4::Function *);
};
} // namespace Moth