Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#463 breaks objective-c's objc_msgSend call #1476

Closed
umjammer opened this issue Oct 25, 2022 · 5 comments
Closed

#463 breaks objective-c's objc_msgSend call #1476

umjammer opened this issue Oct 25, 2022 · 5 comments

Comments

@umjammer
Copy link

umjammer commented Oct 25, 2022

patch #463 breaks objective-c's objc_msgSend call.

i request JNA to make #463 float promotion pluggable.

i mentioned here but i got no response so i promote that to this issue.

i use JNA in my project to talk to objective-c natives.
objective-c natives need to get float argument value of method as float, but the patch #463 promotes float to double.
and #463 is hardcoded, there is no way to change.

below is how i found this issue.


obj-c side

https://github.com/umjammer/rococoa/blob/0.8.5/rococoa-core/src/main/native/test.m#L121-L125

java side

https://github.com/umjammer/rococoa/blob/0.8.5/rococoa-core/src/test/java/org/rococoa/FoundationStructureReturnTest.java#L127-L136

log

main	Foundation.send - sending (boolean) [ID 0x7ff0e3c62650].testGetFloatByValue:(3.14:Float)  # <---- still float
main	Foundation.send - @@@0: 3.14:Float
java.lang.Exception: @@@1:  boolean:Class, [ID 0x7ff0e3c62650]:ID, [Selector testGetFloatByValue:]:Selector, 3.140000104904175:Double, null   # <---- changed as double!!!
	at org.rococoa.internal.MsgSendHandler.invoke(MsgSendHandler.java:122)
	at com.sun.jna.Library$Handler.invoke(Library.java:263)
	at com.sun.proxy.$Proxy13.syntheticSendMessage(Unknown Source)
	at org.rococoa.Foundation.send(Foundation.java:242)
	at org.rococoa.Foundation.send(Foundation.java:220)
	at org.rococoa.FoundationStructureReturnTest.test2(FoundationStructureReturnTest.java:132)
36893488147419103232.0                  # <--- printf shows passed float value is broken

org.opentest4j.AssertionFailedError: 
Expected :true
Actual   :false

i traced around before the call below using a debugger

at com.sun.jna.Library$Handler.invoke(Library.java:263)

then i found

// Promote float varargs to double (https://github.com/java-native-access/jna/issues/463).

caused this issue.


Version of JNA: 5.12.1
Java Virtual Machine:

java version "1.8.0_291"
Java(TM) SE Runtime Environment (build 1.8.0_291-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.291-b10, mixed mode)

Operating system:

$ uname -a                                                                                                                                                                                                                       1.0.10
Darwin nsanomac4 20.6.0 Darwin Kernel Version 20.6.0: Tue Apr 19 21:04:45 PDT 2022; root:xnu-7195.141.29~1/RELEASE_X86_64 x86_64
@matthiasblaesing
Copy link
Member

Here is a discussion about objc_msgSend : #1394

TL;DR Someone needs to come up with a real explanation what is the correct calling convention for objc_msgSend, why https://c-faq.com/varargs/float.html does not apply to the varargs call and based on that create a patch.

@umjammer
Copy link
Author

i haven't know c's variadic argument function has such a spec.

anyway i found a thread that refer to objc_msgSend.
that says objc_msgSend is written in assembly and doesn't use va_* macros (afa my understanding).
so va_* macro's spec couldn't be applied to objc_msgSend, then float is float.
is it not acceptable?

@umjammer
Copy link
Author

umjammer commented Oct 26, 2022

finally i found the answer, but @fkistner already has referred to it at #1394...

conclusion: objc_msgSend is not standard.


umm it's better to modify about float promotion at runtime using like cglib?
but i think it's the easiest way to make float promotion pluggable by JNA.

@matthiasblaesing
Copy link
Member

I reread the article and disagree, you don't need to disable float promotion, because the call to objc_msgSend is not a varargs call and thus you can't bind it in Java as varargs.

So my reading is, that this:

((void (*)(id, SEL, float))objc_msgSend)(obj, @selector(log:), M_PI);

Needs to be called through this:

public class ObjCCalling {
    public static interface ObjCBinding extends Library {
	public static final ObjCBinding INSTANCE = Native.load("????", ObjCBinding.class);

	public static class id extends PointerType {

	    public id() {
	    }

	    public id(Pointer p) {
		super(p);
	    }

	}

	public static class SEL extends PointerType {

	    public SEL() {
	    }

	    public SEL(Pointer p) {
		super(p);
	    }

	}

	public void objc_msgSend(id id, SEL sel, float value);
    }
}

Then everything in the article matches. objc_msgSend is a fast dispatch, that steps out of way as fast as possible, only the ABI of the target method matters. The float -> double promotion would still be needed if the target method is declared as varargs.

This is speculation and I did not test this, as I even only guess how id and SEL are defined.

@umjammer
Copy link
Author

i realized below by your pointing out.

so far...

  • we need to use objc_msgSend for every obj-c method call generated automatically at runtime
  • so we use varargs for variety method arguments <-- this is wrong direction

we (rococoa) should have generated every obj-c method call without varargs.
(currently i'm not sure it's possible or not. is JNA able to call methods generated?)

this problem was our side, not JNA.

thank you for your participation and discussions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants