diff options
Diffstat (limited to 'src/qml/qml/v8/qv8engine.cpp')
-rw-r--r-- | src/qml/qml/v8/qv8engine.cpp | 1250 |
1 files changed, 334 insertions, 916 deletions
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index e80da46fc9..51605cead7 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -41,10 +41,7 @@ #include "qv8engine_p.h" -#include "qv8contextwrapper_p.h" -#include "qv8valuetypewrapper_p.h" -#include "qv8sequencewrapper_p.h" -#include "qv8include_p.h" +#include "qv4sequenceobject_p.h" #include "qjsengine_p.h" #include <private/qqmlbuiltinfunctions_p.h> @@ -55,14 +52,31 @@ #include <private/qqmlglobal_p.h> #include <private/qqmlmemoryprofiler_p.h> #include <private/qqmlplatform_p.h> +#include <private/qjsvalue_p.h> +#include <private/qqmltypewrapper_p.h> +#include <private/qqmlcontextwrapper_p.h> +#include <private/qqmlvaluetypewrapper_p.h> +#include <private/qqmllistwrapper_p.h> -#include "qscript_impl_p.h" -#include "qv8domerrors_p.h" -#include "qv8sqlerrors_p.h" +#include "qv4domerrors_p.h" +#include "qv4sqlerrors_p.h" #include <QtCore/qjsonarray.h> #include <QtCore/qjsonobject.h> #include <QtCore/qjsonvalue.h> +#include <QtCore/qdatetime.h> + +#include <private/qv4value_p.h> +#include <private/qv4dateobject_p.h> +#include <private/qv4objectiterator_p.h> +#include <private/qv4mm_p.h> +#include <private/qv4objectproto_p.h> +#include <private/qv4globalobject_p.h> +#include <private/qv4regexpobject_p.h> +#include <private/qv4variantobject_p.h> +#include <private/qv4script_p.h> +#include <private/qv4include_p.h> +#include <private/qv4jsonobject_p.h> Q_DECLARE_METATYPE(QList<int>) @@ -71,107 +85,25 @@ Q_DECLARE_METATYPE(QList<int>) // QQmlEngine is not available QT_BEGIN_NAMESPACE -static bool ObjectComparisonCallback(v8::Local<v8::Object> lhs, v8::Local<v8::Object> rhs) -{ - if (lhs == rhs) - return true; - - if (lhs.IsEmpty() || rhs.IsEmpty()) - return false; - QV8ObjectResource *lhsr = static_cast<QV8ObjectResource*>(lhs->GetExternalResource()); - QV8ObjectResource *rhsr = static_cast<QV8ObjectResource*>(rhs->GetExternalResource()); - - if (lhsr && rhsr) { - Q_ASSERT(lhsr->engine == rhsr->engine); - QV8ObjectResource::ResourceType lhst = lhsr->resourceType(); - QV8ObjectResource::ResourceType rhst = rhsr->resourceType(); - - switch (lhst) { - case QV8ObjectResource::ValueTypeType: - // a value type might be equal to a variant or another value type - if (rhst == QV8ObjectResource::ValueTypeType) { - return lhsr->engine->valueTypeWrapper()->isEqual(lhsr, lhsr->engine->valueTypeWrapper()->toVariant(rhsr)); - } else if (rhst == QV8ObjectResource::VariantType) { - return lhsr->engine->valueTypeWrapper()->isEqual(lhsr, lhsr->engine->variantWrapper()->toVariant(rhsr)); - } - break; - case QV8ObjectResource::VariantType: - // a variant might be equal to a value type or other variant. - if (rhst == QV8ObjectResource::VariantType) { - return lhsr->engine->variantWrapper()->toVariant(lhsr) == - lhsr->engine->variantWrapper()->toVariant(rhsr); - } else if (rhst == QV8ObjectResource::ValueTypeType) { - return rhsr->engine->valueTypeWrapper()->isEqual(rhsr, rhsr->engine->variantWrapper()->toVariant(lhsr)); - } - break; - case QV8ObjectResource::SequenceType: - // a sequence might be equal to itself. - if (rhst == QV8ObjectResource::SequenceType) { - return lhsr->engine->sequenceWrapper()->isEqual(lhsr, rhsr); - } - break; - default: - break; - } - } - - return false; -} - - -QV8Engine::QV8Engine(QJSEngine* qq, ContextOwnership ownership) +QV8Engine::QV8Engine(QJSEngine* qq) : q(qq) , m_engine(0) - , m_ownsV8Context(ownership == CreateNewContext) , m_xmlHttpRequestData(0) , m_listModelData(0) - , m_platform(0) - , m_application(0) { QML_MEMORY_SCOPE_STRING("QV8Engine::QV8Engine"); qMetaTypeId<QJSValue>(); qMetaTypeId<QList<int> >(); - QByteArray v8args = qgetenv("V8ARGS"); - // change default v8 behaviour to not relocate breakpoints across lines - if (!v8args.contains("breakpoint_relocation")) - v8args.append(" --nobreakpoint_relocation"); - v8::V8::SetFlagsFromString(v8args.constData(), v8args.length()); - - ensurePerThreadIsolate(); - - v8::HandleScope handle_scope; - m_context = (ownership == CreateNewContext) ? v8::Context::New() : v8::Persistent<v8::Context>::New(v8::Context::GetCurrent()); - qPersistentRegister(m_context); - m_originalGlobalObject.init(m_context); - v8::Context::Scope context_scope(m_context); - - v8::V8::SetUserObjectComparisonCallbackFunction(ObjectComparisonCallback); - QV8GCCallback::registerGcPrologueCallback(); - m_strongReferencer = qPersistentNew(v8::Object::New()); - - m_bindingFlagKey = qPersistentNew(v8::String::New("qml::binding")); + m_v4Engine = new QV4::ExecutionEngine; + m_v4Engine->v8Engine = this; - m_stringWrapper.init(); - m_contextWrapper.init(this); - m_qobjectWrapper.init(this); - m_typeWrapper.init(this); - m_listWrapper.init(this); - m_variantWrapper.init(this); - m_valueTypeWrapper.init(this); - m_sequenceWrapper.init(this); - m_jsonWrapper.init(this); - - { - v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames")); - m_getOwnPropertyNames = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(v)); - } + QV4::QObjectWrapper::initializeBindings(m_v4Engine); } QV8Engine::~QV8Engine() { - Q_ASSERT_X(v8::Isolate::GetCurrent(), "QV8Engine::~QV8Engine()", "called after v8::Isolate has exited"); for (int ii = 0; ii < m_extensionData.count(); ++ii) delete m_extensionData[ii]; m_extensionData.clear(); @@ -181,105 +113,52 @@ QV8Engine::~QV8Engine() delete m_listModelData; m_listModelData = 0; - qPersistentDispose(m_freezeObject); - qPersistentDispose(m_getOwnPropertyNames); - - invalidateAllValues(); - - qPersistentDispose(m_strongReferencer); - - m_jsonWrapper.destroy(); - m_sequenceWrapper.destroy(); - m_valueTypeWrapper.destroy(); - m_variantWrapper.destroy(); - m_listWrapper.destroy(); - m_typeWrapper.destroy(); - m_qobjectWrapper.destroy(); - m_contextWrapper.destroy(); - m_stringWrapper.destroy(); - - qPersistentDispose(m_bindingFlagKey); - - m_originalGlobalObject.destroy(); - - if (m_ownsV8Context) - qPersistentDispose(m_context); -} - -QString QV8Engine::toStringStatic(v8::Handle<v8::Value> jsstr) -{ - return toStringStatic(jsstr->ToString()); -} - -QString QV8Engine::toStringStatic(v8::Handle<v8::String> jsstr) -{ - QString qstr; - qstr.resize(jsstr->Length()); - jsstr->Write((uint16_t*)qstr.data()); - return qstr; + delete m_v4Engine; } -QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint) +QVariant QV8Engine::toVariant(const QV4::Value &value, int typeHint) { - if (value.IsEmpty()) + if (value.isEmpty()) return QVariant(); + if (QV4::VariantObject *v = value.as<QV4::VariantObject>()) + return v->data; + if (typeHint == QVariant::Bool) - return QVariant(value->BooleanValue()); + return QVariant(value.toBoolean()); if (typeHint == QMetaType::QJsonValue) - return QVariant::fromValue(jsonValueFromJS(value)); + return QVariant::fromValue(QV4::JsonObject::toJsonValue(value)); if (typeHint == qMetaTypeId<QJSValue>()) - return QVariant::fromValue(scriptValueFromInternal(value)); - - if (value->IsObject()) { - QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource(); - if (r) { - switch (r->resourceType()) { - case QV8ObjectResource::Context2DStyleType: - case QV8ObjectResource::Context2DPixelArrayType: - case QV8ObjectResource::SignalHandlerType: - case QV8ObjectResource::IncubatorType: - case QV8ObjectResource::VisualDataItemType: - case QV8ObjectResource::ContextType: - case QV8ObjectResource::XMLHttpRequestType: - case QV8ObjectResource::DOMNodeType: - case QV8ObjectResource::SQLDatabaseType: - case QV8ObjectResource::ListModelType: - case QV8ObjectResource::Context2DType: - case QV8ObjectResource::ParticleDataType: - case QV8ObjectResource::LocaleDataType: - case QV8ObjectResource::ChangeSetArrayType: - return QVariant(); - case QV8ObjectResource::TypeType: - return m_typeWrapper.toVariant(r); - case QV8ObjectResource::QObjectType: - return qVariantFromValue<QObject *>(m_qobjectWrapper.toQObject(r)); - case QV8ObjectResource::ListType: - return m_listWrapper.toVariant(r); - case QV8ObjectResource::VariantType: - return m_variantWrapper.toVariant(r); - case QV8ObjectResource::ValueTypeType: - return m_valueTypeWrapper.toVariant(r); - case QV8ObjectResource::SequenceType: - return m_sequenceWrapper.toVariant(r); - } - } else if (typeHint == QMetaType::QJsonObject - && !value->IsArray() && !value->IsFunction()) { - return QVariant::fromValue(jsonObjectFromJS(value)); - } - } - - if (value->IsArray()) { - v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value); + return QVariant::fromValue(QJSValue(new QJSValuePrivate(m_v4Engine, value))); + + if (QV4::Object *object = value.asObject()) { + if (typeHint == QMetaType::QJsonObject + && !value.asArrayObject() && !value.asFunctionObject()) { + return QVariant::fromValue(QV4::JsonObject::toJsonObject(object)); + } else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) { + return qVariantFromValue<QObject *>(wrapper->object()); + } else if (QV4::QmlContextWrapper *wrapper = object->as<QV4::QmlContextWrapper>()) { + return QVariant(); + } else if (QV4::QmlTypeWrapper *w = object->as<QV4::QmlTypeWrapper>()) { + return w->toVariant(); + } else if (QV4::QmlValueTypeWrapper *v = object->as<QV4::QmlValueTypeWrapper>()) { + return v->toVariant(); + } else if (QV4::QmlListWrapper *l = object->as<QV4::QmlListWrapper>()) { + return l->toVariant(); + } else if (object->isListType()) + return QV4::SequencePrototype::toVariant(object); + } + + if (QV4::ArrayObject *a = value.asArrayObject()) { if (typeHint == qMetaTypeId<QList<QObject *> >()) { QList<QObject *> list; - uint32_t length = array->Length(); + uint32_t length = a->arrayLength(); for (uint32_t ii = 0; ii < length; ++ii) { - v8::Local<v8::Value> arrayItem = array->Get(ii); - if (arrayItem->IsObject()) { - list << toQObject(arrayItem->ToObject()); + QV4::Value arrayItem = a->getIndexed(ii); + if (QV4::QObjectWrapper *qobjectWrapper = arrayItem.as<QV4::QObjectWrapper>()) { + list << qobjectWrapper->object(); } else { list << 0; } @@ -287,11 +166,11 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint) return qVariantFromValue<QList<QObject*> >(list); } else if (typeHint == QMetaType::QJsonArray) { - return QVariant::fromValue(jsonArrayFromJS(value)); + return QVariant::fromValue(QV4::JsonObject::toJsonArray(a)); } bool succeeded = false; - QVariant retn = m_sequenceWrapper.toVariant(array, typeHint, &succeeded); + QVariant retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded); if (succeeded) return retn; } @@ -299,36 +178,44 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint) return toBasicVariant(value); } -static v8::Handle<v8::Array> arrayFromStringList(QV8Engine *engine, const QStringList &list) +static QV4::Value arrayFromStringList(QV8Engine *engine, const QStringList &list) { - v8::Context::Scope scope(engine->context()); - v8::Local<v8::Array> result = v8::Array::New(list.count()); - for (int ii = 0; ii < list.count(); ++ii) - result->Set(ii, engine->toString(list.at(ii))); - return result; + QV4::ExecutionEngine *e = QV8Engine::getV4(engine); + QV4::ArrayObject *a = e->newArrayObject(); + int len = list.count(); + a->arrayReserve(len); + for (int ii = 0; ii < len; ++ii) + a->arrayData[ii].value = QV4::Value::fromString(e->newString(list.at(ii))); + a->arrayDataLen = len; + a->setArrayLengthUnchecked(len); + return QV4::Value::fromObject(a); } -static v8::Handle<v8::Array> arrayFromVariantList(QV8Engine *engine, const QVariantList &list) +static QV4::Value arrayFromVariantList(QV8Engine *engine, const QVariantList &list) { - v8::Context::Scope scope(engine->context()); - v8::Local<v8::Array> result = v8::Array::New(list.count()); - for (int ii = 0; ii < list.count(); ++ii) - result->Set(ii, engine->fromVariant(list.at(ii))); - return result; + QV4::ExecutionEngine *e = QV8Engine::getV4(engine); + QV4::ArrayObject *a = e->newArrayObject(); + int len = list.count(); + a->arrayReserve(len); + for (int ii = 0; ii < len; ++ii) + a->arrayData[ii].value = engine->fromVariant(list.at(ii)); + a->arrayDataLen = len; + a->setArrayLengthUnchecked(len); + return QV4::Value::fromObject(a); } -static v8::Handle<v8::Object> objectFromVariantMap(QV8Engine *engine, const QVariantMap &map) +static QV4::Value objectFromVariantMap(QV8Engine *engine, const QVariantMap &map) { - v8::Context::Scope scope(engine->context()); - v8::Local<v8::Object> object = v8::Object::New(); + QV4::ExecutionEngine *e = QV8Engine::getV4(engine); + QV4::Object *o = e->newObject(); for (QVariantMap::ConstIterator iter = map.begin(); iter != map.end(); ++iter) - object->Set(engine->toString(iter.key()), engine->fromVariant(iter.value())); - return object; + o->put(e->newString(iter.key()), engine->fromVariant(iter.value())); + return QV4::Value::fromObject(o); } Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax); -v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant) +QV4::Value QV8Engine::fromVariant(const QVariant &variant) { int type = variant.userType(); const void *ptr = variant.constData(); @@ -337,47 +224,47 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant) switch (QMetaType::Type(type)) { case QMetaType::UnknownType: case QMetaType::Void: - return v8::Undefined(); + return QV4::Value::undefinedValue(); case QMetaType::Bool: - return v8::Boolean::New(*reinterpret_cast<const bool*>(ptr)); + return QV4::Value::fromBoolean(*reinterpret_cast<const bool*>(ptr)); case QMetaType::Int: - return v8::Integer::New(*reinterpret_cast<const int*>(ptr)); + return QV4::Value::fromInt32(*reinterpret_cast<const int*>(ptr)); case QMetaType::UInt: - return v8::Integer::NewFromUnsigned(*reinterpret_cast<const uint*>(ptr)); + return QV4::Value::fromUInt32(*reinterpret_cast<const uint*>(ptr)); case QMetaType::LongLong: - return v8::Number::New(*reinterpret_cast<const qlonglong*>(ptr)); + return QV4::Value::fromDouble(*reinterpret_cast<const qlonglong*>(ptr)); case QMetaType::ULongLong: - return v8::Number::New(*reinterpret_cast<const qulonglong*>(ptr)); + return QV4::Value::fromDouble(*reinterpret_cast<const qulonglong*>(ptr)); case QMetaType::Double: - return v8::Number::New(*reinterpret_cast<const double*>(ptr)); + return QV4::Value::fromDouble(*reinterpret_cast<const double*>(ptr)); case QMetaType::QString: - return m_stringWrapper.toString(*reinterpret_cast<const QString*>(ptr)); + return QV4::Value::fromString(m_v4Engine->current, *reinterpret_cast<const QString*>(ptr)); case QMetaType::Float: - return v8::Number::New(*reinterpret_cast<const float*>(ptr)); + return QV4::Value::fromDouble(*reinterpret_cast<const float*>(ptr)); case QMetaType::Short: - return v8::Integer::New(*reinterpret_cast<const short*>(ptr)); + return QV4::Value::fromInt32(*reinterpret_cast<const short*>(ptr)); case QMetaType::UShort: - return v8::Integer::NewFromUnsigned(*reinterpret_cast<const unsigned short*>(ptr)); + return QV4::Value::fromUInt32(*reinterpret_cast<const unsigned short*>(ptr)); case QMetaType::Char: - return v8::Integer::New(*reinterpret_cast<const char*>(ptr)); + return QV4::Value::fromInt32(*reinterpret_cast<const char*>(ptr)); case QMetaType::UChar: - return v8::Integer::NewFromUnsigned(*reinterpret_cast<const unsigned char*>(ptr)); + return QV4::Value::fromUInt32(*reinterpret_cast<const unsigned char*>(ptr)); case QMetaType::QChar: - return v8::Integer::New((*reinterpret_cast<const QChar*>(ptr)).unicode()); + return QV4::Value::fromInt32((*reinterpret_cast<const QChar*>(ptr)).unicode()); case QMetaType::QDateTime: - return v8::Date::New(qtDateTimeToJsDate(*reinterpret_cast<const QDateTime *>(ptr))); + return QV4::Value::fromObject(m_v4Engine->newDateObject(*reinterpret_cast<const QDateTime *>(ptr))); case QMetaType::QDate: - return v8::Date::New(qtDateTimeToJsDate(QDateTime(*reinterpret_cast<const QDate *>(ptr)))); + return QV4::Value::fromObject(m_v4Engine->newDateObject(QDateTime(*reinterpret_cast<const QDate *>(ptr)))); case QMetaType::QTime: - return v8::Date::New(qtDateTimeToJsDate(QDateTime(QDate(1970,1,1), *reinterpret_cast<const QTime *>(ptr)))); + return QV4::Value::fromObject(m_v4Engine->newDateObject(QDateTime(QDate(1970,1,1), *reinterpret_cast<const QTime *>(ptr)))); case QMetaType::QRegExp: - return QJSConverter::toRegExp(*reinterpret_cast<const QRegExp *>(ptr)); + return QV4::Value::fromObject(m_v4Engine->newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr))); case QMetaType::QObjectStar: - return newQObject(*reinterpret_cast<QObject* const *>(ptr)); + return QV4::QObjectWrapper::wrap(m_v4Engine, *reinterpret_cast<QObject* const *>(ptr)); case QMetaType::QStringList: { bool succeeded = false; - v8::Handle<v8::Value> retn = m_sequenceWrapper.fromVariant(variant, &succeeded); + QV4::Value retn = QV4::SequencePrototype::fromVariant(m_v4Engine, variant, &succeeded); if (succeeded) return retn; return arrayFromStringList(this, *reinterpret_cast<const QStringList *>(ptr)); @@ -387,97 +274,63 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant) case QMetaType::QVariantMap: return objectFromVariantMap(this, *reinterpret_cast<const QVariantMap *>(ptr)); case QMetaType::QJsonValue: - return jsonValueToJS(*reinterpret_cast<const QJsonValue *>(ptr)); + return QV4::JsonObject::fromJsonValue(m_v4Engine, *reinterpret_cast<const QJsonValue *>(ptr)); case QMetaType::QJsonObject: - return jsonObjectToJS(*reinterpret_cast<const QJsonObject *>(ptr)); + return QV4::JsonObject::fromJsonObject(m_v4Engine, *reinterpret_cast<const QJsonObject *>(ptr)); case QMetaType::QJsonArray: - return jsonArrayToJS(*reinterpret_cast<const QJsonArray *>(ptr)); + return QV4::JsonObject::fromJsonArray(m_v4Engine, *reinterpret_cast<const QJsonArray *>(ptr)); default: break; } if (QQmlValueType *vt = QQmlValueTypeFactory::valueType(type)) - return m_valueTypeWrapper.newValueType(variant, vt); + return QV4::QmlValueTypeWrapper::create(this, variant, vt); } else { if (type == qMetaTypeId<QQmlListReference>()) { typedef QQmlListReferencePrivate QDLRP; QDLRP *p = QDLRP::get((QQmlListReference*)ptr); if (p->object) { - return m_listWrapper.newList(p->property, p->propertyType); + return QV4::QmlListWrapper::create(this, p->property, p->propertyType); } else { - return v8::Null(); + return QV4::Value::nullValue(); } } else if (type == qMetaTypeId<QJSValue>()) { const QJSValue *value = reinterpret_cast<const QJSValue *>(ptr); QJSValuePrivate *valuep = QJSValuePrivate::get(*value); - if (valuep->assignEngine(this)) - return v8::Local<v8::Value>::New(*valuep); + return valuep->getValue(m_v4Engine); } else if (type == qMetaTypeId<QList<QObject *> >()) { // XXX Can this be made more by using Array as a prototype and implementing // directly against QList<QObject*>? const QList<QObject *> &list = *(QList<QObject *>*)ptr; - v8::Local<v8::Array> array = v8::Array::New(list.count()); + QV4::ArrayObject *a = m_v4Engine->newArrayObject(); + a->arrayReserve(list.count()); for (int ii = 0; ii < list.count(); ++ii) - array->Set(ii, newQObject(list.at(ii))); - return array; + a->arrayData[ii].value = QV4::QObjectWrapper::wrap(m_v4Engine, list.at(ii)); + a->arrayDataLen = list.count(); + a->setArrayLengthUnchecked(list.count()); + return QV4::Value::fromObject(a); } bool objOk; QObject *obj = QQmlMetaType::toQObject(variant, &objOk); if (objOk) - return newQObject(obj); + return QV4::QObjectWrapper::wrap(m_v4Engine, obj); bool succeeded = false; - v8::Handle<v8::Value> retn = m_sequenceWrapper.fromVariant(variant, &succeeded); + QV4::Value retn = QV4::SequencePrototype::fromVariant(m_v4Engine, variant, &succeeded); if (succeeded) return retn; if (QQmlValueType *vt = QQmlValueTypeFactory::valueType(type)) - return m_valueTypeWrapper.newValueType(variant, vt); + return QV4::QmlValueTypeWrapper::create(this, variant, vt); } // XXX TODO: To be compatible, we still need to handle: // + QObjectList // + QList<int> - return m_variantWrapper.newVariant(variant); -} - -// A handle scope and context must be entered -v8::Local<v8::Script> QV8Engine::qmlModeCompile(const QString &source, - const QString &fileName, - quint16 lineNumber) -{ - v8::Local<v8::String> v8source = m_stringWrapper.toString(source); - v8::Local<v8::String> v8fileName = m_stringWrapper.toString(fileName); - - v8::ScriptOrigin origin(v8fileName, v8::Integer::New(lineNumber - 1)); - - v8::Local<v8::Script> script = v8::Script::Compile(v8source, &origin, 0, v8::Handle<v8::String>(), - v8::Script::QmlMode); - - return script; -} - -// A handle scope and context must be entered. -// source can be either ascii or utf8. -v8::Local<v8::Script> QV8Engine::qmlModeCompile(const char *source, int sourceLength, - const QString &fileName, - quint16 lineNumber) -{ - if (sourceLength == -1) - sourceLength = int(strlen(source)); - - v8::Local<v8::String> v8source = v8::String::New(source, sourceLength); - v8::Local<v8::String> v8fileName = m_stringWrapper.toString(fileName); - - v8::ScriptOrigin origin(v8fileName, v8::Integer::New(lineNumber - 1)); - - v8::Local<v8::Script> script = v8::Script::Compile(v8source, &origin, 0, v8::Handle<v8::String>(), - v8::Script::QmlMode); - - return script; + return QV4::Value::fromObject(m_v4Engine->newVariantObject(variant)); } QNetworkAccessManager *QV8Engine::networkAccessManager() @@ -490,22 +343,9 @@ const QStringHash<bool> &QV8Engine::illegalNames() const return m_illegalNames; } -// Requires a handle scope -v8::Local<v8::Array> QV8Engine::getOwnPropertyNames(v8::Handle<v8::Object> o) -{ - // FIXME Newer v8 have API for this function - v8::TryCatch tc; - v8::Handle<v8::Value> args[] = { o }; - v8::Local<v8::Value> r = m_getOwnPropertyNames->Call(global(), 1, args); - if (tc.HasCaught()) - return v8::Array::New(); - else - return v8::Local<v8::Array>::Cast(r); -} - QQmlContextData *QV8Engine::callingContext() { - return m_contextWrapper.callingContext(); + return QV4::QmlContextWrapper::callingContext(m_v4Engine); } // Converts a JS value to a QVariant. @@ -517,178 +357,58 @@ QQmlContextData *QV8Engine::callingContext() // Date -> QVariant(QDateTime) // RegExp -> QVariant(QRegExp) // [Any other object] -> QVariantMap(...) -QVariant QV8Engine::toBasicVariant(v8::Handle<v8::Value> value) +QVariant QV8Engine::toBasicVariant(const QV4::Value &value) { - if (value->IsNull() || value->IsUndefined()) + if (value.isNull() || value.isUndefined()) return QVariant(); - if (value->IsBoolean()) - return value->ToBoolean()->Value(); - if (value->IsInt32()) - return value->ToInt32()->Value(); - if (value->IsNumber()) - return value->ToNumber()->Value(); - if (value->IsString()) - return m_stringWrapper.toString(value->ToString()); - if (value->IsDate()) - return qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(value)->NumberValue()); + if (value.isBoolean()) + return value.booleanValue(); + if (value.isInteger()) + return value.integerValue(); + if (value.isNumber()) + return value.asDouble(); + if (value.isString()) + return value.stringValue()->toQString(); + if (QV4::DateObject *d = value.asDateObject()) + return d->toQDateTime(); // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)! - Q_ASSERT(value->IsObject()); + Q_ASSERT(value.isObject()); - if (value->IsRegExp()) { - v8::Context::Scope scope(context()); - return QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value)); - } - if (value->IsArray()) { - v8::Context::Scope scope(context()); + if (QV4::RegExpObject *re = value.as<QV4::RegExpObject>()) + return re->toQRegExp(); + if (QV4::ArrayObject *a = value.asArrayObject()) { QVariantList rv; - v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value); - int length = array->Length(); + int length = a->arrayLength(); for (int ii = 0; ii < length; ++ii) - rv << toVariant(array->Get(ii), -1); + rv << toVariant(a->getIndexed(ii), -1); return rv; } - if (!value->IsFunction()) { - v8::Context::Scope scope(context()); - v8::Handle<v8::Object> object = value->ToObject(); - return variantMapFromJS(object); - } + if (!value.asFunctionObject()) + return variantMapFromJS(value.asObject()); return QVariant(); } -struct StaticQtMetaObject : public QObject +void QV8Engine::initializeGlobal() { - static const QMetaObject *get() - { return &staticQtMetaObject; } -}; + QV4::GlobalExtensions::init(m_engine, m_v4Engine->globalObject); -void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global) -{ - using namespace QQmlBuiltinFunctions; - - v8::Local<v8::Object> console = v8::Object::New(); - v8::Local<v8::Function> consoleLogFn = V8FUNCTION(consoleLog, this); - - console->Set(v8::String::New("debug"), consoleLogFn); - console->Set(v8::String::New("log"), consoleLogFn); - console->Set(v8::String::New("info"), consoleLogFn); - console->Set(v8::String::New("warn"), V8FUNCTION(consoleWarn, this)); - console->Set(v8::String::New("error"), V8FUNCTION(consoleError, this)); - console->Set(v8::String::New("assert"), V8FUNCTION(consoleAssert, this)); - - console->Set(v8::String::New("count"), V8FUNCTION(consoleCount, this)); - console->Set(v8::String::New("profile"), V8FUNCTION(consoleProfile, this)); - console->Set(v8::String::New("profileEnd"), V8FUNCTION(consoleProfileEnd, this)); - console->Set(v8::String::New("time"), V8FUNCTION(consoleTime, this)); - console->Set(v8::String::New("timeEnd"), V8FUNCTION(consoleTimeEnd, this)); - console->Set(v8::String::New("trace"), V8FUNCTION(consoleTrace, this)); - console->Set(v8::String::New("exception"), V8FUNCTION(consoleException, this)); - - v8::Local<v8::Object> qt = v8::Object::New(); - - // Set all the enums from the "Qt" namespace - const QMetaObject *qtMetaObject = StaticQtMetaObject::get(); - for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) { - QMetaEnum enumerator = qtMetaObject->enumerator(ii); - for (int jj = 0; jj < enumerator.keyCount(); ++jj) { - qt->Set(v8::String::New(enumerator.key(jj)), v8::Integer::New(enumerator.value(jj))); - } - } - qt->Set(v8::String::New("Asynchronous"), v8::Integer::New(0)); - qt->Set(v8::String::New("Synchronous"), v8::Integer::New(1)); - - qt->Set(v8::String::New("include"), V8FUNCTION(QV8Include::include, this)); - qt->Set(v8::String::New("isQtObject"), V8FUNCTION(isQtObject, this)); - qt->Set(v8::String::New("rgba"), V8FUNCTION(rgba, this)); - qt->Set(v8::String::New("hsla"), V8FUNCTION(hsla, this)); - qt->Set(v8::String::New("colorEqual"), V8FUNCTION(colorEqual, this)); - qt->Set(v8::String::New("font"), V8FUNCTION(font, this)); - qt->Set(v8::String::New("rect"), V8FUNCTION(rect, this)); - qt->Set(v8::String::New("point"), V8FUNCTION(point, this)); - qt->Set(v8::String::New("size"), V8FUNCTION(size, this)); - - qt->Set(v8::String::New("vector2d"), V8FUNCTION(vector2d, this)); - qt->Set(v8::String::New("vector3d"), V8FUNCTION(vector3d, this)); - qt->Set(v8::String::New("vector4d"), V8FUNCTION(vector4d, this)); - qt->Set(v8::String::New("quaternion"), V8FUNCTION(quaternion, this)); - qt->Set(v8::String::New("matrix4x4"), V8FUNCTION(matrix4x4, this)); - - qt->Set(v8::String::New("formatDate"), V8FUNCTION(formatDate, this)); - qt->Set(v8::String::New("formatTime"), V8FUNCTION(formatTime, this)); - qt->Set(v8::String::New("formatDateTime"), V8FUNCTION(formatDateTime, this)); - - qt->Set(v8::String::New("openUrlExternally"), V8FUNCTION(openUrlExternally, this)); - qt->Set(v8::String::New("fontFamilies"), V8FUNCTION(fontFamilies, this)); - qt->Set(v8::String::New("md5"), V8FUNCTION(md5, this)); - qt->Set(v8::String::New("btoa"), V8FUNCTION(btoa, this)); - qt->Set(v8::String::New("atob"), V8FUNCTION(atob, this)); - qt->Set(v8::String::New("resolvedUrl"), V8FUNCTION(resolvedUrl, this)); - qt->Set(v8::String::New("locale"), V8FUNCTION(locale, this)); - qt->Set(v8::String::New("binding"), V8FUNCTION(binding, this)); - - if (m_engine) { - qt->SetAccessor(v8::String::New("platform"), getPlatform, 0, v8::External::New(this)); - qt->SetAccessor(v8::String::New("application"), getApplication, 0, v8::External::New(this)); -#ifndef QT_NO_IM - qt->SetAccessor(v8::String::New("inputMethod"), getInputMethod, 0, v8::External::New(this)); -#endif - qt->Set(v8::String::New("lighter"), V8FUNCTION(lighter, this)); - qt->Set(v8::String::New("darker"), V8FUNCTION(darker, this)); - qt->Set(v8::String::New("tint"), V8FUNCTION(tint, this)); - qt->Set(v8::String::New("quit"), V8FUNCTION(quit, this)); - qt->Set(v8::String::New("createQmlObject"), V8FUNCTION(createQmlObject, this)); - qt->Set(v8::String::New("createComponent"), V8FUNCTION(createComponent, this)); - } - -#ifndef QT_NO_TRANSLATION - global->Set(v8::String::New("qsTranslate"), V8FUNCTION(qsTranslate, this)); - global->Set(v8::String::New("QT_TRANSLATE_NOOP"), V8FUNCTION(qsTranslateNoOp, this)); - global->Set(v8::String::New("qsTr"), V8FUNCTION(qsTr, this)); - global->Set(v8::String::New("QT_TR_NOOP"), V8FUNCTION(qsTrNoOp, this)); - global->Set(v8::String::New("qsTrId"), V8FUNCTION(qsTrId, this)); - global->Set(v8::String::New("QT_TRID_NOOP"), V8FUNCTION(qsTrIdNoOp, this)); -#endif + QQmlLocale::registerStringLocaleCompare(m_v4Engine); + QQmlDateExtension::registerExtension(m_v4Engine); + QQmlNumberExtension::registerExtension(m_v4Engine); - global->Set(v8::String::New("print"), consoleLogFn); - global->Set(v8::String::New("console"), console); - global->Set(v8::String::New("Qt"), qt); - global->Set(v8::String::New("gc"), V8FUNCTION(QQmlBuiltinFunctions::gc, this)); - - { -#define STRING_ARG "(function(stringArg) { "\ - " String.prototype.arg = (function() {"\ - " return stringArg.apply(this, arguments);"\ - " })"\ - "})" - - v8::Local<v8::Script> registerArg = v8::Script::New(v8::String::New(STRING_ARG), 0, 0, v8::Handle<v8::String>(), v8::Script::NativeMode); - v8::Local<v8::Value> result = registerArg->Run(); - Q_ASSERT(result->IsFunction()); - v8::Local<v8::Function> registerArgFunc = v8::Local<v8::Function>::Cast(result); - v8::Handle<v8::Value> args = V8FUNCTION(stringArg, this); - registerArgFunc->Call(v8::Local<v8::Object>::Cast(registerArgFunc), 1, &args); -#undef STRING_ARG - } - - QQmlLocale::registerStringLocaleCompare(this); - QQmlDateExtension::registerExtension(this); - QQmlNumberExtension::registerExtension(this); - - qt_add_domexceptions(this); + qt_add_domexceptions(m_v4Engine); m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this); - qt_add_sqlexceptions(this); + qt_add_sqlexceptions(m_v4Engine); { - v8::Handle<v8::Value> args[] = { global }; - v8::Local<v8::Value> names = m_getOwnPropertyNames->Call(global, 1, args); - v8::Local<v8::Array> namesArray = v8::Local<v8::Array>::Cast(names); - for (quint32 ii = 0; ii < namesArray->Length(); ++ii) - m_illegalNames.insert(toString(namesArray->Get(ii)), true); + for (uint i = 0; i < m_v4Engine->globalObject->internalClass->size; ++i) + m_illegalNames.insert(m_v4Engine->globalObject->internalClass->nameMap.at(i)->toQString(), true); } { @@ -710,63 +430,24 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global) " }"\ "})" - v8::Local<v8::Script> freeze = v8::Script::New(v8::String::New(FREEZE_SOURCE)); - v8::Local<v8::Value> result = freeze->Run(); - Q_ASSERT(result->IsFunction()); - m_freezeObject = qPersistentNew(v8::Local<v8::Function>::Cast(result)); + QV4::Value result = QV4::Script::evaluate(m_v4Engine, QString::fromUtf8(FREEZE_SOURCE), 0); + Q_ASSERT(result.asFunctionObject()); + m_freezeObject = result; #undef FREEZE_SOURCE } } -void QV8Engine::freezeObject(v8::Handle<v8::Value> value) +void QV8Engine::freezeObject(const QV4::Value &value) { - v8::Handle<v8::Value> args[] = { value }; - m_freezeObject->Call(global(), 1, args); + QV4::Value args = value; + m_freezeObject.value().asFunctionObject()->call(QV4::Value::fromObject(m_v4Engine->globalObject), &args, 1); } void QV8Engine::gc() { - v8::V8::LowMemoryNotification(); - while (!v8::V8::IdleNotification()) {} -} - -#ifdef QML_GLOBAL_HANDLE_DEBUGGING -#include <QtCore/qthreadstorage.h> -static QThreadStorage<QSet<void *> *> QV8Engine_activeHandles; - -void QV8Engine::registerHandle(void *handle) -{ - if (!handle) { - qWarning("Attempting to register a null handle"); - return; - } - - if (!QV8Engine_activeHandles.hasLocalData()) - QV8Engine_activeHandles.setLocalData(new QSet<void *>); - - if (QV8Engine_activeHandles.localData()->contains(handle)) { - qFatal("Handle %p already alive", handle); - } else { - QV8Engine_activeHandles.localData()->insert(handle); - } + m_v4Engine->memoryManager->runGC(); } -void QV8Engine::releaseHandle(void *handle) -{ - if (!handle) - return; - - if (!QV8Engine_activeHandles.hasLocalData()) - QV8Engine_activeHandles.setLocalData(new QSet<void *>); - - if (QV8Engine_activeHandles.localData()->contains(handle)) { - QV8Engine_activeHandles.localData()->remove(handle); - } else { - qFatal("Handle %p already dead", handle); - } -} -#endif - struct QV8EngineRegistrationData { QV8EngineRegistrationData() : extensionCount(0) {} @@ -797,115 +478,10 @@ void QV8Engine::setExtensionData(int index, Deletable *data) m_extensionData[index] = data; } -double QV8Engine::qtDateTimeToJsDate(const QDateTime &dt) -{ - if (!dt.isValid()) { - return qSNaN(); - } - - return dt.toMSecsSinceEpoch(); -} - -QDateTime QV8Engine::qtDateTimeFromJsDate(double jsDate) -{ - if (qIsNaN(jsDate)) - return QDateTime(); - - return QDateTime::fromMSecsSinceEpoch(jsDate); -} - -v8::Persistent<v8::Object> *QV8Engine::findOwnerAndStrength(QObject *object, bool *shouldBeStrong) -{ - QQmlData *data = QQmlData::get(object); - if (data && data->rootObjectInCreation) { // When the object is still being created it may not show up to the GC. - *shouldBeStrong = true; - return 0; - } - - QObject *parent = object->parent(); - if (!parent) { - // if the object has JS ownership, the object's v8object owns the lifetime of the persistent value. - if (QQmlEngine::objectOwnership(object) == QQmlEngine::JavaScriptOwnership) { - *shouldBeStrong = false; - return &(QQmlData::get(object)->v8object); - } - - // no parent, and has CPP ownership - doesn't have an implicit parent. - *shouldBeStrong = true; - return 0; - } - - // if it is owned by CPP, it's root parent may still be owned by JS. - // in that case, the owner of the persistent handle is the root parent's v8object. - while (parent->parent()) - parent = parent->parent(); - - if (QQmlEngine::objectOwnership(parent) == QQmlEngine::JavaScriptOwnership) { - // root parent is owned by JS. It's v8object owns the persistent value in question. - *shouldBeStrong = false; - return &(QQmlData::get(parent)->v8object); - } else { - // root parent has CPP ownership. The persistent value should not be made weak. - *shouldBeStrong = true; - return 0; - } -} - -void QV8Engine::addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle) -{ - if (!object || handle.IsEmpty()) - return; - - bool handleShouldBeStrong = false; - v8::Persistent<v8::Object> *implicitOwner = findOwnerAndStrength(object, &handleShouldBeStrong); - if (handleShouldBeStrong) { - v8::V8::AddImplicitReferences(m_strongReferencer, &handle, 1); - } else if (!implicitOwner->IsEmpty()) { - v8::V8::AddImplicitReferences(*implicitOwner, &handle, 1); - } -} - -void QV8Engine::addRelationshipForGC(QObject *object, QObject *other) -{ - if (!object || !other) - return; - - bool handleShouldBeStrong = false; - v8::Persistent<v8::Object> *implicitOwner = findOwnerAndStrength(object, &handleShouldBeStrong); - v8::Persistent<v8::Value> handle = QQmlData::get(other, true)->v8object; - if (handle.IsEmpty()) // no JS data to keep alive. - return; - else if (handleShouldBeStrong) - v8::V8::AddImplicitReferences(m_strongReferencer, &handle, 1); - else if (!implicitOwner->IsEmpty()) - v8::V8::AddImplicitReferences(*implicitOwner, &handle, 1); -} - -static QThreadStorage<QV8Engine::ThreadData*> perThreadEngineData; - -bool QV8Engine::hasThreadData() -{ - return perThreadEngineData.hasLocalData(); -} - -QV8Engine::ThreadData *QV8Engine::threadData() -{ - Q_ASSERT(perThreadEngineData.hasLocalData()); - return perThreadEngineData.localData(); -} - -void QV8Engine::ensurePerThreadIsolate() -{ - if (!perThreadEngineData.hasLocalData()) - perThreadEngineData.setLocalData(new ThreadData); -} - void QV8Engine::initQmlGlobalObject() { - v8::HandleScope handels; - v8::Context::Scope contextScope(m_context); - initializeGlobal(m_context->Global()); - freezeObject(m_context->Global()); + initializeGlobal(); + freezeObject(QV4::Value::fromObject(m_v4Engine->globalObject)); } void QV8Engine::setEngine(QQmlEngine *engine) @@ -914,40 +490,51 @@ void QV8Engine::setEngine(QQmlEngine *engine) initQmlGlobalObject(); } -v8::Handle<v8::Value> QV8Engine::throwException(v8::Handle<v8::Value> value) +QV4::Value QV8Engine::global() { - v8::ThrowException(value); - return value; + return QV4::Value::fromObject(m_v4Engine->globalObject); } // Converts a QVariantList to JS. // The result is a new Array object with length equal to the length // of the QVariantList, and the elements being the QVariantList's // elements converted to JS, recursively. -v8::Local<v8::Array> QV8Engine::variantListToJS(const QVariantList &lst) +QV4::Value QV8Engine::variantListToJS(const QVariantList &lst) { - v8::Local<v8::Array> result = v8::Array::New(lst.size()); - for (int i = 0; i < lst.size(); ++i) - result->Set(i, variantToJS(lst.at(i))); - return result; + QV4::ArrayObject *a = m_v4Engine->newArrayObject(); + a->arrayReserve(lst.size()); + for (int i = 0; i < lst.size(); i++) + a->arrayData[i].value = variantToJS(lst.at(i)); + a->arrayDataLen = lst.size(); + a->setArrayLengthUnchecked(lst.size()); + return QV4::Value::fromObject(a); } // Converts a JS Array object to a QVariantList. // The result is a QVariantList with length equal to the length // of the JS Array, and elements being the JS Array's elements // converted to QVariants, recursively. -QVariantList QV8Engine::variantListFromJS(v8::Handle<v8::Array> jsArray, +QVariantList QV8Engine::variantListFromJS(QV4::ArrayObject *a, V8ObjectSet &visitedObjects) { QVariantList result; - if (visitedObjects.contains(jsArray)) - return result; // Avoid recursion. - v8::HandleScope handleScope; - visitedObjects.insert(jsArray); - uint32_t length = jsArray->Length(); - for (uint32_t i = 0; i < length; ++i) - result.append(variantFromJS(jsArray->Get(i), visitedObjects)); - visitedObjects.remove(jsArray); + if (!a) + return result; + + if (visitedObjects.contains(a)) + // Avoid recursion. + return result; + + visitedObjects.insert(a); + + quint32 length = a->arrayLength(); + for (quint32 i = 0; i < length; ++i) { + QV4::Value v = a->getIndexed(i); + result.append(variantFromJS(v, visitedObjects)); + } + + visitedObjects.remove(a); + return result; } @@ -955,91 +542,100 @@ QVariantList QV8Engine::variantListFromJS(v8::Handle<v8::Array> jsArray, // The result is a new Object object with property names being // the keys of the QVariantMap, and values being the values of // the QVariantMap converted to JS, recursively. -v8::Local<v8::Object> QV8Engine::variantMapToJS(const QVariantMap &vmap) +QV4::Value QV8Engine::variantMapToJS(const QVariantMap &vmap) { - v8::Local<v8::Object> result = v8::Object::New(); + QV4::Object *o = m_v4Engine->newObject(); QVariantMap::const_iterator it; - for (it = vmap.constBegin(); it != vmap.constEnd(); ++it) - result->Set(QJSConverter::toString(it.key()), variantToJS(it.value())); - return result; + for (it = vmap.constBegin(); it != vmap.constEnd(); ++it) { + QV4::Property *p = o->insertMember(m_v4Engine->newIdentifier(it.key()), QV4::Attr_Data); + p->value = variantToJS(it.value()); + } + return QV4::Value::fromObject(o); } // Converts a JS Object to a QVariantMap. // The result is a QVariantMap with keys being the property names // of the object, and values being the values of the JS object's // properties converted to QVariants, recursively. -QVariantMap QV8Engine::variantMapFromJS(v8::Handle<v8::Object> jsObject, +QVariantMap QV8Engine::variantMapFromJS(QV4::Object *o, V8ObjectSet &visitedObjects) { QVariantMap result; - v8::HandleScope handleScope; - v8::Handle<v8::Array> propertyNames = jsObject->GetPropertyNames(); - uint32_t length = propertyNames->Length(); - if (length == 0) + if (!o || o->asFunctionObject()) return result; - if (visitedObjects.contains(jsObject)) - return result; // Avoid recursion. + if (visitedObjects.contains(o)) { + // Avoid recursion. + // For compatibility with QVariant{List,Map} conversion, we return an + // empty object (and no error is thrown). + return result; + } + + visitedObjects.insert(o); + + QV4::ObjectIterator it(o, QV4::ObjectIterator::EnumerableOnly); + while (1) { + QV4::Value v; + QV4::Value name = it.nextPropertyNameAsString(&v); + if (name.isNull()) + break; - visitedObjects.insert(jsObject); - // TODO: Only object's own property names. Include non-enumerable properties. - for (uint32_t i = 0; i < length; ++i) { - v8::Handle<v8::Value> name = propertyNames->Get(i); - result.insert(QJSConverter::toString(name->ToString()), - variantFromJS(jsObject->Get(name), visitedObjects)); + QString key = name.toQString(); + result.insert(key, variantFromJS(v, visitedObjects)); } - visitedObjects.remove(jsObject); + + visitedObjects.remove(o); return result; } // Converts the meta-type defined by the given type and data to JS. // Returns the value if conversion succeeded, an empty handle otherwise. -v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data) +QV4::Value QV8Engine::metaTypeToJS(int type, const void *data) { Q_ASSERT(data != 0); - v8::Handle<v8::Value> result; + QV4::Value result; // check if it's one of the types we know switch (QMetaType::Type(type)) { case QMetaType::UnknownType: case QMetaType::Void: - return v8::Undefined(); + return QV4::Value::undefinedValue(); case QMetaType::Bool: - return v8::Boolean::New(*reinterpret_cast<const bool*>(data)); + return QV4::Value::fromBoolean(*reinterpret_cast<const bool*>(data)); case QMetaType::Int: - return v8::Int32::New(*reinterpret_cast<const int*>(data)); + return QV4::Value::fromInt32(*reinterpret_cast<const int*>(data)); case QMetaType::UInt: - return v8::Uint32::New(*reinterpret_cast<const uint*>(data)); + return QV4::Value::fromUInt32(*reinterpret_cast<const uint*>(data)); case QMetaType::LongLong: - return v8::Number::New(double(*reinterpret_cast<const qlonglong*>(data))); + return QV4::Value::fromDouble(double(*reinterpret_cast<const qlonglong*>(data))); case QMetaType::ULongLong: #if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804 #pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.") - return v8::Number::New(double((qlonglong)*reinterpret_cast<const qulonglong*>(data))); + return QV4::Value::fromDouble(double((qlonglong)*reinterpret_cast<const qulonglong*>(data))); #elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET) - return v8::Number::New(double((qlonglong)*reinterpret_cast<const qulonglong*>(data))); + return QV4::Value::fromDouble(double((qlonglong)*reinterpret_cast<const qulonglong*>(data))); #else - return v8::Number::New(double(*reinterpret_cast<const qulonglong*>(data))); + return QV4::Value::fromDouble(double(*reinterpret_cast<const qulonglong*>(data))); #endif case QMetaType::Double: - return v8::Number::New(double(*reinterpret_cast<const double*>(data))); + return QV4::Value::fromDouble(*reinterpret_cast<const double*>(data)); case QMetaType::QString: - return QJSConverter::toString(*reinterpret_cast<const QString*>(data)); + return QV4::Value::fromString(m_v4Engine->current, *reinterpret_cast<const QString*>(data)); case QMetaType::Float: - return v8::Number::New(*reinterpret_cast<const float*>(data)); + return QV4::Value::fromDouble(*reinterpret_cast<const float*>(data)); case QMetaType::Short: - return v8::Int32::New(*reinterpret_cast<const short*>(data)); + return QV4::Value::fromInt32(*reinterpret_cast<const short*>(data)); case QMetaType::UShort: - return v8::Uint32::New(*reinterpret_cast<const unsigned short*>(data)); + return QV4::Value::fromUInt32(*reinterpret_cast<const unsigned short*>(data)); case QMetaType::Char: - return v8::Int32::New(*reinterpret_cast<const char*>(data)); + return QV4::Value::fromInt32(*reinterpret_cast<const char*>(data)); case QMetaType::UChar: - return v8::Uint32::New(*reinterpret_cast<const unsigned char*>(data)); + return QV4::Value::fromUInt32(*reinterpret_cast<const unsigned char*>(data)); case QMetaType::QChar: - return v8::Uint32::New((*reinterpret_cast<const QChar*>(data)).unicode()); + return QV4::Value::fromUInt32((*reinterpret_cast<const QChar*>(data)).unicode()); case QMetaType::QStringList: - result = QJSConverter::toStringList(*reinterpret_cast<const QStringList *>(data)); + result = QV4::Value::fromObject(m_v4Engine->newArrayObject(*reinterpret_cast<const QStringList *>(data))); break; case QMetaType::QVariantList: result = variantListToJS(*reinterpret_cast<const QVariantList *>(data)); @@ -1048,39 +644,39 @@ v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data) result = variantMapToJS(*reinterpret_cast<const QVariantMap *>(data)); break; case QMetaType::QDateTime: - result = QJSConverter::toDateTime(*reinterpret_cast<const QDateTime *>(data)); + result = QV4::Value::fromObject(m_v4Engine->newDateObject(*reinterpret_cast<const QDateTime *>(data))); break; case QMetaType::QDate: - result = QJSConverter::toDateTime(QDateTime(*reinterpret_cast<const QDate *>(data))); + result = QV4::Value::fromObject(m_v4Engine->newDateObject(QDateTime(*reinterpret_cast<const QDate *>(data)))); break; case QMetaType::QRegExp: - result = QJSConverter::toRegExp(*reinterpret_cast<const QRegExp *>(data)); + result = QV4::Value::fromObject(m_v4Engine->newRegExpObject(*reinterpret_cast<const QRegExp *>(data))); break; case QMetaType::QObjectStar: - result = newQObject(*reinterpret_cast<QObject* const *>(data)); + result = QV4::QObjectWrapper::wrap(m_v4Engine, *reinterpret_cast<QObject* const *>(data)); break; case QMetaType::QVariant: result = variantToJS(*reinterpret_cast<const QVariant*>(data)); break; case QMetaType::QJsonValue: - result = jsonValueToJS(*reinterpret_cast<const QJsonValue *>(data)); + result = QV4::JsonObject::fromJsonValue(m_v4Engine, *reinterpret_cast<const QJsonValue *>(data)); break; case QMetaType::QJsonObject: - result = jsonObjectToJS(*reinterpret_cast<const QJsonObject *>(data)); + result = QV4::JsonObject::fromJsonObject(m_v4Engine, *reinterpret_cast<const QJsonObject *>(data)); break; case QMetaType::QJsonArray: - result = jsonArrayToJS(*reinterpret_cast<const QJsonArray *>(data)); + result = QV4::JsonObject::fromJsonArray(m_v4Engine, *reinterpret_cast<const QJsonArray *>(data)); break; default: if (type == qMetaTypeId<QJSValue>()) { - return QJSValuePrivate::get(*reinterpret_cast<const QJSValue*>(data))->asV8Value(this); + return QJSValuePrivate::get(*reinterpret_cast<const QJSValue*>(data))->getValue(m_v4Engine); } else { QByteArray typeName = QMetaType::typeName(type); if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(data)) { - return v8::Null(); + return QV4::Value::nullValue(); } else { // Fall back to wrapping in a QVariant. - result = newVariant(QVariant(type, data)); + result = QV4::Value::fromObject(m_v4Engine->newVariantObject(QVariant(type, data))); } } } @@ -1090,102 +686,104 @@ v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data) // 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. -bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data) { +bool QV8Engine::metaTypeFromJS(const QV4::Value &value, int type, void *data) { // check if it's one of the types we know switch (QMetaType::Type(type)) { case QMetaType::Bool: - *reinterpret_cast<bool*>(data) = value->ToBoolean()->Value(); + *reinterpret_cast<bool*>(data) = value.toBoolean(); return true; case QMetaType::Int: - *reinterpret_cast<int*>(data) = value->ToInt32()->Value(); + *reinterpret_cast<int*>(data) = value.toInt32(); return true; case QMetaType::UInt: - *reinterpret_cast<uint*>(data) = value->ToUint32()->Value(); + *reinterpret_cast<uint*>(data) = value.toUInt32(); return true; case QMetaType::LongLong: - *reinterpret_cast<qlonglong*>(data) = qlonglong(value->ToInteger()->Value()); + *reinterpret_cast<qlonglong*>(data) = qlonglong(value.toInteger()); return true; case QMetaType::ULongLong: - *reinterpret_cast<qulonglong*>(data) = qulonglong(value->ToInteger()->Value()); + *reinterpret_cast<qulonglong*>(data) = qulonglong(value.toInteger()); return true; case QMetaType::Double: - *reinterpret_cast<double*>(data) = value->ToNumber()->Value(); + *reinterpret_cast<double*>(data) = value.toNumber(); return true; case QMetaType::QString: - if (value->IsUndefined() || value->IsNull()) + if (value.isUndefined() || value.isNull()) *reinterpret_cast<QString*>(data) = QString(); else - *reinterpret_cast<QString*>(data) = QJSConverter::toString(value->ToString()); + *reinterpret_cast<QString*>(data) = value.toString(m_v4Engine->current)->toQString(); return true; case QMetaType::Float: - *reinterpret_cast<float*>(data) = value->ToNumber()->Value(); + *reinterpret_cast<float*>(data) = value.toNumber(); return true; case QMetaType::Short: - *reinterpret_cast<short*>(data) = short(value->ToInt32()->Value()); + *reinterpret_cast<short*>(data) = short(value.toInt32()); return true; case QMetaType::UShort: - *reinterpret_cast<unsigned short*>(data) = ushort(value->ToInt32()->Value()); // ### QScript::ToUInt16() + *reinterpret_cast<unsigned short*>(data) = value.toUInt16(); return true; case QMetaType::Char: - *reinterpret_cast<char*>(data) = char(value->ToInt32()->Value()); + *reinterpret_cast<char*>(data) = char(value.toInt32()); return true; case QMetaType::UChar: - *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->ToInt32()->Value()); + *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value.toInt32()); return true; case QMetaType::QChar: - if (value->IsString()) { - QString str = QJSConverter::toString(v8::Handle<v8::String>::Cast(value)); + if (value.isString()) { + QString str = value.stringValue()->toQString(); *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0); } else { - *reinterpret_cast<QChar*>(data) = QChar(ushort(value->ToInt32()->Value())); // ### QScript::ToUInt16() + *reinterpret_cast<QChar*>(data) = QChar(ushort(value.toUInt16())); } return true; case QMetaType::QDateTime: - if (value->IsDate()) { - *reinterpret_cast<QDateTime *>(data) = QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value)); + if (QV4::DateObject *d = value.asDateObject()) { + *reinterpret_cast<QDateTime *>(data) = d->toQDateTime(); return true; } break; case QMetaType::QDate: - if (value->IsDate()) { - *reinterpret_cast<QDate *>(data) = QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value)).date(); + if (QV4::DateObject *d = value.asDateObject()) { + *reinterpret_cast<QDate *>(data) = d->toQDateTime().date(); return true; } break; case QMetaType::QRegExp: - if (value->IsRegExp()) { - *reinterpret_cast<QRegExp *>(data) = QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value)); + if (QV4::RegExpObject *r = value.as<QV4::RegExpObject>()) { + *reinterpret_cast<QRegExp *>(data) = r->toQRegExp(); return true; } break; - case QMetaType::QObjectStar: - if (isQObject(value) || value->IsNull()) { + case QMetaType::QObjectStar: { + QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>(); + if (qobjectWrapper || value.isNull()) { *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(value); return true; } break; + } case QMetaType::QStringList: - if (value->IsArray()) { - *reinterpret_cast<QStringList *>(data) = QJSConverter::toStringList(v8::Handle<v8::Array>::Cast(value)); + if (QV4::ArrayObject *a = value.asArrayObject()) { + *reinterpret_cast<QStringList *>(data) = a->toQStringList(); return true; } break; case QMetaType::QVariantList: - if (value->IsArray()) { - *reinterpret_cast<QVariantList *>(data) = variantListFromJS(v8::Handle<v8::Array>::Cast(value)); + if (QV4::ArrayObject *a = value.asArrayObject()) { + *reinterpret_cast<QVariantList *>(data) = variantListFromJS(a); return true; } break; case QMetaType::QVariantMap: - if (value->IsObject()) { - *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(v8::Handle<v8::Object>::Cast(value)); + if (QV4::Object *o = value.asObject()) { + *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o); return true; } break; case QMetaType::QVariant: *reinterpret_cast<QVariant*>(data) = variantFromJS(value); return true; case QMetaType::QJsonValue: - *reinterpret_cast<QJsonValue *>(data) = jsonValueFromJS(value); + *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value); return true; case QMetaType::QJsonObject: - *reinterpret_cast<QJsonObject *>(data) = jsonObjectFromJS(value); + *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value.asObject()); return true; case QMetaType::QJsonArray: - *reinterpret_cast<QJsonArray *>(data) = jsonArrayFromJS(value); + *reinterpret_cast<QJsonArray *>(data) = QV4::JsonObject::toJsonArray(value.asArrayObject()); return true; default: ; @@ -1215,25 +813,25 @@ bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data QByteArray name = QMetaType::typeName(type); if (convertToNativeQObject(value, name, reinterpret_cast<void* *>(data))) return true; - if (isVariant(value) && name.endsWith('*')) { + if (value.as<QV4::VariantObject>() && name.endsWith('*')) { int valueType = QMetaType::type(name.left(name.size()-1)); - QVariant &var = variantValue(value); + QVariant &var = value.as<QV4::VariantObject>()->data; if (valueType == var.userType()) { // We have T t, T* is requested, so return &t. *reinterpret_cast<void* *>(data) = var.data(); return true; - } else { + } else if (QV4::Object *o = value.asObject()) { // Look in the prototype chain. - v8::Handle<v8::Value> proto = value->ToObject()->GetPrototype(); - while (proto->IsObject()) { + QV4::Object *proto = o->prototype; + while (proto) { bool canCast = false; - if (isVariant(proto)) { - canCast = (type == variantValue(proto).userType()) - || (valueType && (valueType == variantValue(proto).userType())); + if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) { + const QVariant &v = vo->data; + canCast = (type == v.userType()) || (valueType && (valueType == v.userType())); } - else if (isQObject(proto)) { + else if (proto->as<QV4::QObjectWrapper>()) { QByteArray className = name.left(name.size()-1); - if (QObject *qobject = qtObjectFromJS(proto)) + if (QObject *qobject = qtObjectFromJS(QV4::Value::fromObject(proto))) canCast = qobject->qt_metacast(className) != 0; } if (canCast) { @@ -1244,14 +842,14 @@ bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data *reinterpret_cast<void* *>(data) = var.data(); return true; } - proto = proto->ToObject()->GetPrototype(); + proto = proto->prototype; } } - } else if (value->IsNull() && name.endsWith('*')) { + } else if (value.isNull() && name.endsWith('*')) { *reinterpret_cast<void* *>(data) = 0; return true; } else if (type == qMetaTypeId<QJSValue>()) { - *reinterpret_cast<QJSValue*>(data) = QJSValuePrivate::get(new QJSValuePrivate(this, value)); + *reinterpret_cast<QJSValue*>(data) = QJSValuePrivate::get(new QJSValuePrivate(m_v4Engine, value)); return true; } @@ -1259,7 +857,7 @@ bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data } // Converts a QVariant to JS. -v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value) +QV4::Value QV8Engine::variantToJS(const QVariant &value) { return metaTypeToJS(value.userType(), value.constData()); } @@ -1274,71 +872,40 @@ v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value) // Date -> QVariant(QDateTime) // RegExp -> QVariant(QRegExp) // [Any other object] -> QVariantMap(...) -QVariant QV8Engine::variantFromJS(v8::Handle<v8::Value> value, +QVariant QV8Engine::variantFromJS(const QV4::Value &value, V8ObjectSet &visitedObjects) { - Q_ASSERT(!value.IsEmpty()); - if (value->IsUndefined()) + Q_ASSERT(!value.isEmpty()); + if (value.isUndefined()) return QVariant(); - if (value->IsNull()) + if (value.isNull()) return QVariant(QMetaType::VoidStar, 0); - if (value->IsBoolean()) - return value->ToBoolean()->Value(); - if (value->IsInt32()) - return value->ToInt32()->Value(); - if (value->IsNumber()) - return value->ToNumber()->Value(); - if (value->IsString()) - return QJSConverter::toString(value->ToString()); - Q_ASSERT(value->IsObject()); - if (value->IsArray()) - return variantListFromJS(v8::Handle<v8::Array>::Cast(value), visitedObjects); - if (value->IsDate()) - return QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value)); - if (value->IsRegExp()) - return QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value)); - if (isVariant(value)) - return variantValue(value); - if (isQObject(value)) + if (value.isBoolean()) + return value.booleanValue(); + if (value.isInteger()) + return value.integerValue(); + if (value.isNumber()) + return value.asDouble(); + if (value.isString()) + return value.stringValue()->toQString(); + Q_ASSERT(value.isObject()); + if (QV4::ArrayObject *a = value.asArrayObject()) + return variantListFromJS(a, visitedObjects); + if (QV4::DateObject *d = value.asDateObject()) + return d->toQDateTime(); + if (QV4::RegExpObject *re = value.as<QV4::RegExpObject>()) + return re->toQRegExp(); + if (QV4::VariantObject *v = value.as<QV4::VariantObject>()) + return v->data; + if (value.as<QV4::QObjectWrapper>()) return qVariantFromValue(qtObjectFromJS(value)); - if (isValueType(value)) - return toValueType(value); - return variantMapFromJS(value->ToObject(), visitedObjects); + if (QV4::QmlValueTypeWrapper *v = value.as<QV4::QmlValueTypeWrapper>()) + return v->toVariant(); + return variantMapFromJS(value.asObject(), visitedObjects); } -v8::Handle<v8::Value> QV8Engine::jsonValueToJS(const QJsonValue &value) -{ - return m_jsonWrapper.fromJsonValue(value); -} -QJsonValue QV8Engine::jsonValueFromJS(v8::Handle<v8::Value> value) -{ - return m_jsonWrapper.toJsonValue(value); -} - -v8::Local<v8::Object> QV8Engine::jsonObjectToJS(const QJsonObject &object) -{ - return m_jsonWrapper.fromJsonObject(object); -} - -QJsonObject QV8Engine::jsonObjectFromJS(v8::Handle<v8::Value> value) -{ - return m_jsonWrapper.toJsonObject(value); -} - -v8::Local<v8::Array> QV8Engine::jsonArrayToJS(const QJsonArray &array) -{ - return m_jsonWrapper.fromJsonArray(array); -} - -QJsonArray QV8Engine::jsonArrayFromJS(v8::Handle<v8::Value> value) -{ - return m_jsonWrapper.toJsonArray(value); -} - -bool QV8Engine::convertToNativeQObject(v8::Handle<v8::Value> value, - const QByteArray &targetType, - void **result) +bool QV8Engine::convertToNativeQObject(const QV4::Value &value, const QByteArray &targetType, void **result) { if (!targetType.endsWith('*')) return false; @@ -1353,73 +920,22 @@ bool QV8Engine::convertToNativeQObject(v8::Handle<v8::Value> value, return false; } -QObject *QV8Engine::qtObjectFromJS(v8::Handle<v8::Value> value) +QObject *QV8Engine::qtObjectFromJS(const QV4::Value &value) { - if (!value->IsObject()) + if (!value.isObject()) return 0; - QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource(); - if (!r) - return 0; - QV8ObjectResource::ResourceType type = r->resourceType(); - if (type == QV8ObjectResource::QObjectType) - return qobjectWrapper()->toQObject(r); - else if (type == QV8ObjectResource::VariantType) { - QVariant variant = variantWrapper()->toVariant(r); + + if (QV4::VariantObject *v = value.as<QV4::VariantObject>()) { + QVariant variant = v->data; int type = variant.userType(); if (type == QMetaType::QObjectStar) return *reinterpret_cast<QObject* const *>(variant.constData()); } - return 0; -} - - -QVariant &QV8Engine::variantValue(v8::Handle<v8::Value> value) -{ - return variantWrapper()->variantValue(value); -} - -// Creates a QVariant wrapper object. -v8::Local<v8::Object> QV8Engine::newVariant(const QVariant &value) -{ - return variantWrapper()->newVariant(value); -} - -QScriptPassPointer<QJSValuePrivate> QV8Engine::evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch) -{ - v8::HandleScope handleScope; - - if (script.IsEmpty()) { - v8::Handle<v8::Value> exception = tryCatch.Exception(); - if (exception.IsEmpty()) { - // This is possible on syntax errors like { a:12, b:21 } <- missing "(", ")" around expression. - return new QJSValuePrivate(this); - } - return new QJSValuePrivate(this, exception); - } - v8::Handle<v8::Value> result; - result = script->Run(); - if (result.IsEmpty()) { - v8::Handle<v8::Value> exception = tryCatch.Exception(); - // TODO: figure out why v8 doesn't always produce an exception value - //Q_ASSERT(!exception.IsEmpty()); - if (exception.IsEmpty()) - exception = v8::Exception::Error(v8::String::New("missing exception value")); - return new QJSValuePrivate(this, exception); - } - return new QJSValuePrivate(this, result); -} - -QJSValue QV8Engine::scriptValueFromInternal(v8::Handle<v8::Value> value) const -{ - if (value.IsEmpty()) - return QJSValuePrivate::get(new QJSValuePrivate(const_cast<QV8Engine*>(this))); - return QJSValuePrivate::get(new QJSValuePrivate(const_cast<QV8Engine*>(this), value)); -} - -QScriptPassPointer<QJSValuePrivate> QV8Engine::newArray(uint length) -{ - return new QJSValuePrivate(this, v8::Array::New(length)); + QV4::QObjectWrapper *wrapper = value.as<QV4::QObjectWrapper>(); + if (!wrapper) + return 0; + return wrapper->object(); } void QV8Engine::startTimer(const QString &timerName) @@ -1449,107 +965,9 @@ int QV8Engine::consoleCountHelper(const QString &file, quint16 line, quint16 col return number; } -v8::Handle<v8::Value> QV8Engine::getPlatform(v8::Local<v8::String>, const v8::AccessorInfo &info) -{ - QV8Engine *engine = reinterpret_cast<QV8Engine*>(v8::External::Cast(*info.Data())->Value()); - if (!engine->m_platform) { - // Only allocate a platform object once - engine->m_platform = new QQmlPlatform(engine->m_engine); - } - return engine->newQObject(engine->m_platform); -} - -v8::Handle<v8::Value> QV8Engine::getApplication(v8::Local<v8::String>, const v8::AccessorInfo &info) +QV4::Value QV8Engine::toString(const QString &string) { - QV8Engine *engine = reinterpret_cast<QV8Engine*>(v8::External::Cast(*info.Data())->Value()); - if (!engine->m_application) { - // Only allocate an application object once - engine->m_application = QQml_guiProvider()->application(engine->m_engine); - } - return engine->newQObject(engine->m_application); -} - -#ifndef QT_NO_IM -v8::Handle<v8::Value> QV8Engine::getInputMethod(v8::Local<v8::String>, const v8::AccessorInfo &info) -{ - QV8Engine *engine = reinterpret_cast<QV8Engine*>(v8::External::Cast(*info.Data())->Value()); - return engine->newQObject(QQml_guiProvider()->inputMethod(), CppOwnership); -} -#endif - -void QV8GCCallback::registerGcPrologueCallback() -{ - QV8Engine::ThreadData *td = QV8Engine::threadData(); - if (!td->gcPrologueCallbackRegistered) { - td->gcPrologueCallbackRegistered = true; - v8::V8::AddGCPrologueCallback(QV8GCCallback::garbageCollectorPrologueCallback, v8::kGCTypeMarkSweepCompact); - } -} - -QV8GCCallback::Node::Node(PrologueCallback callback) - : prologueCallback(callback) -{ -} - -QV8GCCallback::Node::~Node() -{ - node.remove(); -} - -/* - Ensure that each persistent handle is strong if it has CPP ownership - and has no implicitly JS owned object owner in its parent chain, and - weak otherwise. - - Any weak handle whose parent object is still alive will have an implicit - reference (between the parent and the handle) added, so that it will - not be collected. - - Note that this callback is registered only for kGCTypeMarkSweepCompact - collection cycles, as it is during collection cycles of that type - in which weak persistent handle callbacks are called when required. - */ -void QV8GCCallback::garbageCollectorPrologueCallback(v8::GCType, v8::GCCallbackFlags) -{ - if (!QV8Engine::hasThreadData()) - return; - - QV8Engine::ThreadData *td = QV8Engine::threadData(); - QV8GCCallback::Node *currNode = td->gcCallbackNodes.first(); - - while (currNode) { - // The client which adds itself to the list is responsible - // for maintaining the correct implicit references in the - // specified callback. - currNode->prologueCallback(currNode); - currNode = td->gcCallbackNodes.next(currNode); - } -} - -void QV8GCCallback::addGcCallbackNode(QV8GCCallback::Node *node) -{ - QV8Engine::ThreadData *td = QV8Engine::threadData(); - td->gcCallbackNodes.insert(node); -} - -QV8Engine::ThreadData::ThreadData() - : gcPrologueCallbackRegistered(false) -{ - if (!v8::Isolate::GetCurrent()) { - isolate = v8::Isolate::New(); - isolate->Enter(); - } else { - isolate = 0; - } -} - -QV8Engine::ThreadData::~ThreadData() -{ - if (isolate) { - isolate->Exit(); - isolate->Dispose(); - isolate = 0; - } + return QV4::Value::fromString(m_v4Engine->newString(string)); } QT_END_NAMESPACE |