Commit 34f74502 authored by Cyrille Berger's avatar Cyrille Berger

makes ruby scripts go twice as fast by caching some informations

svn path=/trunk/koffice/; revision=607625
parent bcde712f
......@@ -10,7 +10,9 @@ set(krossruby_PART_SRCS
rubyinterpreter.cpp
rubyextension.cpp
rubyscript.cpp
rubymodule.cpp )
rubymodule.cpp
rubycallcache.cpp
)
kde4_automoc(${krossruby_PART_SRCS})
......
/***************************************************************************
* rubycallcache.cpp
* This file is part of the KDE project
* copyright (C)2006 by Cyrille Berger (cberger@cberger.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Library General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
***************************************************************************/
#include "rubycallcache.h"
#include <QVariant>
#include <rubyvariant.h>
namespace Kross {
struct RubyCallCachePrivate {
RubyCallCachePrivate(QObject* nobject, int nmethodindex, bool nhasreturnvalue, int nreturnTypeId, int nreturnMetaTypeId, QVarLengthArray<int> nvariantargs) :
object(nobject), methodindex(nmethodindex), hasreturnvalue(nhasreturnvalue), returnTypeId(nreturnTypeId), returnMetaTypeId(nreturnMetaTypeId), varianttypes(nvariantargs)
{
}
QObject* object;
int methodindex;
bool hasreturnvalue;
int returnTypeId;
int returnMetaTypeId;
QVarLengthArray<int> varianttypes;
};
RubyCallCache::RubyCallCache(QObject* object, int methodindex, bool hasreturnvalue, int returnTypeId, int returnMetaTypeId, QVarLengthArray<int> variantargs) :
d(new RubyCallCachePrivate(object, methodindex, hasreturnvalue, returnTypeId, returnMetaTypeId, variantargs))
{
}
RubyCallCache::~RubyCallCache()
{
delete d;
}
QVariant RubyCallCache::execfunction( int argc, VALUE *argv )
{
QVariant result;
int typelistcount = d->varianttypes.count();
QVarLengthArray<MetaType*> variantargs( typelistcount );
QVarLengthArray<void*> voidstarargs( typelistcount );
// set the return value
if(d->hasreturnvalue) {
MetaType* returntype;
if(d->returnTypeId != QVariant::Invalid) {
returntype = new MetaTypeVariant< QVariant >( QVariant( (QVariant::Type) d->returnTypeId ) );
}
else {
if(d->returnMetaTypeId == QMetaType::Void) {
returntype = new MetaTypeVariant< QVariant >( QVariant() );
}
else {
//if (id != -1) {
void* myClassPtr = QMetaType::construct(d->returnMetaTypeId, 0);
//QMetaType::destroy(id, myClassPtr);
returntype = new MetaTypeVoidStar( d->returnMetaTypeId, myClassPtr );
}
}
variantargs[0] = returntype;
voidstarargs[0] = returntype->toVoidStar();
}
else {
variantargs[0] = 0;
voidstarargs[0] = (void*)0;
}
//Set the arguments values
for(int idx = 1; idx < typelistcount; ++idx) {
MetaType* metatype = RubyMetaTypeFactory::create( d->varianttypes[idx ], argv[idx]);
if(! metatype) {
// Seems RubyMetaTypeFactory::create returned an invalid RubyType.
krosswarning( QString("RubyExtension::callMetaMethod Aborting cause RubyMetaTypeFactory::create returned NULL.") );
for(int i = 0; i < idx; ++i) // Clear already allocated instances.
delete variantargs[i];
return QVariant(false); // abort execution.
}
variantargs[idx] = metatype;
voidstarargs[idx] = metatype->toVoidStar();
}
// call the method now
int r = d->object->qt_metacall(QMetaObject::InvokeMetaMethod, d->methodindex, &voidstarargs[0]);
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("RESULT nr=%1").arg(r) );
#else
Q_UNUSED(r);
#endif
// eval the return-value
if(d->hasreturnvalue) {
int tp = d->returnTypeId;
if(tp == QVariant::UserType /*|| tp == QVariant::Invalid*/) {
tp = d->returnMetaTypeId;
//QObject* obj = (*reinterpret_cast< QObject*(*)>( variantargs[0]->toVoidStar() ));
}
result = QVariant(tp, variantargs[0]->toVoidStar());
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("Returnvalue id=%1 metamethod.typename=%2 variant.toString=%3 variant.typeName=%4").arg(tp).arg(metamethod.typeName()).arg(result.toString()).arg(result.typeName()) );
#endif
}
for(int idx = 1; idx < typelistcount; ++idx)
{
delete variantargs[idx];
}
return result;
}
}
/***************************************************************************
* rubycallcache.h
* This file is part of the KDE project
* copyright (C)2006 by Cyrille Berger (cberger@cberger.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Library General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
***************************************************************************/
#include <ruby.h>
#include <QVarLengthArray>
class QObject;
class QVariant;
namespace Kross {
class MetaType;
struct RubyCallCachePrivate;
class RubyCallCache {
public:
RubyCallCache(QObject* object, int methodindex, bool hasreturnvalue, int returnTypeId, int returnMetaTypeId, QVarLengthArray<int> variantargs);
~RubyCallCache();
QVariant execfunction( int argc, VALUE *argv );
private:
RubyCallCachePrivate* d;
};
}
......@@ -19,6 +19,8 @@
***************************************************************************/
#include "rubyextension.h"
#include "rubycallcache.h"
#include "rubyvariant.h"
#include "../core/metatype.h"
......@@ -53,6 +55,8 @@ namespace Kross {
QHash<QByteArray, int> m_properties;
/// The cached list of enumerations.
QHash<QByteArray, int> m_enumerations;
QHash<int, RubyCallCache*> callcache;
};
}
......@@ -135,6 +139,8 @@ VALUE RubyExtension::method_missing(int argc, VALUE *argv, VALUE self)
return RubyExtension::call_method_missing(extension, argc, argv);
}
VALUE RubyExtension::callMetaMethod(const QByteArray& funcname, int argc, VALUE *argv)
{
const int argumentcount = argc - 1;
......@@ -153,118 +159,87 @@ VALUE RubyExtension::callMetaMethod(const QByteArray& funcname, int argc, VALUE
return Qfalse;
}
QObject* object = d->m_object;
QMetaMethod metamethod = object->metaObject()->method( methodindex );
if(metamethod.parameterTypes().size() != argumentcount) {
bool found = false;
const int count = object->metaObject()->methodCount();
for(++methodindex; methodindex < count; ++methodindex) {
metamethod = object->metaObject()->method( methodindex );
const QString signature = metamethod.signature();
const QByteArray name = signature.left(signature.indexOf('(')).toLatin1();
if(name == funcname && metamethod.parameterTypes().size() == argumentcount) {
found = true;
break;
}
}
if(! found) {
krosswarning(QString("The function '%1' does not expect %2 arguments.").arg(funcname.constData()).arg(argumentcount));
return Qfalse;
}
}
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("QMetaMethod idx=%1 sig=%2 tag=%3 type=%4").arg(methodindex).arg(metamethod.signature()).arg(metamethod.tag()).arg(metamethod.typeName()) );
#endif
RubyCallCache* callobj = d->callcache[methodindex];
QVariant result;
if(!callobj)
{
QList<QByteArray> typelist = metamethod.parameterTypes();
const int typelistcount = typelist.count();
bool hasreturnvalue = strcmp(metamethod.typeName(),"") != 0;
// exact 1 returnvalue + 0..9 arguments
Q_ASSERT(typelistcount <= 10);
QVarLengthArray<MetaType*> variantargs( typelistcount + 1 );
QVarLengthArray<void*> voidstarargs( typelistcount + 1 );
// set the return value
if(hasreturnvalue) {
MetaType* returntype;
int typeId = QVariant::nameToType( metamethod.typeName() );
if(typeId != QVariant::Invalid) {
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("RubyExtension::callMetaMethod typeName=%1 variant.typeid=%2").arg(metamethod.typeName()).arg(typeId) );
#endif
returntype = new MetaTypeVariant< QVariant >( QVariant( (QVariant::Type) typeId ) );
QObject* object = d->m_object;
QMetaMethod metamethod = object->metaObject()->method( methodindex );
if(metamethod.parameterTypes().size() != argumentcount) {
bool found = false;
const int count = object->metaObject()->methodCount();
for(++methodindex; methodindex < count; ++methodindex) {
metamethod = object->metaObject()->method( methodindex );
const QString signature = metamethod.signature();
const QByteArray name = signature.left(signature.indexOf('(')).toLatin1();
if(name == funcname && metamethod.parameterTypes().size() == argumentcount) {
found = true;
break;
}
}
else {
typeId = QMetaType::type( metamethod.typeName() );
if(typeId == QMetaType::Void) {
if(! found) {
krosswarning(QString("The function '%1' does not expect %2 arguments.").arg(funcname.constData()).arg(argumentcount));
return Qfalse;
}
}
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("QMetaMethod idx=%1 sig=%2 tag=%3 type=%4").arg(methodindex).arg(metamethod.signature()).arg(metamethod.tag()).arg(metamethod.typeName()) );
#endif
{
QList<QByteArray> typelist = metamethod.parameterTypes();
const int typelistcount = typelist.count();
bool hasreturnvalue = strcmp(metamethod.typeName(),"") != 0;
// exact 1 returnvalue + 0..9 arguments
Q_ASSERT(typelistcount <= 10);
QVarLengthArray<MetaType*> variantargs( typelistcount + 1 );
QVarLengthArray<void*> voidstarargs( typelistcount + 1 );
QVarLengthArray<int> varianttypes( typelistcount + 1 );
// set the return type
int returnTypeId;
int returnMetaTypeId;
if(hasreturnvalue) {
returnTypeId = QVariant::nameToType( metamethod.typeName() );
if(returnTypeId != QVariant::Invalid) {
if(returnTypeId == QVariant::UserType)
{
returnMetaTypeId = QMetaType::type( metamethod.typeName() );
}
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("RubyExtension::callMetaMethod typeName=%1 metatype.typeid is QMetaType::Void").arg(metamethod.typeName()) );
krossdebug( QString("RubyExtension::callMetaMethod typeName=%1 variant.typeid=%2").arg(metamethod.typeName()).arg(returnTypeId) );
#endif
returntype = new MetaTypeVariant< QVariant >( QVariant() );
}
else {
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("RubyExtension::callMetaMethod typeName=%1 metatype.typeid=%2").arg(metamethod.typeName()).arg(typeId) );
#endif
//if (id != -1) {
void* myClassPtr = QMetaType::construct(typeId, 0);
//QMetaType::destroy(id, myClassPtr);
returntype = new MetaTypeVoidStar( typeId, myClassPtr );
returnMetaTypeId = QMetaType::type( metamethod.typeName() );
if(returnMetaTypeId == QMetaType::Void) {
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("RubyExtension::callMetaMethod typeName=%1 metatype.typeid is QMetaType::Void").arg(metamethod.typeName()) );
#endif
}
else {
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("RubyExtension::callMetaMethod typeName=%1 metatype.typeid=%2").arg(metamethod.typeName()).arg(returnMetaTypeId) );
#endif
}
}
}
variantargs[0] = returntype;
voidstarargs[0] = returntype->toVoidStar();
}
else {
variantargs[0] = 0;
voidstarargs[0] = (void*)0;
}
// set the arguments
int idx = 1;
for(; idx <= typelistcount; ++idx) {
MetaType* metatype = RubyMetaTypeFactory::create(typelist[idx - 1].constData(), argv[idx]);
if(! metatype) {
// Seems RubyMetaTypeFactory::create returned an invalid RubyType.
krosswarning( QString("RubyExtension::callMetaMethod Aborting cause RubyMetaTypeFactory::create returned NULL.") );
for(int i = 0; i < idx; ++i) // Clear already allocated instances.
delete variantargs[i];
return Qfalse; // abort execution.
}
variantargs[idx] = metatype;
voidstarargs[idx] = metatype->toVoidStar();
}
// call the method now
int r = object->qt_metacall(QMetaObject::InvokeMetaMethod, methodindex, &voidstarargs[0]);
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("RESULT nr=%1").arg(r) );
#else
Q_UNUSED(r);
#endif
// eval the return-value
if(hasreturnvalue) {
int tp = QVariant::nameToType( metamethod.typeName() );
if(tp == QVariant::UserType /*|| tp == QVariant::Invalid*/) {
tp = QMetaType::type( metamethod.typeName() );
//QObject* obj = (*reinterpret_cast< QObject*(*)>( variantargs[0]->toVoidStar() ));
// set the arguments types
int idx = 1;
for(; idx <= typelistcount; ++idx) {
varianttypes[idx ] = QVariant::nameToType(typelist[idx - 1].constData());
}
result = QVariant(tp, variantargs[0]->toVoidStar());
#ifdef KROSS_RUBY_EXTENSION_DEBUG
krossdebug( QString("Returnvalue id=%1 metamethod.typename=%2 variant.toString=%3 variant.typeName=%4").arg(tp).arg(metamethod.typeName()).arg(result.toString()).arg(result.typeName()) );
#endif
// Create a cache of the function call
callobj = new RubyCallCache(object, methodindex, hasreturnvalue, returnTypeId, returnMetaTypeId, varianttypes);
// finally free the PythonVariable instances
d->callcache[methodindex] = callobj;
}
// finally free the PythonVariable instances
for(int i = 0; i <= typelistcount; ++i)
delete variantargs[i];
}
result = callobj->execfunction(argc, argv);
return result.isNull() ? 0 : RubyType<QVariant>::toVALUE(result);
}
......
......@@ -211,6 +211,9 @@ MetaType* RubyMetaTypeFactory::create(const char* typeName, VALUE value)
#ifdef KROSS_RUBY_VARIANT_DEBUG
krossdebug( QString("RubyMetaTypeFactory::create typeName=%1 metatype.id=%2 variant.id=%3").arg(typeName).arg(QMetaType::type(typeName)).arg(typeId) );
#endif
return RubyMetaTypeFactory::create(typeId, value);
}
MetaType* RubyMetaTypeFactory::create(int typeId, VALUE value) {
switch(typeId) {
case QVariant::Int:
......@@ -267,7 +270,7 @@ MetaType* RubyMetaTypeFactory::create(const char* typeName, VALUE value)
//if(typeId == QVariant::Invalid) return new RubyVariantImpl<void>();
//return new RubyVariantImpl<QVariant>(v);
krosswarning( QString("RubyMetaTypeFactory::create Not possible to convert the VALUE to QVariant with '%1' and metaid '%2'").arg(typeName).arg(typeId) );
krosswarning( QString("RubyMetaTypeFactory::create Not possible to convert the VALUE to QVariant with '%1' and metaid '%2'").arg(QVariant::typeToName((QVariant::Type)typeId)).arg(typeId) );
return 0;
} break;
}
......
......@@ -315,6 +315,7 @@ namespace Kross {
{
public:
static MetaType* create(const char* typeName, VALUE valueect);
static MetaType* create(int typeId, VALUE valueect);
};
/// \internal
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment