aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-10-30 10:38:55 +0100
committerLars Knoll <lars.knoll@qt.io>2017-11-13 08:56:14 +0000
commit3daf05ec2d7dbc408e2c302cdade667ec719d847 (patch)
treea5efab7b4a0bf381da6aa9ae0e44ea50cce9ea59
parent831ddc54932d2681712ca9fa3e94484ae11d59f7 (diff)
Introduce new calling convention for builtin functions
And implement Function.apply()/call() with it. Change-Id: I028c82d5f9adfd23328d669db1adccec9de5824c Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp110
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h10
-rw-r--r--src/qml/jsruntime/qv4object.cpp21
-rw-r--r--src/qml/jsruntime/qv4object_p.h4
4 files changed, 91 insertions, 54 deletions
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 1f86672a62..56b62bcad2 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -70,6 +70,20 @@ DEFINE_OBJECT_VTABLE(FunctionObject);
Q_STATIC_ASSERT((Heap::FunctionObject::markTable & Heap::Object::markTable) == Heap::Object::markTable);
+void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
+ ReturnedValue (*code)(const QV4::FunctionObject *, const Value *thisObject, const Value *argv, int argc))
+{
+ jsCall = code;
+ jsConstruct = QV4::FunctionObject::callAsConstructor;
+
+ Object::init();
+ function = nullptr;
+ this->scope.set(scope->engine(), scope->d());
+ Scope s(scope->engine());
+ ScopedFunctionObject f(s, this);
+ f->init(name, false);
+}
+
void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto)
{
jsCall = reinterpret_cast<const ObjectVTable *>(vtable())->call;
@@ -273,70 +287,62 @@ ReturnedValue FunctionPrototype::method_toString(const BuiltinFunction *b, CallD
return Encode(v4->newString(QStringLiteral("function() { [code] }")));
}
-ReturnedValue FunctionPrototype::method_apply(const BuiltinFunction *b, CallData *callData)
+ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
ExecutionEngine *v4 = b->engine();
- callData->function = callData->thisObject;
- FunctionObject *o = callData->function.as<FunctionObject>();
- if (!o)
+ const FunctionObject *f = thisObject->as<FunctionObject>();
+ if (!f)
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()) {
+ thisObject = argc ? argv : nullptr;
+ if (argc < 2 || argv[1].isNullOrUndefined())
+ return f->call(thisObject, argv, 0);
+
+ Object *arr = argv[1].objectValue();
+ if (!arr)
return v4->throwTypeError();
- } else {
- callData->setArgc(0);
- v4->jsStackTop = callData->args;
+
+ uint len = arr->getLength();
+
+ Scope scope(v4);
+ Value *arguments = v4->jsAlloca(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(arguments, a->d()->context->args(), l*sizeof(Value));
+ for (quint32 i = l; i < len; ++i)
+ arguments[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)
+ arguments[i] = sad->data(i);
+ for (quint32 i = alen; i < len; ++i)
+ arguments[i] = Primitive::undefinedValue();
+ } else {
+ for (quint32 i = 0; i < len; ++i)
+ arguments[i] = arr->getIndexed(i);
+ }
}
- return o->call(&callData->thisObject, callData->args, callData->argc());
+ return f->call(thisObject, arguments, len);
}
-ReturnedValue FunctionPrototype::method_call(const BuiltinFunction *b, CallData *callData)
+ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
- ExecutionEngine *engine = b->engine();
- if (!callData->thisObject.isFunctionObject())
- return engine->throwTypeError();
+ if (!thisObject->isFunctionObject())
+ return b->engine()->throwTypeError();
- Q_ASSERT(engine->jsStackTop == callData->args + callData->argc());
+ const FunctionObject *f = static_cast<const FunctionObject *>(thisObject);
- 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;
+ thisObject = argc ? argv : nullptr;
+ if (argc) {
+ ++argv;
+ --argc;
}
- return static_cast<FunctionObject &>(callData->function).call(&callData->thisObject, callData->args, callData->argc());
+ return f->call(thisObject, argv, argc);
}
ReturnedValue FunctionPrototype::method_bind(const BuiltinFunction *b, CallData *callData)
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 3fd0fbeec8..86137e8e6e 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -84,6 +84,7 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
Index_ProtoConstructor = 0
};
+ void init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(const QV4::FunctionObject *, const Value *thisObject, const Value *argv, int argc));
void init(QV4::ExecutionContext *scope, QV4::String *name = 0, bool createProto = false);
void init(QV4::ExecutionContext *scope, QV4::Function *function, bool createProto = false);
void init(QV4::ExecutionContext *scope, const QString &name, bool createProto = false);
@@ -197,8 +198,8 @@ struct FunctionPrototype: FunctionObject
void init(ExecutionEngine *engine, Object *ctor);
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_apply(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_bind(const BuiltinFunction *, CallData *callData);
};
@@ -211,6 +212,11 @@ struct Q_QML_EXPORT BuiltinFunction : FunctionObject {
return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code);
}
+ static Heap::FunctionObject *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc))
+ {
+ return scope->engine()->memoryManager->allocObject<FunctionObject>(scope, name, code);
+ }
+
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/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 1859466348..bfc4eb9ce1 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -170,6 +170,27 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(const Bui
defineDefaultProperty(name, function);
}
+void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount)
+{
+ ExecutionEngine *e = engine();
+ Scope scope(e);
+ ScopedString s(scope, e->newIdentifier(name));
+ ExecutionContext *global = e->rootContext();
+ ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ defineDefaultProperty(s, function);
+}
+
+void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount)
+{
+ ExecutionEngine *e = engine();
+ Scope scope(e);
+ ExecutionContext *global = e->rootContext();
+ ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ defineDefaultProperty(name, function);
+}
+
void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const BuiltinFunction *, CallData *),
ReturnedValue (*setter)(const BuiltinFunction *, CallData *))
{
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index af68f09700..d2e7f3ff8c 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -288,8 +288,12 @@ struct Q_QML_EXPORT Object: Managed {
insertMember(name, value, Attr_Data|Attr_NotEnumerable);
}
void defineDefaultProperty(const QString &name, const Value &value);
+ // old calling convention
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);
+ // new calling convention
+ void defineDefaultProperty(const QString &name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount = 0);
+ void defineDefaultProperty(String *name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), 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 *),