Mercurial > projects > qtd
diff generator/jumptable.cpp @ 1:e78566595089
initial import
author | mandel |
---|---|
date | Mon, 11 May 2009 16:01:50 +0000 |
parents | |
children | 1349940724eb |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/generator/jumptable.cpp Mon May 11 16:01:50 2009 +0000 @@ -0,0 +1,369 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2008 Nokia. All rights reserved. +** +** This file is part of Qt Jambi. +** +** * Commercial Usage +* Licensees holding valid Qt Commercial licenses may use this file in +* accordance with the Qt Commercial License Agreement provided with the +* Software or, alternatively, in accordance with the terms contained in +* a written agreement between you and Nokia. +* +* +* GNU General Public License Usage +* Alternatively, this file may be used under the terms of the GNU +* General Public License versions 2.0 or 3.0 as published by the Free +* Software Foundation and appearing in the file LICENSE.GPL included in +* the packaging of this file. Please review the following information +* to ensure GNU General Public Licensing requirements will be met: +* http://www.fsf.org/licensing/licenses/info/GPLv2.html and +* http://www.gnu.org/copyleft/gpl.html. In addition, as a special +* exception, Nokia gives you certain additional rights. These rights +* are described in the Nokia Qt GPL Exception version 1.2, included in +* the file GPL_EXCEPTION.txt in this package. +* +* Qt for Windows(R) Licensees +* As a special exception, Nokia, as the sole copyright holder for Qt +* Designer, grants users of the Qt/Eclipse Integration plug-in the +* right for the Qt/Eclipse Integration to link to functionality +* provided by Qt Designer and its related libraries. +* +* +* If you are unsure which license is appropriate for your use, please +* contact the sales department at qt-sales@nokia.com. + +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "jumptable.h" +#include "cppimplgenerator.h" +#include "reporthandler.h" +#include "fileout.h" + + +static QHash<QString, QString> shortNames; +static QHash<char, QString> expandNamesJNI; +static QHash<char, QString> expandNamesJava; + +bool JumpTableGenerator::active = false; + +static QString simplifyName(const QString &name, const QString &context, const QString &funcName) +{ + if (shortNames.size() == 0) { + shortNames.insert("jboolean", "Z"); + shortNames.insert("jbyte", "B"); + shortNames.insert("jchar", "C"); + shortNames.insert("jshort", "S"); + shortNames.insert("jint", "I"); + shortNames.insert("jlong", "J"); + shortNames.insert("jfloat", "F"); + shortNames.insert("jdouble", "D"); + shortNames.insert("jobject", "L"); + shortNames.insert("void", "V"); + + // Because QBool is specialcased in the typesystem to do + // automatic conversions from between bool and jboolean, we + // need to handle bool specially here. + shortNames.insert("bool", "Z"); + } + + QString sn = ((const QHash<QString, QString> &) shortNames).value(name); + if (sn.isEmpty()) { + printf("Failed to translate to shortname: %s in %s :: %s\n", + qPrintable(name), + qPrintable(context), + qPrintable(funcName)); + } + + return shortNames.value(name); +} + +static QString expandNameJNI(const QChar &c) { + if (expandNamesJNI.size() == 0) { + expandNamesJNI.insert('Z', "jboolean"); + expandNamesJNI.insert('B', "jbyte"); + expandNamesJNI.insert('C', "jchar"); + expandNamesJNI.insert('S', "jshort"); + expandNamesJNI.insert('I', "jint"); + expandNamesJNI.insert('J', "jlong"); + expandNamesJNI.insert('F', "jfloat"); + expandNamesJNI.insert('D', "jdouble"); + expandNamesJNI.insert('L', "jobject"); + expandNamesJNI.insert('V', "void"); + } + + QString n = ((const QHash<char, QString> &) expandNamesJNI).value(c.toLatin1()); + if (n.isEmpty()) + printf("Failed to translate to expanded names: %c\n", c.toLatin1()); + + return n; +} + +static QString expandNameJava(const QChar &c) { + if (expandNamesJava.size() == 0) { + expandNamesJava.insert('Z', "boolean"); + expandNamesJava.insert('B', "byte"); + expandNamesJava.insert('C', "char"); + expandNamesJava.insert('S', "short"); + expandNamesJava.insert('I', "int"); + expandNamesJava.insert('J', "long"); + expandNamesJava.insert('F', "float"); + expandNamesJava.insert('D', "double"); + expandNamesJava.insert('L', "Object"); + expandNamesJava.insert('V', "void"); + } + + QString n = ((const QHash<char, QString> &) expandNamesJava).value(c.toLatin1()); + if (n.isEmpty()) + printf("Failed to translate to expanded names: %c\n", c.toLatin1()); + + return n; +} + + +void JumpTablePreprocessor::generate() +{ + ReportHandler::setContext("JumpTablePreprocessor"); + foreach (AbstractMetaClass *cl, m_classes) { + process(cl); + } +} + +void JumpTablePreprocessor::process(AbstractMetaClass *cls) +{ + // Skip generate=no classes, such as QFutureIterator + if (cls->typeEntry()->codeGeneration() != TypeEntry::GenerateAll) { +// printf("skipping class: %s, generation is : %x vs %x\n", +// qPrintable(cls->name()), +// cls->typeEntry()->codeGeneration(), +// TypeEntry::GenerateAll); + return; + } + + QString package = cls->package(); + + if (!m_table.contains(package)) + m_table[package] = SignatureTable(); + + + SignatureTable &signatureList = m_table[package]; + + // Native callbacks (all java functions require native callbacks) + AbstractMetaFunctionList class_funcs = cls->functionsInTargetLang(); + foreach (AbstractMetaFunction *function, class_funcs) { + if (!function->isEmptyFunction()) + process(function, &signatureList); + } + + + class_funcs = cls->queryFunctions(AbstractMetaClass::NormalFunctions + | AbstractMetaClass::AbstractFunctions + | AbstractMetaClass::NotRemovedFromTargetLang); + foreach (AbstractMetaFunction *function, class_funcs) { + if (function->implementingClass() != cls) { + process(function, &signatureList); + } + } +} + + +QString JumpTablePreprocessor::signature(const AbstractMetaFunction *func) +{ + QString signature; + QString context = func->implementingClass()->name(); + QString functionSignature = func->signature(); + + if (func->argumentRemoved(0)) + signature = "V"; + else + signature = simplifyName(CppImplGenerator::jniReturnName(func), context, functionSignature); + + AbstractMetaArgumentList args = func->arguments(); + foreach (const AbstractMetaArgument *a, args) { + if (!func->argumentRemoved(a->argumentIndex() + 1)) { + if (!a->type()->hasNativeId()) + signature += simplifyName(CppImplGenerator::translateType(a->type(), EnumAsInts), + context, functionSignature); + else + signature += "J"; + } + } + + return signature; +} + + +void JumpTablePreprocessor::process(AbstractMetaFunction *func, SignatureTable *table) +{ + if (!func->needsCallThrough()) + return; + + + if (func->jumpTableId() >= 0) { +// printf("%s::%s already has an ID=%d, for declaring=%s, owner=%s\n", +// qPrintable(func->implementingClass()->name()), +// qPrintable(func->signature()), +// func->jumpTableId(), +// qPrintable(func->declaringClass()->name()), +// qPrintable(func->ownerClass()->name())); + return; + } + + QString sig = signature(func); + + AbstractMetaFunctionList &list = (*table)[sig]; + list.append(func); + func->setJumpTableId(list.size()); +} + + +JumpTableGenerator::JumpTableGenerator(JumpTablePreprocessor *pp, PriGenerator *pri) + : m_preprocessor(pp), + m_prigenerator(pri) +{ + active = true; +} + + +void JumpTableGenerator::generate() +{ + for (PackageJumpTable::const_iterator it = m_preprocessor->table()->constBegin(); + it != m_preprocessor->table()->constEnd(); ++it) { + QString package = it.key(); + generatePackage(package, it.value()); + } +} + + +void JumpTableGenerator::generatePackage(const QString &packageName, const SignatureTable &table) +{ + generateNativeTable(packageName, table); + generateJavaTable(packageName, table); +} + + +void JumpTableGenerator::generateJavaTable(const QString &packageName, + const SignatureTable &table) +{ + QString tableFile = QString("%1/%2/JTbl.java") + .arg(outputDirectory()) + .arg(QString(packageName).replace(".", "/")); + + printf("Generating jump table (.java): %s\n", qPrintable(tableFile)); + + FileOut file(tableFile); + + QTextStream &s = file.stream; + + s << "package " << packageName << ";" << endl << endl; + s << "class JTbl {" << endl; + + + for (SignatureTable::const_iterator sit = table.constBegin(); sit != table.constEnd(); ++sit) { + QString signature = sit.key(); + + QString ret = expandNameJava(signature.at(0)); + + s << " static native " << ret << " " << signature << "(int id, long nid"; + + for (int i=1; i<signature.size(); ++i) { + s << ", " << expandNameJava(signature.at(i)) << " a" << i; + } + + s << ", Object _this);" << endl; + } + + s << "}" << endl; +} + + +void JumpTableGenerator::generateNativeTable(const QString &packageName, + const SignatureTable &table) +{ + QString tableFile = QString("%1/%2/nativejumptable.cpp") + .arg(outputDirectory()) + .arg(CppGenerator::subDirectoryForPackage(packageName)); + + FileOut file(tableFile); + + QString pkgSubDir = QString(packageName).replace(".", "_"); + m_prigenerator->addSource(pkgSubDir + "/" + pkgSubDir + ".pri", "nativejumptable.cpp"); + + printf("Generating jump table (.cpp): %s\n", qPrintable(tableFile)); + + QTextStream &s = file.stream; + + s << "#include <qtjambi_global.h>" << endl; + + for (SignatureTable::const_iterator sit = table.constBegin(); sit != table.constEnd(); ++sit) { + QString signature = sit.key(); + + QString ret = expandNameJNI(signature.at(0)); + + s << endl << endl + << "extern \"C\" Q_DECL_EXPORT " << ret << " JNICALL QTJAMBI_FUNCTION_PREFIX(Java_" + << QString(packageName).replace("_", "_1").replace(".", "_") << "_JTbl_" << signature << ")" << endl + << "(JNIEnv *e, jclass, jint id, jlong nid"; + + for (int i=1; i<signature.size(); ++i) { + s << ", " << expandNameJNI(signature.at(i)) << " a" << i; + } + + s << ", jobject __this)" << endl + << "{" << endl + << "Q_UNUSED(__this);" << endl + << "Q_UNUSED(nid);" << endl + << "switch (id) { " << endl; + + AbstractMetaFunctionList functions = sit.value(); + bool hasReturn = signature.at(0) != 'V'; + + foreach (AbstractMetaFunction *f, functions) { + const AbstractMetaClass *cls = f->ownerClass(); + s << endl + << "// " << cls->name() << "::" << f->signature() << ", declaring=" << f->declaringClass()->name() << ", implementing=" << f->implementingClass()->name() << endl + << "case " << f->jumpTableId() << ":" << endl + << "extern "; + CppImplGenerator::writeFunctionName(s, f, cls, CppImplGenerator::ReturnType); + s << endl; + CppImplGenerator::writeFinalFunctionArguments(s, f); + s << ";" << endl; + + if (hasReturn && !f->isConstructor()) + s << "return "; + + CppImplGenerator::writeFunctionName(s, f, cls, 0); + + s << "(e"; + + if (f->isStatic()) + s << ", 0"; + else if (f->isConstructor()) + s << ", __this"; + else + s << ", __this, nid"; + + for (int i=1; i<signature.size(); ++i) { + s << ", a" << i; + } + + s << ");" << endl + << "break;" << endl; + } + + s << "} // switch..." << endl; + + if (hasReturn) + s << "return 0;" << endl; + + s << "} // " << signature << endl; + } +} + +bool JumpTableGenerator::isJumpTableActive() { + return active; +}