nativelibs4java / BridJ

BridJ: blazing fast Java / C / C++ interop
https://code.google.com/archive/p/bridj/
Other
297 stars 77 forks source link

C++ Singleton pattern not working #16

Open ochafik opened 9 years ago

ochafik commented 9 years ago

From @slajar on March 28, 2012 17:11

I have a class that is not beeing instanciated by new but by a public static member function.

class API_DECL Test { public: /* the contructor is not available to the public. You'll have to use the singleton patter getInstance() instead. / static Test * getInstance();

private: Test(); static Test* instance; };

Implementation looks like:

Test * Test::instance = NULL;

Test* Test::getInstance() { if( Test::instance == NULL ) { Test::instance = new Test(); } return Test::instance;
}

...

Unfortunately, jnaerator doesn't generate bridj code to access this static getInstance function.

Ok, so I decided to work around this and generated a C-Function thats called "GetTestInstance()".

ifdef __cplusplus

extern "C" {

endif

API_DECL Test* GetTestInstance();

ifdef __cplusplus

} //extern "C"

endif

Internally I call Test::getInstance() to return Test pointer. This compiles successfully. Unfortunately, that doesn't run well. It brings up a Memory error like this:

test = Pointer(peer = 0x5831b08, targetType = com.test.Test) Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2367) at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130) at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:587) at java.lang.StringBuilder.append(StringBuilder.java:214) at org.bridj.demangling.VC9Demangler.parseNameFragment(VC9Demangler.java:599) at org.bridj.demangling.VC9Demangler.parseNameQualification(VC9Demangler.java:642) at org.bridj.demangling.VC9Demangler.parseNameQualifications(VC9Demangler.java:627) at org.bridj.demangling.VC9Demangler.parseQualifiedTypeName(VC9Demangler.java:428) at org.bridj.demangling.VC9Demangler.parseType(VC9Demangler.java:364) at org.bridj.demangling.VC9Demangler.parseType(VC9Demangler.java:352) at org.bridj.demangling.VC9Demangler.parseFunctionProperty(VC9Demangler.java:117) at org.bridj.demangling.VC9Demangler.parseSymbol(VC9Demangler.java:215) at org.bridj.NativeLibrary.parseSymbol(NativeLibrary.java:359) at org.bridj.demangling.Demangler$Symbol.parse(Demangler.java:306) at org.bridj.demangling.Demangler$Symbol.matches(Demangler.java:284) at org.bridj.NativeLibrary.getSymbol(NativeLibrary.java:195) at org.bridj.cpp.CPPRuntime.registerNativeMethod(CPPRuntime.java:263) at org.bridj.CRuntime.register(CRuntime.java:357) at org.bridj.CRuntime.register(CRuntime.java:266) at org.bridj.CRuntime$CTypeInfo.(CRuntime.java:83) at org.bridj.cpp.CPPRuntime$CPPTypeInfo.(CPPRuntime.java:704) at org.bridj.cpp.CPPRuntime.getTypeInfo(CPPRuntime.java:804) at org.bridj.BridJ.getTypeInfo(BridJ.java:309) at org.bridj.BridJ.createNativeObjectFromPointer(BridJ.java:206) at org.bridj.BridJ.createNativeObjectFromPointer(BridJ.java:222) at org.bridj.Pointer.getNativeObjectAtOffset(Pointer.java:690) at org.bridj.CommonPointerIOs$NativeObjectPointerIO.get(CommonPointerIOs.java:43) at org.bridj.CommonPointerIOs$NativeObjectPointerIO.get(CommonPointerIOs.java:11) at org.bridj.Pointer.get(Pointer.java:831) at org.bridj.Pointer.get(Pointer.java:800)

How can I solve this issue in a good way that is compliant with Bridj and JNAerator? I can still change the C++ Api to fit any needs.

Copied from original issue: ochafik/nativelibs4java#291

ochafik commented 9 years ago

Hi @slajar ,

Thanks for your report !

JNAerator actually doesn't report errors well, and the error here is that you've probably not defined API_DECL.

You can try adding -DAPI_DECL= to JNAerator's command line or add the following lines to your header to solve this :

ifndef API_DECL

define API_DECL __declspec(dllexport)

endif

You'll see that JNAerator then generates the bindings you're after :-) (please let me know if you still experience issues after this, I'll reopen this issue)

Cheers

ochafik commented 9 years ago

From @slajar on March 29, 2012 7:36

Sorry, this was not the whole source code. The API_DECL was defined properly.

ifdef _WIN32

ifdef API_EXPORTS

define API_DECL __declspec(dllexport)

else

define API_DECL __declspec(dllimport)

endif

else

define API_DECL

endif

So, I suspect that doesn't help either ;) Do you have further ideas?

kind regards

ochafik commented 9 years ago

From @slajar on March 29, 2012 7:44

Do you think the original Singleton should work flawlessly Or shall I try the C-workaround furthermore?

I rethough the C-workaround and I am quite sure that casting the Pointer to the Peer internally might be not good in terms of interpreting the object structure. What do you think?

ochafik commented 9 years ago

From @slajar on March 29, 2012 7:55

I removed the workaround and did the standard singleton again. Now I am getting:

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.test.Test.getInstance()Lorg/bridj/Pointer; at com.test.Test.getInstance(Native Method) at com.test.Test.Tester.main(Test.java:18) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

When I look at dependency walker the function is in the DLL: ?getInstance@Test@@SAPAV1@XZ

ochafik commented 9 years ago

From @slajar on March 29, 2012 8:2

Btw, my call to the singleton is like this:

Pointer test = Test.getInstance();

After that I expect to call test.get().someMethod();

ochafik commented 9 years ago

Hi @slajar,

Could you have a look at BridJ's logs and paste them here ? Something must have gone wrong during BridJ.register(), which should be called from a static initializer inside the generated Test class. If nothing shows up, you can increase the verbosity with the environment variable BRIDJ_VERBOSE=1

Cheers

Le jeudi 29 mars 2012, slajar a crit :

Btw, my call to the singleton is like this:

Pointer test = Test.getInstance();

After that I expect to call test.get().someMethod();


Reply to this email directly or view it on GitHub: https://github.com/ochafik/nativelibs4java/issues/291#issuecomment-4798602

Olivier http://ochafik.com http://twitter.com/ochafik +44 7428 034374

ochafik commented 9 years ago

From @slajar on March 30, 2012 9:54

Nothing happend after enabling those flags. I sent an entire sample code to olivier.

ochafik commented 9 years ago

Hi @slajar ,

Thanks for your patience !

The main issue in the sample code you kindly sent me is that JNAerator command lines are only read from .jnaerator files, not from .config files (you should rename jnaerator.config into config.jnaerator). I've added some runtime check that fail upon files with unexpected extension to prevent future such issues.

Also, I would suggest you to add -Iinc, remove the #if 0 switch I found in EDAPI.h, add -mode Directory (or if you'd like to use Maven to build the resulting jar, -mode Maven), so as to be compatible with the latest snapshot.

Thanks again for your feedback.

Cheers

ochafik commented 9 years ago

Small update on the runtime error : there's apparently a bug in the VisualC++ demangler, which I can now reproduce.

Working on it now, will let you know as soon as there's progress.

ochafik commented 9 years ago

From @slajar on April 2, 2012 9:9

Thank you for taking care of this isse :)

ochafik commented 9 years ago

From @slajar on April 2, 2012 14:11

Maybe it helps. I found that with the newest Snapshot all my classes throw an error like this "Failed to find a vtable for type com."

ochafik commented 9 years ago

From @slajar on April 4, 2012 8:54

Any news on that? I found that virtual functions/destructors have an impact to the demangler. I found a working solution for me now. Nevertheless on Mac the LLVM-GCC seems to have much more impacts on the demangler.

May current findings are:

Windows:

Mac:

ochafik commented 9 years ago

From @slajar on April 4, 2012 17:37

One more platform difference finding:

while method with the same name and different parameters work fine on Mac they don't work on Windows.