#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
-QT_BEGIN_NAMESPACE
-
Q_DECLARE_METATYPE(QJSValue);
Q_DECLARE_METATYPE(QDeclarativeV8Handle);
+QT_BEGIN_NAMESPACE
+
#if defined(__GNUC__)
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
// The code in this file does not violate strict aliasing, but GCC thinks it does
};
namespace {
+
+template<typename A, typename B, typename C, typename D, typename E>
+class MaxSizeOf5 {
+ template<typename Z, typename X>
+ struct SMax {
+ static const size_t Size = sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X);
+ };
+public:
+ static const size_t Size = SMax<A, SMax<B, SMax<C, SMax<D, E> > > >::Size;
+};
+
struct MetaCallArgument {
inline MetaCallArgument();
inline ~MetaCallArgument();
bool boolValue;
QObject *qobjectPtr;
- char allocData[sizeof(QVariant)];
+ char allocData[MaxSizeOf5<QVariant,
+ QString,
+ QList<QObject *>,
+ QJSValue,
+ QDeclarativeV8Handle>::Size];
+ qint64 q_for_alignment;
};
// Pointers to allocData
// Load value properties
static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
- const QDeclarativePropertyCache::Data &property)
+ const QDeclarativePropertyData &property)
{
Q_ASSERT(!property.isFunction());
QDeclarativeValueType *valueType = ep->valueTypes[property.propType];
if (valueType)
return engine->newValueType(object, property.coreIndex, valueType);
- }
+ } else {
+ // see if it's a sequence type
+ bool succeeded = false;
+ v8::Handle<v8::Value> retn = engine->newSequence(property.propType, object, property.coreIndex, &succeeded);
+ if (succeeded)
+ return retn;
+ }
QVariant var = object->metaObject()->property(property.coreIndex).read(object);
return engine->fromVariant(var);
}
static v8::Handle<v8::Value> LoadPropertyDirect(QV8Engine *engine, QObject *object,
- const QDeclarativePropertyCache::Data &property)
+ const QDeclarativePropertyData &property)
{
Q_ASSERT(!property.isFunction());
void *args[] = { &handle, 0 };
object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex, args);
return handle.toHandle();
- } else if (QDeclarativeValueTypeFactory::isValueType((uint)property.propType)
- && engine->engine()) {
+ } else if (engine->engine() && QDeclarativeValueTypeFactory::isValueType((uint)property.propType)) {
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
QDeclarativeValueType *valueType = ep->valueTypes[property.propType];
if (valueType)
return engine->newValueType(object, property.coreIndex, valueType);
- }
+ } else {
+ // see if it's a sequence type
+ bool success = false;
+ v8::Handle<v8::Value> retn = engine->newSequence(property.propType, object, property.coreIndex, &success);
+ if (success)
+ return retn;
+ }
QVariant var = object->metaObject()->property(property.coreIndex).read(object);
return engine->fromVariant(var);
}
}
- QDeclarativePropertyCache::Data local;
- QDeclarativePropertyCache::Data *result = 0;
+ QDeclarativePropertyData local;
+ QDeclarativePropertyData *result = 0;
{
QDeclarativeData *ddata = QDeclarativeData::get(object, false);
if (ddata && ddata->propertyCache)
ep->capturedProperties << CapturedProperty(object, result->coreIndex, result->notifyIndex);
}
+ if (result->isVMEProperty())
+ return static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject*>(object->metaObject()))->vmeProperty(result->coreIndex);
+
if (result->isDirect()) {
return LoadPropertyDirect(engine, object, *result);
} else {
}
// Setter for writable properties. Shared between the interceptor and fast property accessor
-static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativePropertyCache::Data *property,
+static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativePropertyData *property,
v8::Handle<v8::Value> value)
{
QDeclarativeBinding *newBinding = 0;
int lineNumber = frame->GetLineNumber();
QString url = engine->toString(frame->GetScriptName());
- QDeclarativePropertyCache::ValueTypeData valueTypeData;
newBinding = new QDeclarativeBinding(&function, object, context);
newBinding->setSourceLocation(url, lineNumber);
- newBinding->setTarget(QDeclarativePropertyPrivate::restore(*property, valueTypeData, object, context));
+ newBinding->setTarget(QDeclarativePropertyPrivate::restore(*property, object, context));
newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
}
PROPERTY_STORE(double, double(value->ToNumber()->Value()));
} else if (property->propType == QMetaType::QString && value->IsString()) {
PROPERTY_STORE(QString, engine->toString(value->ToString()));
+ } else if (property->isVMEProperty()) {
+ static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject *>(object->metaObject()))->setVMEProperty(property->coreIndex, value);
} else {
QVariant v;
if (property->isQList())
v = engine->toVariant(value, property->propType);
QDeclarativeContextData *context = engine->callingContext();
-
if (!QDeclarativePropertyPrivate::write(object, *property, v, context)) {
const char *valueType = 0;
if (v.userType() == QVariant::Invalid) valueType = "null";
engine->qobjectWrapper()->m_destroyString == property)
return true;
- QDeclarativePropertyCache::Data local;
- QDeclarativePropertyCache::Data *result = 0;
+ QDeclarativePropertyData local;
+ QDeclarativePropertyData *result = 0;
result = QDeclarativePropertyCache::property(engine->engine(), object, property, local);
if (!result)
QHashedV8String propertystring(property);
- QDeclarativePropertyCache::Data local;
- QDeclarativePropertyCache::Data *result = 0;
+ QDeclarativePropertyData local;
+ QDeclarativePropertyData *result = 0;
result = QDeclarativePropertyCache::property(engine->engine(), object, propertystring, local);
if (!result)
Q_ASSERT(ddata);
Q_ASSERT(ddata->propertyCache);
- QDeclarativePropertyCache::Data *pdata = ddata->propertyCache->property(index);
+ QDeclarativePropertyData *pdata = ddata->propertyCache->property(index);
Q_ASSERT(pdata);
Q_ASSERT(pdata->isWritable() || pdata->isQList());
v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8Engine *engine)
{
Q_ASSERT(object);
+ Q_ASSERT(this->engine);
Q_ASSERT(QDeclarativeData::get(object, false));
Q_ASSERT(QDeclarativeData::get(object, false)->propertyCache == this);
// performance, but the cost of setting up this structure hasn't been measured so
// its not guarenteed that this is a win overall. We need to try and measure the cost.
for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) {
- Data *property = *iter;
+ QDeclarativePropertyData *property = *iter;
if (property->isFunction() ||
property->coreIndex >= 0x7FFF || property->notifyIndex >= 0x0FFF ||
property->coreIndex == 0)
ft->InstanceTemplate()->SetHasExternalResource(true);
constructor = qPersistentNew<v8::Function>(ft->GetFunction());
}
+
+ QDeclarativeCleanup::addToEngine(this->engine);
}
v8::Local<v8::Object> result = constructor->NewInstance();
QList<Connection> connections = connectionList;
- QMetaMethod method = data()->metaObject()->method(index);
- Q_ASSERT(method.methodType() == QMetaMethod::Signal);
- // XXX TODO: We should figure out a way to cache the parameter types to avoid resolving
- // them each time.
- QList<QByteArray> params = method.parameterTypes();
+ QVarLengthArray<int, 9> dummy;
+ int *argsTypes = QDeclarativePropertyCache::methodParameterTypes(data(), index, dummy, 0);
v8::HandleScope handle_scope;
v8::Context::Scope scope(engine->context());
- QVarLengthArray<v8::Handle<v8::Value> > args(params.count());
- int argCount = params.count();
+ int argCount = argsTypes?argsTypes[0]:0;
+ QVarLengthArray<v8::Handle<v8::Value>, 9> args(argCount);
for (int ii = 0; ii < argCount; ++ii) {
- int type = QMetaType::type(params.at(ii).constData());
+ int type = argsTypes[ii + 1];
if (type == qMetaTypeId<QVariant>()) {
args[ii] = engine->fromVariant(*((QVariant *)metaArgs[ii + 1]));
} else {
}
}
-static int EnumType(const QMetaObject *meta, const QString &strname)
-{
- QByteArray str = strname.toUtf8();
- QByteArray scope;
- QByteArray name;
- int scopeIdx = str.lastIndexOf("::");
- if (scopeIdx != -1) {
- scope = str.left(scopeIdx);
- name = str.mid(scopeIdx + 2);
- } else {
- name = str;
- }
- for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
- QMetaEnum m = meta->enumerator(i);
- if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
- return QVariant::Int;
- }
- return QVariant::Invalid;
-}
-
/*!
Returns the match score for converting \a actual to be of type \a conversionType. A
zero score means "perfect match" whereas a higher score is worse.
The conversion table is copied out of the QtScript callQtMethod() function.
*/
-static int MatchScore(v8::Handle<v8::Value> actual, int conversionType,
- const QByteArray &conversionTypeName)
+static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
{
if (actual->IsNumber()) {
switch (conversionType) {
case QMetaType::VoidStar:
case QMetaType::QObjectStar:
return 0;
- default:
- if (!conversionTypeName.endsWith('*'))
- return 10;
- else
+ default: {
+ const char *typeName = QMetaType::typeName(conversionType);
+ if (typeName && typeName[strlen(typeName) - 1] == '*')
return 0;
+ else
+ return 10;
+ }
}
} else if (actual->IsObject()) {
v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(actual);
/*!
Returns the next related method, if one, or 0.
*/
-static const QDeclarativePropertyCache::Data * RelatedMethod(QObject *object,
- const QDeclarativePropertyCache::Data *current,
- QDeclarativePropertyCache::Data &dummy)
+static const QDeclarativePropertyData * RelatedMethod(QObject *object,
+ const QDeclarativePropertyData *current,
+ QDeclarativePropertyData &dummy)
{
QDeclarativePropertyCache *cache = QDeclarativeData::get(object)->propertyCache;
- if (current->relatedIndex == -1)
+ if (!current->isOverload())
return 0;
+ Q_ASSERT(!current->overrideIndexIsProperty);
+
if (cache) {
- return cache->method(current->relatedIndex);
+ return cache->method(current->overrideIndex);
} else {
const QMetaObject *mo = object->metaObject();
int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
- while (methodOffset > current->relatedIndex) {
+ while (methodOffset > current->overrideIndex) {
mo = mo->superClass();
methodOffset -= QMetaObject_methods(mo);
}
- QMetaMethod method = mo->method(current->relatedIndex);
+ QMetaMethod method = mo->method(current->overrideIndex);
dummy.load(method);
// Look for overloaded methods
QByteArray methodName = QMetaMethod_name(method);
- for (int ii = current->relatedIndex - 1; ii >= methodOffset; --ii) {
+ for (int ii = current->overrideIndex - 1; ii >= methodOffset; --ii) {
if (methodName == QMetaMethod_name(mo->method(ii))) {
- dummy.relatedIndex = ii;
+ dummy.setFlags(dummy.getFlags() | QDeclarativePropertyData::IsOverload);
+ dummy.overrideIndexIsProperty = 0;
+ dummy.overrideIndex = ii;
return &dummy;
}
}
}
}
-static v8::Handle<v8::Value> CallPrecise(QObject *object, const QDeclarativePropertyCache::Data &data,
+static v8::Handle<v8::Value> CallPrecise(QObject *object, const QDeclarativePropertyData &data,
QV8Engine *engine, CallArgs &callArgs)
{
if (data.hasArguments()) {
- QMetaMethod m = object->metaObject()->method(data.coreIndex);
- QList<QByteArray> argTypeNames = m.parameterTypes();
- QVarLengthArray<int, 9> argTypes(argTypeNames.count());
-
- // ### Cache
- for (int ii = 0; ii < argTypeNames.count(); ++ii) {
- argTypes[ii] = QMetaType::type(argTypeNames.at(ii));
- if (argTypes[ii] == QVariant::Invalid)
- argTypes[ii] = EnumType(object->metaObject(), QString::fromLatin1(argTypeNames.at(ii)));
- if (argTypes[ii] == QVariant::Invalid) {
- QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(QLatin1String(argTypeNames.at(ii)));
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- return v8::Handle<v8::Value>();
- }
+ int *args = 0;
+ QVarLengthArray<int, 9> dummy;
+ QByteArray unknownTypeError;
+
+ args = QDeclarativePropertyCache::methodParameterTypes(object, data.coreIndex, dummy,
+ &unknownTypeError);
+
+ if (!args) {
+ QString typeName = QString::fromLatin1(unknownTypeError);
+ QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName);
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
}
- if (argTypes.count() > callArgs.Length()) {
+ if (args[0] > callArgs.Length()) {
QString error = QLatin1String("Insufficient arguments");
v8::ThrowException(v8::Exception::Error(engine->toString(error)));
return v8::Handle<v8::Value>();
}
- return CallMethod(object, data.coreIndex, data.propType, argTypes.count(),
- argTypes.data(), engine, callArgs);
+ return CallMethod(object, data.coreIndex, data.propType, args[0], args + 1, engine, callArgs);
} else {
If two or more overloads have the same match score, call the last one. The match
score is constructed by adding the matchScore() result for each of the parameters.
*/
-static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativePropertyCache::Data &data,
+static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativePropertyData &data,
QV8Engine *engine, CallArgs &callArgs)
{
int argumentCount = callArgs.Length();
- const QDeclarativePropertyCache::Data *best = 0;
+ const QDeclarativePropertyData *best = 0;
int bestParameterScore = INT_MAX;
int bestMatchScore = INT_MAX;
- QDeclarativePropertyCache::Data dummy;
- const QDeclarativePropertyCache::Data *attempt = &data;
+ QDeclarativePropertyData dummy;
+ const QDeclarativePropertyData *attempt = &data;
do {
- QList<QByteArray> methodArgTypeNames;
-
- if (attempt->hasArguments())
- methodArgTypeNames = object->metaObject()->method(attempt->coreIndex).parameterTypes();
+ QVarLengthArray<int, 9> dummy;
+ int methodArgumentCount = 0;
+ int *methodArgTypes = 0;
+ if (attempt->hasArguments()) {
+ typedef QDeclarativePropertyCache PC;
+ int *args = PC::methodParameterTypes(object, attempt->coreIndex, dummy, 0);
+ if (!args) // Must be an unknown argument
+ continue;
- int methodArgumentCount = methodArgTypeNames.count();
+ methodArgumentCount = args[0];
+ methodArgTypes = args + 1;
+ }
if (methodArgumentCount > argumentCount)
continue; // We don't have sufficient arguments to call this method
continue; // We already have a better option
int methodMatchScore = 0;
- QVarLengthArray<int, 9> methodArgTypes(methodArgumentCount);
-
- bool unknownArgument = false;
- for (int ii = 0; ii < methodArgumentCount; ++ii) {
- methodArgTypes[ii] = QMetaType::type(methodArgTypeNames.at(ii));
- if (methodArgTypes[ii] == QVariant::Invalid)
- methodArgTypes[ii] = EnumType(object->metaObject(),
- QString::fromLatin1(methodArgTypeNames.at(ii)));
- if (methodArgTypes[ii] == QVariant::Invalid) {
- unknownArgument = true;
- break;
- }
- methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii], methodArgTypeNames.at(ii));
- }
- if (unknownArgument)
- continue; // We don't understand all the parameters
+ for (int ii = 0; ii < methodArgumentCount; ++ii)
+ methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii]);
if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
best = attempt;
return CallPrecise(object, *best, engine, callArgs);
} else {
QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
- const QDeclarativePropertyCache::Data *candidate = &data;
+ const QDeclarativePropertyData *candidate = &data;
while (candidate) {
error += QLatin1String("\n ") +
QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).signature());
}
}
- QDeclarativePropertyCache::Data method;
+ QDeclarativePropertyData method;
if (QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(object)->declarativeData)) {
if (ddata->propertyCache) {
- QDeclarativePropertyCache::Data *d = ddata->propertyCache->method(index);
+ QDeclarativePropertyData *d = ddata->propertyCache->method(index);
if (!d)
return v8::Undefined();
method = *d;
}
if (method.coreIndex == -1) {
- QMetaMethod mm = object->metaObject()->method(index);
method.load(object->metaObject()->method(index));
if (method.coreIndex == -1)
}
CallArgs callArgs(argCount, &arguments);
- if (method.relatedIndex == -1) {
+ if (!method.isOverload()) {
return CallPrecise(object, method, resource->engine, callArgs);
} else {
return CallOverloaded(object, method, resource->engine, callArgs);
return v8::Undefined();
}
}
+
+QT_END_NAMESPACE
+