aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlcomponent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlcomponent.cpp')
-rw-r--r--src/qml/qml/qqmlcomponent.cpp360
1 files changed, 174 insertions, 186 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 1fa1c2382f..382b85685a 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -59,7 +59,9 @@
#include <private/qqmljavascriptexpression_p.h>
#include <private/qv8engine_p.h>
-#include <private/qv8include_p.h>
+
+#include <private/qv4functionobject_p.h>
+#include <private/qv4script_p.h>
#include <QStack>
#include <QStringList>
@@ -68,6 +70,23 @@
#include <qqmlinfo.h>
#include "qqmlmemoryprofiler_p.h"
+#define INITIALPROPERTIES_SOURCE \
+ "(function(object, values) {"\
+ "try {"\
+ "for (var property in values) {" \
+ "try {"\
+ "var properties = property.split(\".\");"\
+ "var o = object;"\
+ "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
+ "o = o[properties[ii]];"\
+ "}"\
+ "o[properties[properties.length - 1]] = values[property];"\
+ "} catch(e) {}"\
+ "}"\
+ "} catch(e) {}"\
+ "})"
+
+
namespace {
QThreadStorage<int> creationDepth;
}
@@ -80,9 +99,7 @@ public:
QQmlComponentExtension(QV8Engine *);
virtual ~QQmlComponentExtension();
- v8::Persistent<v8::Function> incubationConstructor;
- v8::Persistent<v8::Script> initialProperties;
- v8::Persistent<v8::Function> forceCompletion;
+ QV4::PersistentValue incubationProto;
};
V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
@@ -1069,37 +1086,33 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
enginePriv->incubate(incubator, forContextData);
}
-class QV8IncubatorResource : public QV8ObjectResource,
- public QQmlIncubator
+class QmlIncubatorObject : public QV4::Object, public QQmlIncubator
{
-V8_RESOURCE_TYPE(IncubatorType)
+ Q_MANAGED
public:
- QV8IncubatorResource(QV8Engine *engine, IncubationMode = Asynchronous);
+ QmlIncubatorObject(QV8Engine *engine, IncubationMode = Asynchronous);
- static v8::Handle<v8::Value> StatusChangedGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info);
- static v8::Handle<v8::Value> StatusGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info);
- static v8::Handle<v8::Value> ObjectGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info);
- static v8::Handle<v8::Value> ForceCompletionGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info);
- static v8::Handle<v8::Value> ForceCompletion(const v8::Arguments &args);
+ static QV4::Value method_get_statusChanged(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_set_statusChanged(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_status(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_object(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_forceCompletion(QV4::SimpleCallContext *ctx);
- static void StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
- const v8::AccessorInfo& info);
+ static void destroy(Managed *that);
+ static void markObjects(Managed *that);
- void dispose();
-
- v8::Persistent<v8::Object> me;
+ QV8Engine *v8;
QQmlGuard<QObject> parent;
- v8::Persistent<v8::Value> valuemap;
- v8::Persistent<v8::Object> qmlGlobal;
+ QV4::Value valuemap;
+ QV4::Value qmlGlobal;
+ QV4::Value m_statusChanged;
protected:
virtual void statusChanged(Status);
virtual void setInitialState(QObject *);
};
+DEFINE_MANAGED_VTABLE(QmlIncubatorObject);
+
static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
{
if (parent) {
@@ -1167,29 +1180,32 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
/*!
\internal
*/
-void QQmlComponent::createObject(QQmlV8Function *args)
+void QQmlComponent::createObject(QQmlV4Function *args)
{
Q_D(QQmlComponent);
Q_ASSERT(d->engine);
Q_ASSERT(args);
QObject *parent = 0;
- v8::Local<v8::Object> valuemap;
+ QV4::Value valuemap = QV4::Value::emptyValue();
- if (args->Length() >= 1)
- parent = args->engine()->toQObject((*args)[0]);
+ if (args->length() >= 1) {
+ if (QV4::QObjectWrapper *qobjectWrapper = (*args)[0].as<QV4::QObjectWrapper>())
+ parent = qobjectWrapper->object();
+ }
- if (args->Length() >= 2) {
- v8::Local<v8::Value> v = (*args)[1];
- if (!v->IsObject() || v->IsArray()) {
+ if (args->length() >= 2) {
+ QV4::Value v = (*args)[1];
+ if (!v.asObject() || v.asArrayObject()) {
qmlInfo(this) << tr("createObject: value is not an object");
- args->returnValue(v8::Null());
+ args->setReturnValue(QV4::Value::nullValue());
return;
}
- valuemap = v8::Local<v8::Object>::Cast(v);
+ valuemap = v;
}
QV8Engine *v8engine = args->engine();
+ QV4::ExecutionEngine *v4engine = QV8Engine::getV4(v8engine);
QQmlContext *ctxt = creationContext();
if (!ctxt) ctxt = d->engine->rootContext();
@@ -1197,22 +1213,20 @@ void QQmlComponent::createObject(QQmlV8Function *args)
QObject *rv = beginCreate(ctxt);
if (!rv) {
- args->returnValue(v8::Null());
+ args->setReturnValue(QV4::Value::nullValue());
return;
}
QQmlComponent_setQmlParent(rv, parent);
- v8::Handle<v8::Value> ov = v8engine->newQObject(rv);
- Q_ASSERT(ov->IsObject());
- v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
+ QV4::Value object = QV4::QObjectWrapper::wrap(v4engine, rv);
+ Q_ASSERT(object.asObject());
- if (!valuemap.IsEmpty()) {
+ if (!valuemap.isEmpty()) {
QQmlComponentExtension *e = componentExtension(v8engine);
- // Try catch isn't needed as the function itself is loaded with try/catch
- v8::Handle<v8::Value> function = e->initialProperties->Run(args->qmlGlobal());
- v8::Handle<v8::Value> args[] = { object, valuemap };
- v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
+ QV4::Value f = QV4::Script::evaluate(QV8Engine::getV4(v8engine), QString::fromLatin1(INITIALPROPERTIES_SOURCE), args->qmlGlobal().asObject());
+ QV4::Value args[] = { object, valuemap };
+ f.asFunctionObject()->call(QV4::Value::fromObject(v4engine->globalObject), args, 2);
}
d->completeCreate();
@@ -1222,9 +1236,9 @@ void QQmlComponent::createObject(QQmlV8Function *args)
QQmlData::get(rv)->indestructible = false;
if (!rv)
- args->returnValue(v8::Null());
+ args->setReturnValue(QV4::Value::nullValue());
else
- args->returnValue(object);
+ args->setReturnValue(object);
}
/*!
@@ -1285,7 +1299,7 @@ void QQmlComponent::createObject(QQmlV8Function *args)
/*!
\internal
*/
-void QQmlComponent::incubateObject(QQmlV8Function *args)
+void QQmlComponent::incubateObject(QQmlV4Function *args)
{
Q_D(QQmlComponent);
Q_ASSERT(d->engine);
@@ -1293,26 +1307,28 @@ void QQmlComponent::incubateObject(QQmlV8Function *args)
Q_ASSERT(args);
QObject *parent = 0;
- v8::Local<v8::Object> valuemap;
+ QV4::Value valuemap = QV4::Value::emptyValue();
QQmlIncubator::IncubationMode mode = QQmlIncubator::Asynchronous;
- if (args->Length() >= 1)
- parent = args->engine()->toQObject((*args)[0]);
+ if (args->length() >= 1) {
+ if (QV4::QObjectWrapper *qobjectWrapper = (*args)[0].as<QV4::QObjectWrapper>())
+ parent = qobjectWrapper->object();
+ }
- if (args->Length() >= 2) {
- v8::Local<v8::Value> v = (*args)[1];
- if (v->IsNull()) {
- } else if (!v->IsObject() || v->IsArray()) {
+ if (args->length() >= 2) {
+ QV4::Value v = (*args)[1];
+ if (v.isNull()) {
+ } else if (!v.asObject() || v.asArrayObject()) {
qmlInfo(this) << tr("createObject: value is not an object");
- args->returnValue(v8::Null());
+ args->setReturnValue(QV4::Value::nullValue());
return;
} else {
- valuemap = v8::Local<v8::Object>::Cast(v);
+ valuemap = v;
}
}
- if (args->Length() >= 3) {
- quint32 v = (*args)[2]->Uint32Value();
+ if (args->length() >= 3) {
+ quint32 v = (*args)[2].toUInt32();
if (v == 0)
mode = QQmlIncubator::Asynchronous;
else if (v == 1)
@@ -1321,177 +1337,156 @@ void QQmlComponent::incubateObject(QQmlV8Function *args)
QQmlComponentExtension *e = componentExtension(args->engine());
- QV8IncubatorResource *r = new QV8IncubatorResource(args->engine(), mode);
- v8::Local<v8::Object> o = e->incubationConstructor->NewInstance();
- o->SetExternalResource(r);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(args->engine());
+ QmlIncubatorObject *r = new (v4->memoryManager) QmlIncubatorObject(args->engine(), mode);
+ r->prototype = e->incubationProto.value().asObject();
- if (!valuemap.IsEmpty()) {
- r->valuemap = qPersistentNew(valuemap);
- r->qmlGlobal = qPersistentNew(args->qmlGlobal());
+ if (!valuemap.isEmpty()) {
+ r->valuemap = valuemap;
+ r->qmlGlobal = args->qmlGlobal();
}
r->parent = parent;
- r->me = qPersistentNew(o);
create(*r, creationContext());
if (r->status() == QQmlIncubator::Null) {
- r->dispose();
- args->returnValue(v8::Null());
+ args->setReturnValue(QV4::Value::nullValue());
} else {
- args->returnValue(o);
+ args->setReturnValue(QV4::Value::fromObject(r));
}
}
// XXX used by QSGLoader
-void QQmlComponentPrivate::initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate)
+void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Value &qmlGlobal, const QV4::Value &valuemap, QObject *toCreate)
{
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV8Engine *v8engine = ep->v8engine();
+ QV4::ExecutionEngine *v4engine = QV8Engine::getV4(v8engine);
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(v8engine->context());
- v8::Handle<v8::Value> ov = v8engine->newQObject(toCreate);
- Q_ASSERT(ov->IsObject());
- v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
+ QV4::Value object = QV4::QObjectWrapper::wrap(v4engine, toCreate);
+ Q_ASSERT(object.asObject());
- if (!valuemap.IsEmpty()) {
+ if (!valuemap.isEmpty()) {
QQmlComponentExtension *e = componentExtension(v8engine);
- // Try catch isn't needed as the function itself is loaded with try/catch
- v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
- v8::Handle<v8::Value> args[] = { object, valuemap };
- v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
+ QV4::Value f = QV4::Script::evaluate(QV8Engine::getV4(v8engine), QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobal.asObject());
+ QV4::Value args[] = { object, valuemap };
+ f.asFunctionObject()->call(QV4::Value::fromObject(v4engine->globalObject), args, 2);
}
}
+#define V4FUNCTION(function, engine) engine->newBuiltinFunction(engine->rootContext, engine->id_undefined, function)
+
QQmlComponentExtension::QQmlComponentExtension(QV8Engine *engine)
{
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(engine->context());
-
- forceCompletion = qPersistentNew(V8FUNCTION(QV8IncubatorResource::ForceCompletion, engine));
-
- {
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetHasExternalResource(true);
- ft->InstanceTemplate()->SetInternalFieldCount(1);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("onStatusChanged"),
- QV8IncubatorResource::StatusChangedGetter,
- QV8IncubatorResource::StatusChangedSetter);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("status"),
- QV8IncubatorResource::StatusGetter);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("object"),
- QV8IncubatorResource::ObjectGetter);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("forceCompletion"),
- QV8IncubatorResource::ForceCompletionGetter);
- incubationConstructor = qPersistentNew(ft->GetFunction());
- }
-
- {
-#define INITIALPROPERTIES_SOURCE \
- "(function(object, values) {"\
- "try {"\
- "for(var property in values) {" \
- "try {"\
- "var properties = property.split(\".\");"\
- "var o = object;"\
- "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
- "o = o[properties[ii]];"\
- "}"\
- "o[properties[properties.length - 1]] = values[property];"\
- "} catch(e) {}"\
- "}"\
- "} catch(e) {}"\
- "})"
- initialProperties = qPersistentNew(engine->qmlModeCompile(QLatin1String(INITIALPROPERTIES_SOURCE)));
-#undef INITIALPROPERTIES_SOURCE
- }
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Object *proto = v4->newObject();
+ QV4::Property *s = proto->insertMember(v4->newString(QStringLiteral("onStatusChanged")),
+ QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ s->setGetter(V4FUNCTION(QmlIncubatorObject::method_get_statusChanged, v4));
+ s->setSetter(V4FUNCTION(QmlIncubatorObject::method_set_statusChanged, v4));
+ s = proto->insertMember(v4->newString(QStringLiteral("status")),
+ QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ s->setGetter(V4FUNCTION(QmlIncubatorObject::method_get_status, v4));
+ s = proto->insertMember(v4->newString(QStringLiteral("object")),
+ QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ s->setGetter(V4FUNCTION(QmlIncubatorObject::method_get_object, v4));
+ proto->defineDefaultProperty(v4, QStringLiteral("forceCompletion"), QmlIncubatorObject::method_forceCompletion);
+
+ incubationProto = QV4::Value::fromObject(proto);
}
-v8::Handle<v8::Value> QV8IncubatorResource::ObjectGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info)
+QV4::Value QmlIncubatorObject::method_get_object(QV4::SimpleCallContext *ctx)
{
- QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
- return r->engine->newQObject(r->object());
-}
+ QmlIncubatorObject *o = ctx->thisObject.as<QmlIncubatorObject>();
+ if (!o)
+ ctx->throwTypeError();
-v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletionGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info)
-{
- QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
- return componentExtension(r->engine)->forceCompletion;
+ return QV4::QObjectWrapper::wrap(ctx->engine, o->object());
}
-v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletion(const v8::Arguments &args)
+QV4::Value QmlIncubatorObject::method_forceCompletion(QV4::SimpleCallContext *ctx)
{
- QV8IncubatorResource *r = v8_resource_cast<QV8IncubatorResource>(args.This());
- if (!r)
- V8THROW_TYPE("Not an incubator object");
+ QmlIncubatorObject *o = ctx->thisObject.as<QmlIncubatorObject>();
+ if (!o)
+ ctx->throwTypeError();
- r->forceCompletion();
+ o->forceCompletion();
- return v8::Undefined();
+ return QV4::Value::undefinedValue();
}
-v8::Handle<v8::Value> QV8IncubatorResource::StatusGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info)
+QV4::Value QmlIncubatorObject::method_get_status(QV4::SimpleCallContext *ctx)
{
- QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
- return v8::Integer::NewFromUnsigned(r->status());
+ QmlIncubatorObject *o = ctx->thisObject.as<QmlIncubatorObject>();
+ if (!o)
+ ctx->throwTypeError();
+
+ return QV4::Value::fromUInt32(o->status());
}
-v8::Handle<v8::Value> QV8IncubatorResource::StatusChangedGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info)
+QV4::Value QmlIncubatorObject::method_get_statusChanged(QV4::SimpleCallContext *ctx)
{
- return info.This()->GetInternalField(0);
+ QmlIncubatorObject *o = ctx->thisObject.as<QmlIncubatorObject>();
+ if (!o)
+ ctx->throwTypeError();
+
+ return o->m_statusChanged;
}
-void QV8IncubatorResource::StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
- const v8::AccessorInfo& info)
+QV4::Value QmlIncubatorObject::method_set_statusChanged(QV4::SimpleCallContext *ctx)
{
- info.This()->SetInternalField(0, value);
+ QmlIncubatorObject *o = ctx->thisObject.as<QmlIncubatorObject>();
+ if (!o || ctx->argumentCount < 1)
+ ctx->throwTypeError();
+
+ o->m_statusChanged = ctx->arguments[0];
+ return QV4::Value::undefinedValue();
}
QQmlComponentExtension::~QQmlComponentExtension()
{
- qPersistentDispose(incubationConstructor);
- qPersistentDispose(initialProperties);
- qPersistentDispose(forceCompletion);
}
-QV8IncubatorResource::QV8IncubatorResource(QV8Engine *engine, IncubationMode m)
-: QV8ObjectResource(engine), QQmlIncubator(m)
+QmlIncubatorObject::QmlIncubatorObject(QV8Engine *engine, IncubationMode m)
+ : Object(QV8Engine::getV4(engine)), QQmlIncubator(m)
{
+ v8 = engine;
+ vtbl = &static_vtbl;
}
-void QV8IncubatorResource::setInitialState(QObject *o)
+void QmlIncubatorObject::setInitialState(QObject *o)
{
QQmlComponent_setQmlParent(o, parent);
- if (!valuemap.IsEmpty()) {
- QQmlComponentExtension *e = componentExtension(engine);
-
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(engine->context());
+ if (!valuemap.isEmpty()) {
+ QQmlComponentExtension *e = componentExtension(v8);
- v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
- v8::Handle<v8::Value> args[] = { engine->newQObject(o), valuemap };
- v8::Handle<v8::Function>::Cast(function)->Call(engine->global(), 2, args);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8);
- qPersistentDispose(valuemap);
- qPersistentDispose(qmlGlobal);
+ QV4::Value f = QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobal.asObject());
+ QV4::Value args[] = { QV4::QObjectWrapper::wrap(v4, o), valuemap };
+ f.asFunctionObject()->call(QV4::Value::fromObject(v4->globalObject), args, 2);
}
}
-void QV8IncubatorResource::dispose()
+void QmlIncubatorObject::destroy(Managed *that)
+{
+ QmlIncubatorObject *o = that->as<QmlIncubatorObject>();
+ assert(o);
+ o->~QmlIncubatorObject();
+}
+
+void QmlIncubatorObject::markObjects(QV4::Managed *that)
{
- qPersistentDispose(valuemap);
- qPersistentDispose(qmlGlobal);
- // No further status changes are forthcoming, so we no long need a self reference
- qPersistentDispose(me);
+ QmlIncubatorObject *o = that->as<QmlIncubatorObject>();
+ assert(o);
+ o->valuemap.mark();
+ o->qmlGlobal.mark();
+ o->m_statusChanged.mark();
}
-void QV8IncubatorResource::statusChanged(Status s)
+void QmlIncubatorObject::statusChanged(Status s)
{
if (s == Ready) {
Q_ASSERT(QQmlData::get(object()));
@@ -1499,29 +1494,22 @@ void QV8IncubatorResource::statusChanged(Status s)
QQmlData::get(object())->indestructible = false;
}
- if (!me.IsEmpty()) { // Will be false in synchronous mode
- v8::HandleScope scope;
- v8::Local<v8::Value> callback = me->GetInternalField(0);
-
- if (!callback.IsEmpty() && !callback->IsUndefined()) {
-
- if (callback->IsFunction()) {
- v8::Context::Scope context_scope(engine->context());
- v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
- v8::Handle<v8::Value> args[] = { v8::Integer::NewFromUnsigned(s) };
- v8::TryCatch tc;
- f->Call(me, 1, args);
- if (tc.HasCaught()) {
- QQmlError error;
- QQmlJavaScriptExpression::exceptionToError(tc.Message(), error);
- QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error);
- }
- }
+ QV4::Value callback = m_statusChanged;
+
+ if (QV4::FunctionObject *f = callback.asFunctionObject()) {
+ QV4::ExecutionContext *ctx = f->engine()->current;
+ QV4::Value args[] = { QV4::Value::fromUInt32(s) };
+ try {
+ f->call(QV4::Value::fromObject(this), args, 1);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ QQmlError error;
+ QQmlJavaScriptExpression::exceptionToError(e, error);
+ QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v8->engine()), error);
}
}
-
- if (s == Ready || s == Error)
- dispose();
}
+#undef INITIALPROPERTIES_SOURCE
+
QT_END_NAMESPACE