From 009c191430d2e87e19ce33ed1bce43f3939f8c1b Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Mon, 13 Aug 2012 21:41:08 +0000 Subject: [PATCH] Add assumeoverride feature option for Java directors to improve performance when it can be assumed that all methods are overridden by the Java derived classes git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@13606 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- CHANGES.current | 4 +++ Doc/Manual/Java.html | 23 +++++++++++++- Examples/test-suite/common.mk | 1 + .../java_director_assumeoverride_runme.java | 27 +++++++++++++++++ .../test-suite/java_director_assumeoverride.i | 30 +++++++++++++++++++ Source/Modules/java.cxx | 30 +++++++++++++++---- 6 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 Examples/test-suite/java/java_director_assumeoverride_runme.java create mode 100644 Examples/test-suite/java_director_assumeoverride.i diff --git a/CHANGES.current b/CHANGES.current index b8a80cfed..78e39dbc1 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -5,6 +5,10 @@ See the RELEASENOTES file for a summary of changes in each release. Version 2.0.8 (in progress) =========================== +2012-08-13: wsfulton + [Java] Patch from David Baum to add the assumeoverride feature for Java directors to + improve performance when all overridden methods can be assumed to be overridden. + 2012-08-05: wsfulton [Python] #3530021 Fix unused variable warning. diff --git a/Doc/Manual/Java.html b/Doc/Manual/Java.html index 8a081f46d..cfee64fa0 100644 --- a/Doc/Manual/Java.html +++ b/Doc/Manual/Java.html @@ -86,6 +86,7 @@
  • Overhead and code bloat
  • Simple directors example
  • Director threading issues +
  • Director performance tuning
  • Accessing protected members
  • Common customization features @@ -3525,6 +3526,27 @@ Macros can be defined on the commandline when compiling your C++ code, or altern +

    24.5.6 Director performance tuning

    + +

    +When a new instance of a director (or subclass) is created in Java, the C++ side of the director performs a runtime check per director method to determine if that particular method is overridden in Java or if it should invoke the C++ base implementation directly. Although this makes initialization slightly more expensive, it is generally a good overall tradeoff. +

    + +

    +However, if all director methods are expected to usually be overridden by Java subclasses, then initialization can be made faster by avoiding these checks via the assumeoverride attribute. For example: +

    + +
    +
    +%feature("director", assumeoverride=1) Foo;
    +
    +
    + +

    +The disadvantage is that invocation of director methods from C++ when Java doesn't actually override the method will require an additional call up into Java and back to C++. As such, this option is only useful when overrides are extremely common and instantiation is frequent enough that its performance is critical. +

    + +

    24.6 Accessing protected members

    @@ -7862,4 +7884,3 @@ Many of these have runtime tests in the java subdirectory. - diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index f6a8056e5..ef65fbb1b 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -161,6 +161,7 @@ CPP_TEST_CASES += \ destructor_reprotected \ director_abstract \ director_alternating \ + director_assumeoverride \ director_basic \ director_binary_string \ director_classes \ diff --git a/Examples/test-suite/java/java_director_assumeoverride_runme.java b/Examples/test-suite/java/java_director_assumeoverride_runme.java new file mode 100644 index 000000000..e876a79c9 --- /dev/null +++ b/Examples/test-suite/java/java_director_assumeoverride_runme.java @@ -0,0 +1,27 @@ + +import java_director_assumeoverride.*; + +public class java_director_assumeoverride_runme { + + static { + try { + System.loadLibrary("java_director_assumeoverride"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + static class MyOverrideMe extends OverrideMe { + } + + public static void main(String argv[]) { + OverrideMe overrideMe = new MyOverrideMe(); + + // MyOverrideMe doesn't actually override func(), but because assumeoverride + // was set to true, the C++ side will believe it was overridden. + if (!java_director_assumeoverride.isFuncOverridden(overrideMe)) { + throw new RuntimeException ( "isFuncOverridden()" ); + } + } +} diff --git a/Examples/test-suite/java_director_assumeoverride.i b/Examples/test-suite/java_director_assumeoverride.i new file mode 100644 index 000000000..7364a3d58 --- /dev/null +++ b/Examples/test-suite/java_director_assumeoverride.i @@ -0,0 +1,30 @@ +%module(directors="1") java_director_assumeoverride +#pragma SWIG nowarn=SWIGWARN_TYPEMAP_THREAD_UNSAFE,SWIGWARN_TYPEMAP_DIRECTOROUT_PTR + +%{ +class OverrideMe { +public: + virtual ~OverrideMe() {} + virtual void func() {}; +}; + +#include "java_director_assumeoverride_wrap.h" +bool isFuncOverridden(OverrideMe* f) { + SwigDirector_OverrideMe* director = dynamic_cast(f); + if (!director) { + return false; + } + return director->swig_overrides(0); +} + +%} + +%feature("director", assumeoverride=1) OverrideMe; + +class OverrideMe { +public: + virtual ~OverrideMe(); + virtual void func(); +}; + +bool isFuncOverridden(OverrideMe* f); diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx index ffc4d8d97..1c39aec11 100644 --- a/Source/Modules/java.cxx +++ b/Source/Modules/java.cxx @@ -4318,12 +4318,30 @@ public: Printf(w->code, " methods[i].base_methid = jenv->GetMethodID(baseclass, methods[i].mname, methods[i].mdesc);\n"); Printf(w->code, " if (!methods[i].base_methid) return;\n"); Printf(w->code, " }\n"); - Printf(w->code, " swig_override[i] = false;\n"); - Printf(w->code, " if (derived) {\n"); - Printf(w->code, " jmethodID methid = jenv->GetMethodID(jcls, methods[i].mname, methods[i].mdesc);\n"); - Printf(w->code, " swig_override[i] = (methid != methods[i].base_methid);\n"); - Printf(w->code, " jenv->ExceptionClear();\n"); - Printf(w->code, " }\n"); + // Generally, derived classes have a mix of overridden and + // non-overridden methods and it is worth making a GetMethodID + // check during initialization to determine if each method is + // overridden, thus avoiding unnecessary calls into Java. + // + // On the other hand, when derived classes are + // expected to override all director methods then the + // GetMethodID calls are inefficient, and it is better to let + // the director unconditionally call up into Java. The resulting code + // will still behave correctly (though less efficiently) when Java + // code doesn't override a given method. + // + // The assumeoverride feature on a director controls whether or not + // overrides are assumed. + if (GetFlag(n, "feature:director:assumeoverride")) { + Printf(w->code, " swig_override[i] = derived;\n"); + } else { + Printf(w->code, " swig_override[i] = false;\n"); + Printf(w->code, " if (derived) {\n"); + Printf(w->code, " jmethodID methid = jenv->GetMethodID(jcls, methods[i].mname, methods[i].mdesc);\n"); + Printf(w->code, " swig_override[i] = (methid != methods[i].base_methid);\n"); + Printf(w->code, " jenv->ExceptionClear();\n"); + Printf(w->code, " }\n"); + } Printf(w->code, "}\n"); } else { Printf(f_directors_h, "public:\n");