From 82fe464b9412ab86c670ceedac7bd599aea5801c Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Wed, 16 Nov 2011 19:36:41 +0000 Subject: [PATCH 1/5] Updated darwin/MacOS X makefile with compiler optimizations --- .gitignore | 9 ++++++++- buildscripts/config.darwin.makefile | 14 +++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index a5c135c..0b5fb0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ *.obj *.class -*.bak \ No newline at end of file +*.bak +*.o +*.lib +*~ +*.jar +java/cppjvm/java_*.cpp +java/cppjvm/include/java/* +bin/* \ No newline at end of file diff --git a/buildscripts/config.darwin.makefile b/buildscripts/config.darwin.makefile index 330c678..fdea2e6 100644 --- a/buildscripts/config.darwin.makefile +++ b/buildscripts/config.darwin.makefile @@ -1,9 +1,17 @@ -thirdparty_platform = linux +thirdparty_platform = macosx compiler = g++ compiler_global_flags = -c -DPOSIX -compiler_object_name_prefix = -o +#compiler_global_flags += -g +compiler_global_flags += -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/ +compiler_global_flags += -O3 -Os +compiler_global_flags += -fno-stack-protector -funsafe-loop-optimizations +compiler_global_flags += -U_FORTIFY_SOURCE + +#compiler_global_flags += -arch x86_64 + +compiler_object_name_prefix = -o compiler_object_suffix = .o staticlib_suffix = .lib @@ -12,7 +20,7 @@ static_linker_global_flags = -static static_linker_output_name_prefix = -o executable_linker = g++ -executable_linker_global_flags = +executable_linker_global_flags = -framework JavaVM executable_linker_output_name_prefix = -o executable_linker_library_path_prefix = -L executable_linker_library_name_prefix = From 714864fd0ddb51811152d8e31e6f86a789c6a7cb Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Wed, 16 Nov 2011 19:36:58 +0000 Subject: [PATCH 2/5] Fixed array compilation --- java/jniutil/include/jvm/array.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/jniutil/include/jvm/array.hpp b/java/jniutil/include/jvm/array.hpp index 3032c6e..c2db6f6 100644 --- a/java/jniutil/include/jvm/array.hpp +++ b/java/jniutil/include/jvm/array.hpp @@ -126,7 +126,7 @@ namespace jvm } }; - accessor_ operator[](jsize index) const + accessor_ operator[](jlong index) const { return accessor_(*this, index); } accessor_ operator[](int index) const // VC++2008 needs this when using int literals { return accessor_(*this, index); } From c1dd602a563bde39630a1798231cb6b788d009fd Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Wed, 16 Nov 2011 19:38:32 +0000 Subject: [PATCH 3/5] Added cache for JNI classes' jclass & jmethodIDs --- java/jniutil/class_cache.cpp | 195 ++++++++++++++++++++++ java/jniutil/include/impl/class_cache.hpp | 68 ++++++++ 2 files changed, 263 insertions(+) create mode 100644 java/jniutil/class_cache.cpp create mode 100644 java/jniutil/include/impl/class_cache.hpp diff --git a/java/jniutil/class_cache.cpp b/java/jniutil/class_cache.cpp new file mode 100644 index 0000000..b57bf9d --- /dev/null +++ b/java/jniutil/class_cache.cpp @@ -0,0 +1,195 @@ +#include +#include + +/* + * class_cache implementation + */ + +void cppjvm::impl::class_cache::alloc() { +#ifdef ARRAY_BASED_CLASS_CACHE + if (m_constructors) + return; + + m_constructors = new jmethodID[m_constructorCount]; + m_methods = new jmethodID[m_methodCount]; + + memset(m_constructors, 0, sizeof(jmethodID) * m_constructorCount); + memset(m_methods, 0, sizeof(jmethodID) * m_methodCount); +#endif +} +cppjvm::impl::class_cache::class_cache(const char* className, int constructorCount, int methodCount) : +#ifdef ARRAY_BASED_CLASS_CACHE + m_methodCount(methodCount), m_constructorCount(constructorCount), + m_methods(NULL), m_constructors(NULL), +#endif + m_className(className), + m_class(NULL) +{ +} +cppjvm::impl::class_cache::~class_cache() { + JNIEnv* env = ::jvm::global_vm().env(); + if (env && m_class) + env->DeleteGlobalRef(m_class); + +#ifdef ARRAY_BASED_CLASS_CACHE + delete[] m_constructors; + delete[] m_methods; +#endif +} +jclass cppjvm::impl::class_cache::get_class(JNIEnv* env) { + if (!m_class) { + jclass cls; + if (!env) + env = ::jvm::global_vm().env(); + cls = env->FindClass(m_className); + if (!cls) + throw std::logic_error("Unknown class !"); + m_class = (jclass)env->NewGlobalRef(cls); + } + return m_class; +} +jmethodID cppjvm::impl::class_cache::getMethod(int index, MethodCacheType& cache/*, int cacheSize*/, const char* name, const char* signature, JNIEnv* env, bool isStatic) +{ + jmethodID m; + + //if (index < 0 || index >= cacheSize) + // throw std::logic_error("Invalid index in jmethodID cache array !"); + + if (!(m = cache[index])) + { + jclass cls; + if (!env) + env = ::jvm::global_vm().env(); + cls = get_class(env); + cache[index] = m = (isStatic ? + env->GetStaticMethodID(cls, name, signature) : + env->GetMethodID(cls, name, signature) + ); + } + if (!m) + throw std::logic_error("Unknown method !"); + return m; +} + +jmethodID cppjvm::impl::class_cache::getConstructor(int index, const char* signature, JNIEnv* env) +{ + alloc(); + return getMethod(index, m_constructors/*, m_constructorCount*/, "", signature, env, false); +} +jmethodID cppjvm::impl::class_cache::getMethod(int index, const char* name, const char* signature, JNIEnv* env, bool isStatic) +{ + alloc(); + return getMethod(index, m_methods/*, m_methodCount*/, name, signature, env, isStatic); +} +jmethodID cppjvm::impl::class_cache::getStaticMethod(int index, const char* name, const char* signature, JNIEnv* env) +{ + return getMethod(index, name, signature, env, true); +} + +#define CALL_IMPL(jtype, typeName) \ + jtype ::cppjvm::impl::class_cache::Call ## typeName ## Method(int index, const char* name, const char* signature, jobject instance, ...) \ + { \ + JNIEnv *env = ::jvm::global_vm().env(); \ + jmethodID m = getMethod(index, name, signature, env); \ + jtype ret; \ + va_list args; \ + va_start(args, instance); \ + ret = env->Call ## typeName ## MethodV(instance, m, args); \ + va_end(args); \ + ::jvm::global_vm().check_exception(env); \ + return ret; \ + } + +#define STATIC_CALL_IMPL(jtype, typeName) \ + jtype ::cppjvm::impl::class_cache::CallStatic ## typeName ## Method(int index, const char* name, const char* signature, ...) \ + { \ + JNIEnv *env = ::jvm::global_vm().env(); \ + jmethodID m = getStaticMethod(index, name, signature, env); \ + jclass c = get_class(env); \ + jtype ret; \ + va_list args; \ + va_start(args, signature); \ + ret = env->CallStatic ## typeName ## MethodV(c, m, args); \ + va_end(args); \ + ::jvm::global_vm().check_exception(env); \ + return ret; \ + } + +#define CALL_IMPLS(jtype, typeName) \ + CALL_IMPL(jtype, typeName); \ + STATIC_CALL_IMPL(jtype, typeName); + +CALL_IMPLS( jint , Int ); +CALL_IMPLS( jshort , Short ); +CALL_IMPLS( jlong , Long ); +CALL_IMPLS( jbyte , Byte ); +CALL_IMPLS( jchar , Char ); +CALL_IMPLS( jdouble , Double ); +CALL_IMPLS( jfloat , Float ); +CALL_IMPLS( jobject , Object ); +CALL_IMPLS( jboolean , Boolean ); + +/* +jobject ::cppjvm::impl::class_cache::CallStaticObjectMethod(int index, const char* name, const char* signature, ...) +{ + JNIEnv *env = ::jvm::global_vm().env(); + jmethodID m = getStaticMethod(index, name, signature, env); + jclass c = get_class(env); + jobject ret; + va_list args; + va_start(args, signature); + ret = env->CallStaticObjectMethodV(c, m, args); + va_end(args); + ::jvm::global_vm().check_exception(env); + return ret; +} + +jobject ::cppjvm::impl::class_cache::CallObjectMethod(int index, const char* name, const char* signature, jobject instance, ...) +{ + JNIEnv *env = ::jvm::global_vm().env(); + jmethodID m = getMethod(index, name, signature, env); + jobject ret; + va_list args; + va_start(args, signature); + ret = env->CallObjectMethodV(instance, m, args); + va_end(args); + ::jvm::global_vm().check_exception(env); + return ret; +} +*/ +void ::cppjvm::impl::class_cache::CallVoidMethod(int index, const char* name, const char* signature, jobject instance, ...) +{ + JNIEnv *env = ::jvm::global_vm().env(); + jmethodID m = getMethod(index, name, signature, env); + va_list args; + va_start(args, instance); + env->CallVoidMethodV(instance, m, args); + va_end(args); + ::jvm::global_vm().check_exception(env); +} + +void ::cppjvm::impl::class_cache::CallStaticVoidMethod(int index, const char* name, const char* signature, ...) +{ + JNIEnv *env = ::jvm::global_vm().env(); + jmethodID m = getStaticMethod(index, name, signature, env); + jclass c = get_class(env); + va_list args; + va_start(args, signature); + env->CallStaticVoidMethodV(c, m, args); + va_end(args); + ::jvm::global_vm().check_exception(env); +} + +jobject ::cppjvm::impl::class_cache::NewObject(int index, const char* signature, ...) +{ + JNIEnv *env = ::jvm::global_vm().env(); + jmethodID m = getConstructor(index, signature, env); + jclass c = get_class(env); + jobject ret; + va_list args; + va_start(args, signature); + ret = env->NewObject(c, m, args); + va_end(args); + ::jvm::global_vm().check_exception(env); + return ret; +} diff --git a/java/jniutil/include/impl/class_cache.hpp b/java/jniutil/include/impl/class_cache.hpp new file mode 100644 index 0000000..de8cf65 --- /dev/null +++ b/java/jniutil/include/impl/class_cache.hpp @@ -0,0 +1,68 @@ +#ifndef CPPJVM_IMPL_CLASS_CACHE_INCLUDED +#define CPPJVM_IMPL_CLASS_CACHE_INCLUDED + +//#include +#include +#include + +//#define ARRAY_BASED_CLASS_CACHE + +namespace cppjvm +{ +namespace impl +{ + class class_cache + { +#ifdef ARRAY_BASED_CLASS_CACHE + typedef jmethodID* MethodCacheType; + int m_methodCount, m_constructorCount; +#else + typedef std::map MethodCacheType; +#endif + MethodCacheType m_constructors, m_methods; + + const char* m_className; + jclass m_class; + + void alloc(); + jmethodID getMethod(int index, MethodCacheType& cache/*, int cacheSize*/, const char* name, const char* signature, JNIEnv* env, bool isStatic); + + jmethodID getConstructor(int index, const char* signature, JNIEnv* env = NULL); + jmethodID getMethod(int index, const char* name, const char* signature, JNIEnv* env = NULL, bool isStatic = false); + jmethodID getStaticMethod(int index, const char* name, const char* signature, JNIEnv* env = NULL); + + + public: + class_cache(const char* className, int constructorCount, int methodCount); + ~class_cache(); + + jclass get_class(JNIEnv* env = NULL); + + jobject NewObject(int index, const char* signature, ...); + + jint CallIntMethod(int index, const char* name, const char* signature, jobject instance, ...); + jshort CallShortMethod(int index, const char* name, const char* signature, jobject instance, ...); + jlong CallLongMethod(int index, const char* name, const char* signature, jobject instance, ...); + jbyte CallByteMethod(int index, const char* name, const char* signature, jobject instance, ...); + jchar CallCharMethod(int index, const char* name, const char* signature, jobject instance, ...); + jboolean CallBooleanMethod(int index, const char* name, const char* signature, jobject instance, ...); + jdouble CallDoubleMethod(int index, const char* name, const char* signature, jobject instance, ...); + jfloat CallFloatMethod(int index, const char* name, const char* signature, jobject instance, ...); + void CallVoidMethod(int index, const char* name, const char* signature, jobject instance, ...); + jobject CallObjectMethod(int index, const char* name, const char* signature, jobject instance, ...); + + jint CallStaticIntMethod(int index, const char* name, const char* signature, ...); + jshort CallStaticShortMethod(int index, const char* name, const char* signature, ...); + jlong CallStaticLongMethod(int index, const char* name, const char* signature, ...); + jbyte CallStaticByteMethod(int index, const char* name, const char* signature, ...); + jchar CallStaticCharMethod(int index, const char* name, const char* signature, ...); + jboolean CallStaticBooleanMethod(int index, const char* name, const char* signature, ...); + jdouble CallStaticDoubleMethod(int index, const char* name, const char* signature, ...); + jfloat CallStaticFloatMethod(int index, const char* name, const char* signature, ...); + void CallStaticVoidMethod(int index, const char* name, const char* signature, ...); + jobject CallStaticObjectMethod(int index, const char* name, const char* signature, ...); + }; +} +} + +#endif // CPPJVM_IMPL_CLASS_CACHE_INCLUDED From e455d8cf32b1bf26287db1866cc6425f91766fd6 Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Wed, 16 Nov 2011 19:39:55 +0000 Subject: [PATCH 4/5] Changed code generation to use class_cache (& shrink size of object code for each wrapped class) --- .../cppjvm/cppwrap/HeaderGenerator.java | 106 ++++++++++++------ .../cppwrap/ImplementationGenerator.java | 83 ++++++-------- .../cppjvm/cppwrap/SourceGenerator.java | 8 +- 3 files changed, 113 insertions(+), 84 deletions(-) diff --git a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/HeaderGenerator.java b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/HeaderGenerator.java index 3ecdc71..611c998 100644 --- a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/HeaderGenerator.java +++ b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/HeaderGenerator.java @@ -6,7 +6,7 @@ import java.io.*; public class HeaderGenerator extends SourceGenerator { - public void generate() throws Exception { + public void generate() throws Exception { beginIncludeGuard(); globalIncludes(); forwardDeclareRequiredTypes(); @@ -45,6 +45,8 @@ protected void globalIncludes() { out().println("#include "); out().println("#include "); out().println("#include "); + if (!putDefinitionsInHeaders) + out().println("#include "); } protected void forwardDeclareRequiredTypes() throws Exception { @@ -57,6 +59,8 @@ protected void beginClass() { out().println(); out().println("class " + cls().getSimpleName() + " : public ::jvm::object"); out().println("{"); + if (putDefinitionsInHeaders) + out().println(" static cppjvm::impl::class_cache s_impl_cache;"); out().println("public:"); // Can construct from a jobject, but not implicitly to avoid accidental unsafe conversion @@ -77,29 +81,44 @@ protected void endClass() { } protected void declareConstructors() throws Exception { - for (Constructor ctor : cls().getConstructors()) { - Class[] params = ctor.getParameterTypes(); - - // void new_(params...); - out().print(" void new_("); - listParameters(params, DECLARE_TYPES); - out().println(");"); - - // For non-default and non-copy constructors only: - if ((params.length > 1) || - ((params.length == 1) && !params[0].equals(cls()))) { - - // Make an actual C++ constructor - out().print(" explicit " + cls().getSimpleName() + "("); - listParameters(params, DECLARE_TYPES); - out().println(")"); - out().println(" {"); - out().print(" new_("); - listParameters(params, CALL_WRAPPED); - out().println(");"); - out().println(" }"); - } - } + if (putDefinitionsInHeaders) { + out().println(indent(new ImplementationGenerator() { + @Override + public void generate() throws Exception { + defineConstructors(); + } + @Override + protected boolean isInHeader() { + return true; + } + @Override + protected void editWarning() {} + }.toString(cls()))); + } else { + for (Constructor ctor : cls().getConstructors()) { + Class[] params = ctor.getParameterTypes(); + + // void new_(params...); + out().print(" void new_("); + listParameters(params, DECLARE_TYPES); + out().println(");"); + + // For non-default and non-copy constructors only: + if ((params.length > 1) || + ((params.length == 1) && !params[0].equals(cls()))) { + + // Make an actual C++ constructor + out().print(" explicit " + cls().getSimpleName() + "("); + listParameters(params, DECLARE_TYPES); + out().println(")"); + out().println(" {"); + out().print(" new_("); + listParameters(params, CALL_WRAPPED); + out().println(");"); + out().println(" }"); + } + } + } } protected void declareConversions() throws Exception { @@ -109,18 +128,33 @@ protected void declareConversions() throws Exception { } protected void declareMethods() throws Exception { - for (Method m : cls().getMethods()) { - if (m.isSynthetic()) - continue; - - // [static] return-type methodName(params...) [const]; - out().print(" " + - (Modifier.isStatic(m.getModifiers()) ? "static " : "") + - CppWrap.cppType(m.getReturnType()) + " " + - CppWrap.fixName(m.getName()) + "("); - listParameters(m.getParameterTypes(), DECLARE_TYPES); - out().println(Modifier.isStatic(m.getModifiers()) ? ");" : ") const;"); - } + if (putDefinitionsInHeaders) + out().println(indent(new ImplementationGenerator() { + @Override + public void generate() throws Exception { + defineMethods(); + } + @Override + protected boolean isInHeader() { + return true; + } + @Override + protected void editWarning() {} + }.toString(cls()))); + else { + for (Method m : cls().getMethods()) { + if (m.isSynthetic()) + continue; + + // [static] return-type methodName(params...) [const]; + out().print(" " + + (Modifier.isStatic(m.getModifiers()) ? "static " : "") + + CppWrap.cppType(m.getReturnType()) + " " + + CppWrap.fixName(m.getName()) + "("); + listParameters(m.getParameterTypes(), DECLARE_TYPES); + out().println(Modifier.isStatic(m.getModifiers()) ? ");" : ") const;"); + } + } } protected void declareSpecialStringFeatures() { diff --git a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/ImplementationGenerator.java b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/ImplementationGenerator.java index a2a37a9..8f63c23 100644 --- a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/ImplementationGenerator.java +++ b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/ImplementationGenerator.java @@ -9,12 +9,17 @@ public class ImplementationGenerator extends SourceGenerator { public void generate() throws Exception { include(cls()); // include our own header, obviously + if (putDefinitionsInHeaders) + out().println("#include "); + includeRequiredTypes(); beginNamespace(cls()); classInfo(); - defineConstructors(); - defineConversions(); - defineMethods(); + if (!putDefinitionsInHeaders) { + defineConstructors(); + defineMethods(); + } + defineConversions(); endNamespace(cls()); } @@ -25,48 +30,39 @@ protected void includeRequiredTypes() throws Exception { } protected void classInfo() throws Exception { - out().println("static jclass cached_class = 0;"); - out().println("jclass " + cls().getSimpleName() + "::get_class()"); + Class c = cls(); + + if (putDefinitionsInHeaders) + out().print(c.getSimpleName() + "::"); + else + out().print("static cppjvm::impl::class_cache "); + out().println("s_impl_cache(" + + "\"" + c.getName().replace('.', '/') + "\", " + + c.getConstructors().length + ", " + + c.getMethods().length + + ");"); + out().println("jclass " + c.getSimpleName() + "::get_class()"); out().println("{"); - out().println(" if (cached_class == 0)"); - out().println(" {"); - out().print(" cached_class = ::jvm::global_vm().env()->FindClass(\""); - out().print(cls().getName().replace('.', '/')); - out().println("\");"); - out().println(" cached_class = (jclass)::jvm::global_vm().env()->NewGlobalRef(cached_class);"); - out().println(" }"); - out().println(" return cached_class;"); + out().println(" return s_impl_cache.get_class();"); out().println("}"); - - out().println("static jmethodID cached_constructors[" + (cls().getConstructors().length + 1) + "];"); - out().println("static jmethodID cached_methods[" + (cls().getMethods().length + 1) + "];"); } protected void defineConstructors() throws Exception { int pos = 0; for (Constructor ctor : cls().getConstructors()) { // void ClassName::new_(params...) - out().print("void " + cls().getSimpleName() + "::new_("); + out().print("void " + (isInHeader() ? "" : cls().getSimpleName() + "::") + "new_("); listParameters(ctor.getParameterTypes(), DECLARE_TYPES); out().println(")"); out().println("{"); - out().println(" JNIEnv *env = ::jvm::global_vm().env();"); - - out().println(" jmethodID i = cached_constructors[" + pos + "];"); - out().println(" if (i == 0)"); - out().println(" {"); - out().println(" i = env->GetMethodID(get_class(), \"\", \"" + - Signature.generate(ctor) + "\");"); - out().println(" cached_constructors[" + pos + "] = i;"); - out().println(" }"); out().print( - " ::jvm::object::put_impl(env->NewObject(get_class(), i" + + " ::jvm::object::put_impl(s_impl_cache.NewObject(" + pos + ", \"" + Signature.generate(ctor) + "\"" + (ctor.getParameterTypes().length != 0 ? ", " : "") ); listParameters(ctor.getParameterTypes(), CALL_UNWRAPPED); out().println("));"); - out().println(" ::jvm::global_vm().check_exception(env);"); + //out().println(" ::jvm::global_vm().check_exception(env);"); out().println("}"); pos++; @@ -82,8 +78,11 @@ protected void defineConversions() throws Exception { } } + protected boolean isInHeader() { + return false; + } protected void defineMethods() throws Exception { - int pos = 0; + int pos = 0; for (Method m : cls().getMethods()) { if (m.isSynthetic()) continue; @@ -95,24 +94,12 @@ protected void defineMethods() throws Exception { // return-type ClassName::methodName(params...) [const] out().print(CppWrap.cppType(returns) + " " + - cls().getSimpleName() + "::" + + (isInHeader() ? "" : cls().getSimpleName() + "::") + CppWrap.fixName(m.getName()) + "("); listParameters(params, DECLARE_TYPES); out().println(isStatic ? ")" : ") const"); out().println("{"); - out().println(" JNIEnv *env = ::jvm::global_vm().env();"); - - out().println(" jmethodID i = cached_methods[" + pos + "];"); - out().println(" if (i == 0)"); - out().println(" {"); - out().println(" i = env->Get" + - (isStatic ? "Static" : "") + - "MethodID(get_class(), \"" + m.getName() + - "\", \"" + Signature.generate(m) + "\");"); - out().println(" cached_methods[" + pos + "] = i;"); - out().println(" }"); - String returnFlavour = returns.isPrimitive() ? (Character.toUpperCase(returns.toString().charAt(0)) + returns.toString().substring(1)) @@ -124,15 +111,17 @@ protected void defineMethods() throws Exception { ? "" : (CppWrap.cppType(returns) + " ret" + (CppWrap.isWrapped(returns) ? "(" : " = ")) ) + - "env->Call" + - (isStatic ? "Static" : "") + returnFlavour + - (isStatic ? "Method(get_class(), i" : "Method(::jvm::object::get_impl(), i") + + "s_impl_cache.Call" + + (isStatic ? "Static" : "") + returnFlavour + "Method(" + + pos + ", " + + "\"" + m.getName() + "\", " + + "\"" + Signature.generate(m) + "\"" + + (isStatic ? "" : ", ::jvm::object::get_impl()") + (params.length != 0 ? ", " : "") ); listParameters(params, CALL_UNWRAPPED); out().println(CppWrap.isWrapped(returns) ? "));" : ");"); - out().println(" ::jvm::global_vm().check_exception(env);"); - + if (!returnsVoid) { out().println(CppWrap.isWrapped(returns) ? " return ret;" diff --git a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/SourceGenerator.java b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/SourceGenerator.java index 8363824..d874eaf 100644 --- a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/SourceGenerator.java +++ b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/SourceGenerator.java @@ -9,6 +9,12 @@ public abstract class SourceGenerator { private PrintWriter writer; private Class source; + public static boolean putDefinitionsInHeaders = false; + + public String indent(String s) { + String indent = " "; + return indent + s.replaceAll("\n", "\n" + indent); + } public String toString(Class cls) throws Exception { source = cls; final Writer result = new StringWriter(); @@ -28,7 +34,7 @@ protected Class cls() { public abstract void generate() throws Exception; - private void editWarning() { + protected void editWarning() { out().println(); out().println("//"); out().println("// Do not edit this file - it was generated automatically from the Java class:"); From e1feb48eee3396d3a5ecb539de467c0a8643cba0 Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Thu, 17 Nov 2011 00:11:35 +0000 Subject: [PATCH 5/5] Use C++ inheritance in generated wrappers : avoids many duplicates and produces lighter code (only Object defines hashCode(), for instance), except when there are overloads (in which case superclass methods are redefined in sub-classes, as we cannot use virtual inheritance with by-value returns) --- .../com/earwicker/cppjvm/cppwrap/CppWrap.java | 22 ++++++++--- .../cppjvm/cppwrap/HeaderGenerator.java | 35 +++++++++++++---- .../cppwrap/ImplementationGenerator.java | 20 +++++++--- .../cppjvm/cppwrap/SourceGenerator.java | 38 ++++++++++++++++++- 4 files changed, 95 insertions(+), 20 deletions(-) diff --git a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/CppWrap.java b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/CppWrap.java index c026d1f..9ff3005 100644 --- a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/CppWrap.java +++ b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/CppWrap.java @@ -27,28 +27,38 @@ public class CppWrap { } - public static String cppType(Class j) throws Exception { + public static String cppType(Class j) {//throws Exception { if (j == null) + //j = Object.class; return "jobject"; if (j.isPrimitive()) { String g = primitives.get(j); - return g == null ? "jobject" : g; + if (g != null) + return g; + //return g == null ? "jobject" : g; } if (j.isArray()) return "::jvm::array< " + cppType(j.getComponentType()) + " >"; // very poor support for nested classes! - if (j.getDeclaringClass() != null) - return "jobject"; + if (!shouldGenerate(j))//j.getDeclaringClass() != null) + j = Object.class; + //return "jobject"; return "::" + j.getName().replaceAll("\\.", "::"); } + public static boolean shouldGenerate(Class cls) { + String n = cls.getName(); + if (n.startsWith("sun.")) + return false; + return cls.getDeclaringClass() == null; + } public static boolean isWrapped(Class cls) { // Can't wrap nested classes yet... - return !cls.isPrimitive() && cls.getDeclaringClass() == null; + return !cls.isPrimitive();// && cls.getDeclaringClass() == null; } public static String fixName(String name) { @@ -88,7 +98,7 @@ public static int saveIfDifferent(String path, String content) throws Exception public static int generate(Class cls, File out) throws Exception { int generated = 0; - if (!isWrapped(cls)) + if (!CppWrap.shouldGenerate(cls) || !isWrapped(cls)) return generated; char sl = File.separatorChar; diff --git a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/HeaderGenerator.java b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/HeaderGenerator.java index 611c998..0def860 100644 --- a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/HeaderGenerator.java +++ b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/HeaderGenerator.java @@ -9,6 +9,7 @@ public class HeaderGenerator extends SourceGenerator { public void generate() throws Exception { beginIncludeGuard(); globalIncludes(); + includeParentType(); forwardDeclareRequiredTypes(); beginNamespace(cls()); beginClass(); @@ -22,7 +23,7 @@ public void generate() throws Exception { } protected void forwardDeclare(Class cls) { - if (!CppWrap.isWrapped(cls)) + if (!CppWrap.shouldGenerate(cls) || !CppWrap.isWrapped(cls)) return; beginNamespace(cls); @@ -48,6 +49,14 @@ protected void globalIncludes() { if (!putDefinitionsInHeaders) out().println("#include "); } + + protected void includeParentType() { + Class superclass = cls().getSuperclass(); + if (superclass == null) + return; + + out().println("#include <" + superclass.getName().replace('.', '/') + ".hpp>"); + } protected void forwardDeclareRequiredTypes() throws Exception { for (Class required : CppWrap.getDirectlyRequiredTypes(cls())) { @@ -57,14 +66,21 @@ protected void forwardDeclareRequiredTypes() throws Exception { protected void beginClass() { out().println(); - out().println("class " + cls().getSimpleName() + " : public ::jvm::object"); + Class superclass = cls().getSuperclass(); + String superclassCppName; + if (superclass == null) { + superclassCppName = "::jvm::object"; + } else { + superclassCppName = CppWrap.cppType(superclass);//"::" + superclass.getName().replaceAll("\\.", "::"); + } + out().println("class " + cls().getSimpleName() + " : public " + superclassCppName); out().println("{"); if (putDefinitionsInHeaders) out().println(" static cppjvm::impl::class_cache s_impl_cache;"); out().println("public:"); // Can construct from a jobject, but not implicitly to avoid accidental unsafe conversion - out().println(" explicit " + cls().getSimpleName() + "(jobject jobj) : object(jobj) {}"); + out().println(" explicit " + cls().getSimpleName() + "(jobject jobj) : " + superclassCppName + "(jobj) {}"); out().println(" static jclass get_class();"); @@ -73,7 +89,7 @@ protected void beginClass() { // Copy constructor: copy reference out().println(" " + cls().getSimpleName() + "(const " + cls().getSimpleName() + " &other)"); - out().println(" : object(other.get_impl()) {}"); + out().println(" : " + superclassCppName + "(other.get_impl()) {}"); } protected void endClass() { @@ -122,8 +138,13 @@ protected void editWarning() {} } protected void declareConversions() throws Exception { + String dummy = CppWrap.cppType(Object.class); for (Class st : CppWrap.getSuperTypes(cls())) { - out().println(" operator " + CppWrap.cppType(st) + "() const;"); + String conv = CppWrap.cppType(st); + if (conv.equals(dummy)) + continue; + + out().println(" operator " + CppWrap.cppType(st) + "() const;"); } } @@ -142,13 +163,13 @@ protected boolean isInHeader() { protected void editWarning() {} }.toString(cls()))); else { - for (Method m : cls().getMethods()) { + for (Method m : methods()) { if (m.isSynthetic()) continue; // [static] return-type methodName(params...) [const]; out().print(" " + - (Modifier.isStatic(m.getModifiers()) ? "static " : "") + + (Modifier.isStatic(m.getModifiers()) ? "static " : ""/*"virtual "*/) + CppWrap.cppType(m.getReturnType()) + " " + CppWrap.fixName(m.getName()) + "("); listParameters(m.getParameterTypes(), DECLARE_TYPES); diff --git a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/ImplementationGenerator.java b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/ImplementationGenerator.java index 8f63c23..e88a2ee 100644 --- a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/ImplementationGenerator.java +++ b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/ImplementationGenerator.java @@ -39,7 +39,7 @@ protected void classInfo() throws Exception { out().println("s_impl_cache(" + "\"" + c.getName().replace('.', '/') + "\", " + c.getConstructors().length + ", " + - c.getMethods().length + + methods().length + ");"); out().println("jclass " + c.getSimpleName() + "::get_class()"); out().println("{"); @@ -70,11 +70,16 @@ protected void defineConstructors() throws Exception { } protected void defineConversions() throws Exception { + String dummy = CppWrap.cppType(Object.class); for (Class st : CppWrap.getSuperTypes(cls())) { - out().println(cls().getSimpleName() + "::operator " + CppWrap.cppType(st) + "() const"); - out().println("{"); - out().println(" return " + CppWrap.cppType(st) + "(get_impl());"); - out().println("}"); + String conv = CppWrap.cppType(st); + if (conv.equals(dummy)) + continue; + + out().println(cls().getSimpleName() + "::operator " + CppWrap.cppType(st) + "() const"); + out().println("{"); + out().println(" return " + CppWrap.cppType(st) + "(get_impl());"); + out().println("}"); } } @@ -83,7 +88,7 @@ protected boolean isInHeader() { } protected void defineMethods() throws Exception { int pos = 0; - for (Method m : cls().getMethods()) { + for (Method m : methods()) { if (m.isSynthetic()) continue; @@ -93,6 +98,9 @@ protected void defineMethods() throws Exception { Class[] params = m.getParameterTypes(); // return-type ClassName::methodName(params...) [const] + if (isInHeader()) + out().print(isStatic ? "static " : ""/*"virtual "*/); + out().print(CppWrap.cppType(returns) + " " + (isInHeader() ? "" : cls().getSimpleName() + "::") + CppWrap.fixName(m.getName()) + "("); diff --git a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/SourceGenerator.java b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/SourceGenerator.java index d874eaf..8d5a2e2 100644 --- a/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/SourceGenerator.java +++ b/java/cppwrap/src/com/earwicker/cppjvm/cppwrap/SourceGenerator.java @@ -15,6 +15,15 @@ public String indent(String s) { String indent = " "; return indent + s.replaceAll("\n", "\n" + indent); } + public boolean dependsOnlyOnPrimitives(Method m) { + if (!m.getReturnType().isPrimitive()) + return false; + for (Class c : m.getParameterTypes()) + if (!c.isPrimitive()) + return false; + + return true; + } public String toString(Class cls) throws Exception { source = cls; final Writer result = new StringWriter(); @@ -31,6 +40,33 @@ protected PrintWriter out() { protected Class cls() { return source; } + + static Set getMethodNames(Class c, boolean declaredMethodsOnly) { + Set names = new HashSet(); + if (c != null) + for (Method m : (declaredMethodsOnly ? c.getDeclaredMethods() : c.getMethods())) + names.add(m.getName()); + return names; + } + Method[] methods; + protected Method[] methods() { + if (methods == null) { + Class cls = cls(); + Set parentMethodNames = getMethodNames(cls.getSuperclass(), false); + Set declaredMethodNames = getMethodNames(cls, true); + List list = new ArrayList(); + for (Method m : cls.getMethods()) { + String name = m.getName(); + //if (name.equals("getClass") && m.getParameterTypes().length == 0)//cls != Object.class) continue; + // //list.add(m); + + if (m.getDeclaringClass() == cls || parentMethodNames.contains(name) && declaredMethodNames.contains(name)) + list.add(m); + } + methods = list.toArray(new Method[list.size()]); + } + return methods; + } public abstract void generate() throws Exception; @@ -45,7 +81,7 @@ protected void editWarning() { } protected void include(Class cls) { - if (CppWrap.isWrapped(cls)) + if (CppWrap.shouldGenerate(cls) && CppWrap.isWrapped(cls)) out().println("#include <" + cls.getName().replace('.', '/') + ".hpp>"); }