src/script/bridge/qscriptqobject.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
--- a/src/script/bridge/qscriptqobject.cpp	Wed Jun 23 19:07:03 2010 +0300
+++ b/src/script/bridge/qscriptqobject.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -35,6 +35,7 @@
 
 #include "Error.h"
 #include "PrototypeFunction.h"
+#include "NativeFunctionWrapper.h"
 #include "PropertyNameArray.h"
 #include "JSFunction.h"
 #include "JSString.h"
@@ -151,7 +152,8 @@
 static bool hasMethodAccess(const QMetaMethod &method, int index, const QScriptEngine::QObjectWrapOptions &opt)
 {
     return (method.access() != QMetaMethod::Private)
-        && ((index != 2) || !(opt & QScriptEngine::ExcludeDeleteLater));
+        && ((index != 2) || !(opt & QScriptEngine::ExcludeDeleteLater))
+        && (!(opt & QScriptEngine::ExcludeSlots) || (method.methodType() != QMetaMethod::Slot));
 }
 
 static bool isEnumerableMetaProperty(const QMetaProperty &prop,
@@ -163,23 +165,51 @@
         && (mo->indexOfProperty(prop.name()) == index);
 }
 
-static inline QByteArray methodName(const QMetaMethod &method)
+/*! \internal
+  Calculates the length of the name of the given \a method by looking
+  for the first '(' character.
+*/
+static inline int methodNameLength(const QMetaMethod &method)
 {
-    QByteArray signature = method.signature();
-    return signature.left(signature.indexOf('('));
+    const char *signature = method.signature();
+    const char *s = signature;
+    while (*s && (*s != '('))
+        ++s;
+    return s - signature;
+}
+
+/*! \internal
+  Makes a deep copy of the first \a nameLength characters of the given
+  method \a signature and returns the copy.
+*/
+static inline QByteArray methodName(const char *signature, int nameLength)
+{
+    return QByteArray(signature, nameLength);
 }
 
-static QVariant variantFromValue(QScriptEnginePrivate *eng,
-                                 int targetType, const QScriptValue &value)
+/*! \internal
+
+  Returns true if the name of the given \a method is the same as that
+  specified by the (signature, nameLength) pair, otherwise returns
+  false.
+*/
+static inline bool methodNameEquals(const QMetaMethod &method,
+                                    const char *signature, int nameLength)
+{
+    const char *otherSignature = method.signature();
+    return !qstrncmp(otherSignature, signature, nameLength)
+        && (otherSignature[nameLength] == '(');
+}
+
+static QVariant variantFromValue(JSC::ExecState *exec, int targetType, JSC::JSValue value)
 {
     QVariant v(targetType, (void *)0);
-    Q_ASSERT(eng);
-    if (QScriptEnginePrivate::convert(value, targetType, v.data(), eng))
+    if (QScriptEnginePrivate::convertValue(exec, value, targetType, v.data()))
         return v;
     if (uint(targetType) == QVariant::LastType)
-        return value.toVariant();
-    if (value.isVariant()) {
-        v = value.toVariant();
+        return QScriptEnginePrivate::toVariant(exec, value);
+    if (QScriptEnginePrivate::isVariant(value)) {
+        v = QScriptEnginePrivate::variantValue(value);
         if (v.canConvert(QVariant::Type(targetType))) {
             v.convert(QVariant::Type(targetType));
             return v;
@@ -312,25 +342,16 @@
     if (!maybeOverloaded())
         return QList<int>();
     QList<int> result;
-    QString name = functionName();
     const QMetaObject *meta = metaObject();
+    QMetaMethod method = meta->method(initialIndex());
+    int nameLength = methodNameLength(method);
     for (int index = mostGeneralMethod() - 1; index >= 0; --index) {
-        QString otherName = QString::fromLatin1(methodName(meta->method(index)));
-        if (otherName == name)
+        if (methodNameEquals(meta->method(index), method.signature(), nameLength))
             result.append(index);
     }
     return result;
 }
 
-QString QtFunction::functionName() const
-{
-    const QMetaObject *meta = metaObject();
-    if (!meta)
-        return QString();
-    QMetaMethod method = meta->method(initialIndex());
-    return QLatin1String(methodName(method));
-}
-
 class QScriptMetaType
 {
 public:
@@ -417,8 +438,8 @@
 public:
     inline QScriptMetaMethod()
         { }
-    inline QScriptMetaMethod(const QByteArray &name, const QVector<QScriptMetaType> &types)
-        : m_name(name), m_types(types), m_firstUnresolvedIndex(-1)
+    inline QScriptMetaMethod(const QVector<QScriptMetaType> &types)
+        : m_types(types), m_firstUnresolvedIndex(-1)
     {
         QVector<QScriptMetaType>::const_iterator it;
         for (it = m_types.constBegin(); it != m_types.constEnd(); ++it) {
@@ -431,9 +452,6 @@
     inline bool isValid() const
     { return !m_types.isEmpty(); }
 
-    QByteArray name() const
-    { return m_name; }
-
     inline QScriptMetaType returnType() const
     { return m_types.at(0); }
 
@@ -462,7 +480,6 @@
     { return m_types; }
 
 private:
-    QByteArray m_name;
     QVector<QScriptMetaType> m_types;
     int m_firstUnresolvedIndex;
 };
@@ -499,7 +516,6 @@
                                  const QMetaObject *meta, int initialIndex,
                                  bool maybeOverloaded)
 {
-    QByteArray funName;
     QScriptMetaMethod chosenMethod;
     int chosenIndex = -1;
     QVarLengthArray<QVariant, 9> args;
@@ -508,65 +524,62 @@
     QVector<int> tooFewArgs;
     QVector<int> conversionFailed;
     int index;
+    int nameLength = 0;
+    const char *initialMethodSignature = 0;
     exec->clearException();
     QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(exec);
     for (index = initialIndex; index >= 0; --index) {
         QMetaMethod method = metaMethod(meta, callType, index);
 
-        if (index == initialIndex)
-            funName = methodName(method);
-        else {
-            if (methodName(method) != funName)
+        if (index == initialIndex) {
+            initialMethodSignature = method.signature();
+            nameLength = methodNameLength(method);
+        } else {
+            if (!methodNameEquals(method, initialMethodSignature, nameLength))
                 continue;
         }
 
+        QList<QByteArray> parameterTypeNames = method.parameterTypes();
+
         QVector<QScriptMetaType> types;
+        types.resize(1 + parameterTypeNames.size());
+        QScriptMetaType *typesData = types.data();
         // resolve return type
         QByteArray returnTypeName = method.typeName();
         int rtype = QMetaType::type(returnTypeName);
         if ((rtype == 0) && !returnTypeName.isEmpty()) {
-            if (returnTypeName == "QVariant") {
-                types.append(QScriptMetaType::variant());
-            } else {
-                int enumIndex = indexOfMetaEnum(meta, returnTypeName);
-                if (enumIndex != -1)
-                    types.append(QScriptMetaType::metaEnum(enumIndex, returnTypeName));
-                else
-                    types.append(QScriptMetaType::unresolved(returnTypeName));
-            }
+            int enumIndex = indexOfMetaEnum(meta, returnTypeName);
+            if (enumIndex != -1)
+                typesData[0] = QScriptMetaType::metaEnum(enumIndex, returnTypeName);
+            else
+                typesData[0] = QScriptMetaType::unresolved(returnTypeName);
         } else {
             if (callType == QMetaMethod::Constructor)
-                types.append(QScriptMetaType::metaType(QMetaType::QObjectStar, "QObject*"));
-            else if (returnTypeName == "QVariant")
-                types.append(QScriptMetaType::variant());
+                typesData[0] = QScriptMetaType::metaType(QMetaType::QObjectStar, "QObject*");
+            else if (rtype == QMetaType::QVariant)
+                typesData[0] = QScriptMetaType::variant();
             else
-                types.append(QScriptMetaType::metaType(rtype, returnTypeName));
+                typesData[0] = QScriptMetaType::metaType(rtype, returnTypeName);
         }
 
         // resolve argument types
-        QList<QByteArray> parameterTypeNames = method.parameterTypes();
         for (int i = 0; i < parameterTypeNames.count(); ++i) {
             QByteArray argTypeName = parameterTypeNames.at(i);
             int atype = QMetaType::type(argTypeName);
             if (atype == 0) {
-                if (argTypeName == "QVariant") {
-                    types.append(QScriptMetaType::variant());
-                } else {
-                    int enumIndex = indexOfMetaEnum(meta, argTypeName);
-                    if (enumIndex != -1)
-                        types.append(QScriptMetaType::metaEnum(enumIndex, argTypeName));
-                    else
-                        types.append(QScriptMetaType::unresolved(argTypeName));
-                }
+                int enumIndex = indexOfMetaEnum(meta, argTypeName);
+                if (enumIndex != -1)
+                    typesData[1 + i] = QScriptMetaType::metaEnum(enumIndex, argTypeName);
+                else
+                    typesData[1 + i] = QScriptMetaType::unresolved(argTypeName);
+            } else if (atype == QMetaType::QVariant) {
+                typesData[1 + i] = QScriptMetaType::variant();
             } else {
-                if (argTypeName == "QVariant")
-                    types.append(QScriptMetaType::variant());
-                else
-                    types.append(QScriptMetaType::metaType(atype, argTypeName));
+                typesData[1 + i] = QScriptMetaType::metaType(atype, argTypeName);
             }
         }
 
-        QScriptMetaMethod mtd = QScriptMetaMethod(methodName(method), types);
+        QScriptMetaMethod mtd = QScriptMetaMethod(types);
 
         if (int(scriptArgs.size()) < mtd.argumentCount()) {
             tooFewArgs.append(index);
@@ -591,38 +604,38 @@
         bool converted = true;
         int matchDistance = 0;
         for (int i = 0; converted && i < mtd.argumentCount(); ++i) {
-            QScriptValue actual;
+            JSC::JSValue actual;
             if (i < (int)scriptArgs.size())
-                actual = engine->scriptValueFromJSCValue(scriptArgs.at(i));
+                actual = scriptArgs.at(i);
             else
-                actual = QScriptValue(QScriptValue::UndefinedValue);
+                actual = JSC::jsUndefined();
             QScriptMetaType argType = mtd.argumentType(i);
             int tid = -1;
             QVariant v;
             if (argType.isUnresolved()) {
                 v = QVariant(QMetaType::QObjectStar, (void *)0);
-                converted = engine->convertToNativeQObject(
-                    actual, argType.name(), reinterpret_cast<void* *>(v.data()));
+                converted = QScriptEnginePrivate::convertToNativeQObject(
+                    exec, actual, argType.name(), reinterpret_cast<void* *>(v.data()));
             } else if (argType.isVariant()) {
-                if (actual.isVariant()) {
-                    v = actual.toVariant();
+                if (QScriptEnginePrivate::isVariant(actual)) {
+                    v = QScriptEnginePrivate::variantValue(actual);
                 } else {
-                    v = actual.toVariant();
+                    v = QScriptEnginePrivate::toVariant(exec, actual);
                     converted = v.isValid() || actual.isUndefined() || actual.isNull();
                 }
             } else {
                 tid = argType.typeId();
                 v = QVariant(tid, (void *)0);
-                converted = QScriptEnginePrivate::convert(actual, tid, v.data(), engine);
+                converted = QScriptEnginePrivate::convertValue(exec, actual, tid, v.data());
                 if (exec->hadException())
                     return exec->exception();
             }
 
             if (!converted) {
-                if (actual.isVariant()) {
+                if (QScriptEnginePrivate::isVariant(actual)) {
                     if (tid == -1)
                         tid = argType.typeId();
-                    QVariant vv = actual.toVariant();
+                    QVariant vv = QScriptEnginePrivate::variantValue(actual);
                     if (vv.canConvert(QVariant::Type(tid))) {
                         v = vv;
                         converted = v.convert(QVariant::Type(tid));
@@ -649,15 +662,15 @@
                     }
                     if (m.isValid()) {
                         if (actual.isNumber()) {
-                            int ival = actual.toInt32();
+                            int ival = QScriptEnginePrivate::toInt32(exec, actual);
                             if (m.valueToKey(ival) != 0) {
                                 qVariantSetValue(v, ival);
                                 converted = true;
                                 matchDistance += 10;
                             }
                         } else {
-                            QString sval = actual.toString();
-                            int ival = m.keyToValue(sval.toLatin1());
+                            JSC::UString sval = QScriptEnginePrivate::toString(exec, actual);
+                            int ival = m.keyToValue(convertToLatin1(sval));
                             if (ival != -1) {
                                 qVariantSetValue(v, ival);
                                 converted = true;
@@ -718,7 +731,7 @@
                         matchDistance += 10;
                         break;
                     }
-                } else if (actual.isDate()) {
+                } else if (QScriptEnginePrivate::isDate(actual)) {
                     switch (tid) {
                     case QMetaType::QDateTime:
                         // perfect
@@ -733,7 +746,7 @@
                         matchDistance += 10;
                         break;
                     }
-                } else if (actual.isRegExp()) {
+                } else if (QScriptEnginePrivate::isRegExp(actual)) {
                     switch (tid) {
                     case QMetaType::QRegExp:
                         // perfect
@@ -742,14 +755,14 @@
                         matchDistance += 10;
                         break;
                     }
-                } else if (actual.isVariant()) {
+                } else if (QScriptEnginePrivate::isVariant(actual)) {
                     if (argType.isVariant()
-                        || (actual.toVariant().userType() == tid)) {
+                        || (QScriptEnginePrivate::toVariant(exec, actual).userType() == tid)) {
                         // perfect
                     } else {
                         matchDistance += 10;
                     }
-                } else if (actual.isArray()) {
+                } else if (QScriptEnginePrivate::isArray(actual)) {
                     switch (tid) {
                     case QMetaType::QStringList:
                     case QMetaType::QVariantList:
@@ -759,7 +772,7 @@
                         matchDistance += 10;
                         break;
                     }
-                } else if (actual.isQObject()) {
+                } else if (QScriptEnginePrivate::isQObject(actual)) {
                     switch (tid) {
                     case QMetaType::QObjectStar:
                     case QMetaType::QWidgetStar:
@@ -841,9 +854,10 @@
 //#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
 //        engine->notifyFunctionEntry(context);
 //#endif
+        QString funName = QString::fromLatin1(methodName(initialMethodSignature, nameLength));
         if (!conversionFailed.isEmpty()) {
             QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
-                              .arg(QLatin1String(funName));
+                              .arg(funName);
             for (int i = 0; i < conversionFailed.size(); ++i) {
                 if (i > 0)
                     message += QLatin1String("\n");
@@ -858,7 +872,7 @@
             QScriptMetaType unresolvedType = argsInstance.method.type(unresolvedIndex);
             QString unresolvedTypeName = QString::fromLatin1(unresolvedType.name());
             QString message = QString::fromLatin1("cannot call %0(): ")
-                              .arg(QString::fromLatin1(funName));
+                              .arg(funName);
             if (unresolvedIndex > 0) {
                 message.append(QString::fromLatin1("argument %0 has unknown type `%1'").
                                arg(unresolvedIndex).arg(unresolvedTypeName));
@@ -870,7 +884,7 @@
             result = JSC::throwError(exec, JSC::TypeError, message);
         } else {
             QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
-                              .arg(QLatin1String(funName));
+                              .arg(funName);
             for (int i = 0; i < tooFewArgs.size(); ++i) {
                 if (i > 0)
                     message += QLatin1String("\n");
@@ -886,6 +900,7 @@
                 && (metaArgs.args.count() == candidates.at(1).args.count())
                 && (metaArgs.matchDistance == candidates.at(1).matchDistance)) {
                 // ambiguous call
+                QByteArray funName = methodName(initialMethodSignature, nameLength);
                 QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
                                   .arg(QLatin1String(funName));
                 for (int i = 0; i < candidates.size(); ++i) {
@@ -953,13 +968,11 @@
             } else {
                 QScriptMetaType retType = chosenMethod.returnType();
                 if (retType.isVariant()) {
-                    result = engine->jscValueFromVariant(*(QVariant *)params[0]);
+                    result = QScriptEnginePrivate::jscValueFromVariant(exec, *(QVariant *)params[0]);
                 } else if (retType.typeId() != 0) {
-                    result = engine->scriptValueToJSCValue(engine->create(retType.typeId(), params[0]));
-                    if (!result) {
-                        QScriptValue sv = QScriptEnginePrivate::get(engine)->newVariant(QVariant(retType.typeId(), params[0]));
-                        result = engine->scriptValueToJSCValue(sv);
-                    }
+                    result = QScriptEnginePrivate::create(exec, retType.typeId(), params[0]);
+                    if (!result)
+                        result = engine->newVariant(QVariant(retType.typeId(), params[0]));
                 } else {
                     result = JSC::jsUndefined();
                 }
@@ -1049,14 +1062,7 @@
     if (!callee->inherits(&QtPropertyFunction::info))
         return throwError(exec, JSC::TypeError, "callee is not a QtPropertyFunction object");
     QtPropertyFunction *qfun =  static_cast<QtPropertyFunction*>(callee);
-    QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
-    JSC::ExecState *previousFrame = eng_p->currentFrame;
-    eng_p->currentFrame = exec;
-    eng_p->pushContext(exec, thisValue, args, callee);
-    JSC::JSValue result = qfun->execute(eng_p->currentFrame, thisValue, args);
-    eng_p->popContext();
-    eng_p->currentFrame = previousFrame;
-    return result;
+    return qfun->execute(exec, thisValue, args);
 }
 
 JSC::JSValue QtPropertyFunction::execute(JSC::ExecState *exec,
@@ -1065,15 +1071,16 @@
 {
     JSC::JSValue result = JSC::jsUndefined();
 
-    // ### don't go via QScriptValue
     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
-    thisValue = engine->toUsableValue(thisValue);
-    QScriptValue object = engine->scriptValueFromJSCValue(thisValue);
-    QObject *qobject = object.toQObject();
+    JSC::ExecState *previousFrame = engine->currentFrame;
+    engine->currentFrame = exec;
+
+    JSC::JSValue qobjectValue = engine->toUsableValue(thisValue);
+    QObject *qobject = QScriptEnginePrivate::toQObject(exec, qobjectValue);
     while ((!qobject || (qobject->metaObject() != data->meta))
-           && object.prototype().isObject()) {
-        object = object.prototype();
-        qobject = object.toQObject();
+        && JSC::asObject(qobjectValue)->prototype().isObject()) {
+        qobjectValue = JSC::asObject(qobjectValue)->prototype();
+        qobject = QScriptEnginePrivate::toQObject(exec, qobjectValue);
     }
     Q_ASSERT_X(qobject, Q_FUNC_INFO, "this-object must be a QObject");
 
@@ -1085,16 +1092,19 @@
             QScriptable *scriptable = scriptableFromQObject(qobject);
             QScriptEngine *oldEngine = 0;
             if (scriptable) {
+                engine->pushContext(exec, thisValue, args, this);
                 oldEngine = QScriptablePrivate::get(scriptable)->engine;
                 QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine);
             }
 
             QVariant v = prop.read(qobject);
 
-            if (scriptable)
+            if (scriptable) {
                 QScriptablePrivate::get(scriptable)->engine = oldEngine;
+                engine->popContext();
+            }
 
-            result = engine->jscValueFromVariant(v);
+            result = QScriptEnginePrivate::jscValueFromVariant(exec, v);
         }
     } else {
         // set
@@ -1106,25 +1116,27 @@
             // string to enum value
             v = (QString)arg.toString(exec);
         } else {
-            // ### don't go via QScriptValue
-            QScriptValue tmp = engine->scriptValueFromJSCValue(arg);
-            v = variantFromValue(engine, prop.userType(), tmp);
+            v = variantFromValue(exec, prop.userType(), arg);
         }
 
         QScriptable *scriptable = scriptableFromQObject(qobject);
         QScriptEngine *oldEngine = 0;
         if (scriptable) {
+            engine->pushContext(exec, thisValue, args, this);
             oldEngine = QScriptablePrivate::get(scriptable)->engine;
             QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine);
         }
 
         prop.write(qobject, v);
 
-        if (scriptable)
+        if (scriptable) {
             QScriptablePrivate::get(scriptable)->engine = oldEngine;
+            engine->popContext();
+        }
 
         result = arg;
     }
+    engine->currentFrame = previousFrame;
     return result;
 }
 
@@ -1176,7 +1188,7 @@
 {
     //Note: this has to be kept in sync with getOwnPropertyDescriptor
 #ifndef QT_NO_PROPERTIES
-    QByteArray name = QString(propertyName.ustring()).toLatin1();
+    QByteArray name = convertToLatin1(propertyName.ustring());
     QObject *qobject = data->value;
     if (!qobject) {
         QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
@@ -1237,7 +1249,7 @@
                     if (!prop.isValid())
                         val = JSC::jsUndefined();
                     else
-                        val = eng->jscValueFromVariant(prop.read(qobject));
+                        val = QScriptEnginePrivate::jscValueFromVariant(exec, prop.read(qobject));
                     slot.setValue(val);
                 }
                 return true;
@@ -1247,7 +1259,7 @@
 
     index = qobject->dynamicPropertyNames().indexOf(name);
     if (index != -1) {
-        JSC::JSValue val = eng->jscValueFromVariant(qobject->property(name));
+        JSC::JSValue val = QScriptEnginePrivate::jscValueFromVariant(exec, qobject->property(name));
         slot.setValue(val);
         return true;
     }
@@ -1257,7 +1269,7 @@
     for (index = meta->methodCount() - 1; index >= offset; --index) {
         QMetaMethod method = meta->method(index);
         if (hasMethodAccess(method, index, opt)
-            && (methodName(method) == name)) {
+            && methodNameEquals(method, name.constData(), name.length())) {
             QtFunction *fun = new (exec)QtFunction(
                 object, index, /*maybeOverloaded=*/true,
                 &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
@@ -1274,8 +1286,7 @@
             QObject *child = children.at(index);
             if (child->objectName() == QString(propertyName.ustring())) {
                 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
-                QScriptValue tmp = QScriptEnginePrivate::get(eng)->newQObject(child, QScriptEngine::QtOwnership, opt);
-                slot.setValue(eng->scriptValueToJSCValue(tmp));
+                slot.setValue(eng->newQObject(child, QScriptEngine::QtOwnership, opt));
                 return true;
             }
         }
@@ -1292,9 +1303,9 @@
                                          const JSC::Identifier &propertyName,
                                          JSC::PropertyDescriptor &descriptor)
 {
-    //Note: this has to be kept in sync with getOwnPropertySlot abd getPropertyAttributes
+    //Note: this has to be kept in sync with getOwnPropertySlot
 #ifndef QT_NO_PROPERTIES
-    QByteArray name = QString(propertyName.ustring()).toLatin1();
+    QByteArray name = convertToLatin1(propertyName.ustring());
     QObject *qobject = data->value;
     if (!qobject) {
         QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
@@ -1370,7 +1381,7 @@
                     if (!prop.isValid())
                         val = JSC::jsUndefined();
                     else
-                        val = eng->jscValueFromVariant(prop.read(qobject));
+                        val = QScriptEnginePrivate::jscValueFromVariant(exec, prop.read(qobject));
                     descriptor.setDescriptor(val, attributes);
                 }
                 return true;
@@ -1380,7 +1391,7 @@
 
     index = qobject->dynamicPropertyNames().indexOf(name);
     if (index != -1) {
-        JSC::JSValue val = eng->jscValueFromVariant(qobject->property(name));
+        JSC::JSValue val = QScriptEnginePrivate::jscValueFromVariant(exec, qobject->property(name));
         descriptor.setDescriptor(val, QObjectMemberAttribute);
         return true;
     }
@@ -1390,7 +1401,7 @@
     for (index = meta->methodCount() - 1; index >= offset; --index) {
         QMetaMethod method = meta->method(index);
         if (hasMethodAccess(method, index, opt)
-            && (methodName(method) == name)) {
+            && methodNameEquals(method, name.constData(), name.length())) {
             QtFunction *fun = new (exec)QtFunction(
                 object, index, /*maybeOverloaded=*/true,
                 &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
@@ -1410,8 +1421,8 @@
             QObject *child = children.at(index);
             if (child->objectName() == QString(propertyName.ustring())) {
                 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
-                QScriptValue tmp = QScriptEnginePrivate::get(eng)->newQObject(child, QScriptEngine::QtOwnership, opt);
-                descriptor.setDescriptor(eng->scriptValueToJSCValue(tmp), JSC::ReadOnly | JSC::DontDelete | JSC::DontEnum);
+                descriptor.setDescriptor(eng->newQObject(child, QScriptEngine::QtOwnership, opt),
+                                         JSC::ReadOnly | JSC::DontDelete | JSC::DontEnum);
                 return true;
             }
         }
@@ -1428,7 +1439,7 @@
                           JSC::JSValue value, JSC::PutPropertySlot &slot)
 {
 #ifndef QT_NO_PROPERTIES
-    QByteArray name = ((QString)propertyName.ustring()).toLatin1();
+    QByteArray name = convertToLatin1(propertyName.ustring());
     QObject *qobject = data->value;
     if (!qobject) {
         QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
@@ -1490,7 +1501,7 @@
                         // string to enum value
                         v = (QString)value.toString(exec);
                     } else {
-                        v = eng->jscValueToVariant(value, prop.userType());
+                        v = QScriptEnginePrivate::jscValueToVariant(exec, value, prop.userType());
                     }
                     (void)prop.write(qobject, v);
                 }
@@ -1504,7 +1515,7 @@
     for (index = meta->methodCount() - 1; index >= offset; --index) {
         QMetaMethod method = meta->method(index);
         if (hasMethodAccess(method, index, opt)
-            && (methodName(method) == name)) {
+            && methodNameEquals(method, name.constData(), name.length())) {
             data->cachedMembers.insert(name, value);
             return;
         }
@@ -1512,7 +1523,7 @@
 
     index = qobject->dynamicPropertyNames().indexOf(name);
     if ((index != -1) || (opt & QScriptEngine::AutoCreateDynamicProperties)) {
-        QVariant v = eng->scriptValueFromJSCValue(value).toVariant();
+        QVariant v = QScriptEnginePrivate::toVariant(exec, value);
         (void)qobject->setProperty(name, v);
         return;
     }
@@ -1522,11 +1533,10 @@
 }
 
 bool QObjectDelegate::deleteProperty(QScriptObject *object, JSC::ExecState *exec,
-                                     const JSC::Identifier& propertyName,
-                                     bool checkDontDelete)
+                                     const JSC::Identifier& propertyName)
 {
 #ifndef QT_NO_PROPERTIES
-    QByteArray name = ((QString)propertyName.ustring()).toLatin1();
+    QByteArray name = convertToLatin1(propertyName.ustring());
     QObject *qobject = data->value;
     if (!qobject) {
         QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
@@ -1563,86 +1573,7 @@
         return true;
     }
 
-    return QScriptObjectDelegate::deleteProperty(object, exec, propertyName, checkDontDelete);
-#else //QT_NO_PROPERTIES
-    return false;
-#endif //QT_NO_PROPERTIES
-}
-
-bool QObjectDelegate::getPropertyAttributes(const QScriptObject *object,
-                                            JSC::ExecState *exec,
-                                            const JSC::Identifier &propertyName,
-                                            unsigned &attributes) const
-{
-#ifndef QT_NO_PROPERTIES
-    //Note: this has to be kept in sync with getOwnPropertyDescriptor and getOwnPropertySlot
-    QByteArray name = ((QString)propertyName.ustring()).toLatin1();
-    QObject *qobject = data->value;
-    if (!qobject)
-        return false;
-
-    const QScriptEngine::QObjectWrapOptions &opt = data->options;
-    const QMetaObject *meta = qobject->metaObject();
-    int index = -1;
-    if (name.contains('(')) {
-        QByteArray normalized = QMetaObject::normalizedSignature(name);
-        if (-1 != (index = meta->indexOfMethod(normalized))) {
-            QMetaMethod method = meta->method(index);
-            if (hasMethodAccess(method, index, opt)) {
-                if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
-                    || (index >= meta->methodOffset())) {
-                    attributes = QObjectMemberAttribute;
-                    if (opt & QScriptEngine::SkipMethodsInEnumeration)
-                        attributes |= JSC::DontEnum;
-                    return true;
-                }
-            }
-        }
-    }
-
-    index = meta->indexOfProperty(name);
-    if (index != -1) {
-        QMetaProperty prop = meta->property(index);
-        if (prop.isScriptable()) {
-            if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
-                || (index >= meta->propertyOffset())) {
-                attributes = flagsForMetaProperty(prop);
-                return true;
-            }
-        }
-    }
-
-    index = qobject->dynamicPropertyNames().indexOf(name);
-    if (index != -1) {
-        attributes = QObjectMemberAttribute;
-        return true;
-    }
-
-    const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
-                       ? meta->methodOffset() : 0;
-    for (index = meta->methodCount() - 1; index >= offset; --index) {
-        QMetaMethod method = meta->method(index);
-        if (hasMethodAccess(method, index, opt)
-            && (methodName(method) == name)) {
-            attributes = QObjectMemberAttribute;
-            if (opt & QScriptEngine::SkipMethodsInEnumeration)
-                attributes |= JSC::DontEnum;
-            return true;
-        }
-    }
-
-    if (!(opt & QScriptEngine::ExcludeChildObjects)) {
-        QList<QObject*> children = qobject->children();
-        for (index = 0; index < children.count(); ++index) {
-            QObject *child = children.at(index);
-            if (child->objectName() == (QString)(propertyName.ustring())) {
-                attributes = JSC::ReadOnly | JSC::DontDelete | JSC::DontEnum;
-                return true;
-            }
-        }
-    }
-
-    return QScriptObjectDelegate::getPropertyAttributes(object, exec, propertyName, attributes);
+    return QScriptObjectDelegate::deleteProperty(object, exec, propertyName);
 #else //QT_NO_PROPERTIES
     return false;
 #endif //QT_NO_PROPERTIES
@@ -1650,7 +1581,7 @@
 
 void QObjectDelegate::getOwnPropertyNames(QScriptObject *object, JSC::ExecState *exec,
                                           JSC::PropertyNameArray &propertyNames,
-                                          bool includeNonEnumerable)
+                                          JSC::EnumerationMode mode)
 {
 #ifndef QT_NO_PROPERTIES
     QObject *qobject = data->value;
@@ -1695,7 +1626,7 @@
         }
     }
 
-    QScriptObjectDelegate::getOwnPropertyNames(object, exec, propertyNames, includeNonEnumerable);
+    QScriptObjectDelegate::getOwnPropertyNames(object, exec, propertyNames, mode);
 #endif //QT_NO_PROPERTIES
 }
 
@@ -1823,9 +1754,9 @@
                                     | QScriptEngine::ExcludeSuperClassProperties
                                     | QScriptEngine::ExcludeChildObjects));
 
-    putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, exec->propertyNames().toString, qobjectProtoFuncToString), JSC::DontEnum);
-    putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChild"), qobjectProtoFuncFindChild), JSC::DontEnum);
-    putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChildren"), qobjectProtoFuncFindChildren), JSC::DontEnum);
+    putDirectFunction(exec, new (exec) JSC::NativeFunctionWrapper(exec, prototypeFunctionStructure, /*length=*/0, exec->propertyNames().toString, qobjectProtoFuncToString), JSC::DontEnum);
+    putDirectFunction(exec, new (exec) JSC::NativeFunctionWrapper(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChild"), qobjectProtoFuncFindChild), JSC::DontEnum);
+    putDirectFunction(exec, new (exec) JSC::NativeFunctionWrapper(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChildren"), qobjectProtoFuncFindChildren), JSC::DontEnum);
     this->structure()->setHasGetterSetterProperties(true);
 }
 
@@ -1862,7 +1793,7 @@
         return true;
     }
 
-    QByteArray name = QString(propertyName.ustring()).toLatin1();
+    QByteArray name = convertToLatin1(propertyName.ustring());
 
     for (int i = 0; i < meta->enumeratorCount(); ++i) {
         QMetaEnum e = meta->enumerator(i);
@@ -1878,6 +1809,39 @@
     return JSC::JSObject::getOwnPropertySlot(exec, propertyName, slot);
 }
 
+bool QMetaObjectWrapperObject::getOwnPropertyDescriptor(
+    JSC::ExecState* exec, const JSC::Identifier& propertyName,
+    JSC::PropertyDescriptor& descriptor)
+{
+    const QMetaObject *meta = data->value;
+    if (!meta)
+        return false;
+
+    if (propertyName == exec->propertyNames().prototype) {
+        descriptor.setDescriptor(data->ctor
+                                 ? data->ctor.get(exec, propertyName)
+                                 : data->prototype,
+                                 JSC::DontDelete | JSC::DontEnum);
+        return true;
+    }
+
+    QByteArray name = QString(propertyName.ustring()).toLatin1();
+
+    for (int i = 0; i < meta->enumeratorCount(); ++i) {
+        QMetaEnum e = meta->enumerator(i);
+        for (int j = 0; j < e.keyCount(); ++j) {
+            const char *key = e.key(j);
+            if (!qstrcmp(key, name.constData())) {
+                descriptor.setDescriptor(JSC::JSValue(exec, e.value(j)),
+                                         JSC::ReadOnly | JSC::DontDelete);
+                return true;
+            }
+        }
+    }
+
+    return JSC::JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+}
+
 void QMetaObjectWrapperObject::put(JSC::ExecState* exec, const JSC::Identifier& propertyName,
                                    JSC::JSValue value, JSC::PutPropertySlot &slot)
 {
@@ -1890,7 +1854,7 @@
     }
     const QMetaObject *meta = data->value;
     if (meta) {
-        QByteArray name = QString(propertyName.ustring()).toLatin1();
+        QByteArray name = convertToLatin1(propertyName.ustring());
         for (int i = 0; i < meta->enumeratorCount(); ++i) {
             QMetaEnum e = meta->enumerator(i);
             for (int j = 0; j < e.keyCount(); ++j) {
@@ -1903,14 +1867,13 @@
 }
 
 bool QMetaObjectWrapperObject::deleteProperty(
-    JSC::ExecState *exec, const JSC::Identifier& propertyName,
-    bool checkDontDelete)
+    JSC::ExecState *exec, const JSC::Identifier& propertyName)
 {
     if (propertyName == exec->propertyNames().prototype)
         return false;
     const QMetaObject *meta = data->value;
     if (meta) {
-        QByteArray name = QString(propertyName.ustring()).toLatin1();
+        QByteArray name = convertToLatin1(propertyName.ustring());
         for (int i = 0; i < meta->enumeratorCount(); ++i) {
             QMetaEnum e = meta->enumerator(i);
             for (int j = 0; j < e.keyCount(); ++j) {
@@ -1919,36 +1882,12 @@
             }
         }
     }
-    return JSC::JSObject::deleteProperty(exec, propertyName, checkDontDelete);
-}
-
-bool QMetaObjectWrapperObject::getPropertyAttributes(JSC::ExecState *exec,
-                                                     const JSC::Identifier &propertyName,
-                                                     unsigned &attributes) const
-{
-    if (propertyName == exec->propertyNames().prototype) {
-        attributes = JSC::DontDelete;
-        return true;
-    }
-    const QMetaObject *meta = data->value;
-    if (meta) {
-        QByteArray name = QString(propertyName.ustring()).toLatin1();
-        for (int i = 0; i < meta->enumeratorCount(); ++i) {
-            QMetaEnum e = meta->enumerator(i);
-            for (int j = 0; j < e.keyCount(); ++j) {
-                if (!qstrcmp(e.key(j), name.constData())) {
-                    attributes = JSC::ReadOnly | JSC::DontDelete;
-                    return true;
-                }
-            }
-        }
-    }
-    return JSC::JSObject::getPropertyAttributes(exec, propertyName, attributes);
+    return JSC::JSObject::deleteProperty(exec, propertyName);
 }
 
 void QMetaObjectWrapperObject::getOwnPropertyNames(JSC::ExecState *exec,
                                                    JSC::PropertyNameArray &propertyNames,
-                                                   bool includeNonEnumerable)
+                                                   JSC::EnumerationMode mode)
 {
     const QMetaObject *meta = data->value;
     if (!meta)
@@ -1958,7 +1897,7 @@
         for (int j = 0; j < e.keyCount(); ++j)
             propertyNames.add(JSC::Identifier(exec, e.key(j)));
     }
-    JSC::JSObject::getOwnPropertyNames(exec, propertyNames, includeNonEnumerable);
+    JSC::JSObject::getOwnPropertyNames(exec, propertyNames, mode);
 }
 
 void QMetaObjectWrapperObject::markChildren(JSC::MarkStack& markStack)
@@ -2077,7 +2016,7 @@
     JSC::Structure* prototypeFunctionStructure)
     : QMetaObjectWrapperObject(exec, StaticQtMetaObject::get(), /*ctor=*/JSC::JSValue(), structure)
 {
-    putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, JSC::Identifier(exec, "className"), qmetaobjectProtoFuncClassName), JSC::DontEnum);
+    putDirectFunction(exec, new (exec) JSC::NativeFunctionWrapper(exec, prototypeFunctionStructure, /*length=*/0, JSC::Identifier(exec, "className"), qmetaobjectProtoFuncClassName), JSC::DontEnum);
 }
 
 static const uint qt_meta_data_QObjectConnectionManager[] = {
@@ -2136,6 +2075,7 @@
     JSC::JSValue slot;
     JSC::JSValue senderWrapper;
     int signalIndex = -1;
+    QScript::APIShim shim(engine);
     for (int i = 0; i < connections.size(); ++i) {
         const QVector<QObjectConnection> &cs = connections.at(i);
         for (int j = 0; j < cs.size(); ++j) {
@@ -2178,24 +2118,21 @@
     JSC::ExecState *exec = engine->currentFrame;
     QVarLengthArray<JSC::JSValue, 8> argsVector(argc);
     for (int i = 0; i < argc; ++i) {
-        // ### optimize -- no need to convert via QScriptValue
-        QScriptValue actual;
+        JSC::JSValue actual;
         void *arg = argv[i + 1];
         QByteArray typeName = parameterTypes.at(i);
         int argType = QMetaType::type(parameterTypes.at(i));
         if (!argType) {
-            if (typeName == "QVariant") {
-                actual = engine->scriptValueFromVariant(*reinterpret_cast<QVariant*>(arg));
-            } else {
-                qWarning("QScriptEngine: Unable to handle unregistered datatype '%s' "
-                         "when invoking handler of signal %s::%s",
-                         typeName.constData(), meta->className(), method.signature());
-                actual = QScriptValue(QScriptValue::UndefinedValue);
-            }
+            qWarning("QScriptEngine: Unable to handle unregistered datatype '%s' "
+                        "when invoking handler of signal %s::%s",
+                        typeName.constData(), meta->className(), method.signature());
+            actual = JSC::jsUndefined();
+        } else if (argType == QMetaType::QVariant) {
+            actual = QScriptEnginePrivate::jscValueFromVariant(exec, *reinterpret_cast<QVariant*>(arg));
         } else {
-            actual = engine->create(argType, arg);
+            actual = QScriptEnginePrivate::create(exec, argType, arg);
         }
-        argsVector[i] = engine->scriptValueToJSCValue(actual);
+        argsVector[i] = actual;
     }
     JSC::ArgList jscArgs(argsVector.data(), argsVector.size());