diff --git a/src/main/java/jnr/ffi/provider/jffi/DefaultInvokerFactory.java b/src/main/java/jnr/ffi/provider/jffi/DefaultInvokerFactory.java index 3a04907b3..c64135185 100644 --- a/src/main/java/jnr/ffi/provider/jffi/DefaultInvokerFactory.java +++ b/src/main/java/jnr/ffi/provider/jffi/DefaultInvokerFactory.java @@ -506,6 +506,9 @@ public final Object invoke(Runtime runtime, Function function, HeapInvocationBuf static class BooleanInvoker extends BaseInvoker { static FunctionInvoker INSTANCE = new BooleanInvoker(); public final Object invoke(Runtime runtime, Function function, HeapInvocationBuffer buffer) { + if (function.getReturnType().size() == 8) { + return invoker.invokeLong(function, buffer) != 0; + } return invoker.invokeInt(function, buffer) != 0; } } diff --git a/src/main/java/jnr/ffi/provider/jffi/NumberUtil.java b/src/main/java/jnr/ffi/provider/jffi/NumberUtil.java index 3ca02c51c..c94e9f2cb 100644 --- a/src/main/java/jnr/ffi/provider/jffi/NumberUtil.java +++ b/src/main/java/jnr/ffi/provider/jffi/NumberUtil.java @@ -20,6 +20,7 @@ import jnr.ffi.NativeType; import jnr.ffi.provider.SigType; +import org.objectweb.asm.Label; public final class NumberUtil { private NumberUtil() {} @@ -144,23 +145,40 @@ public static void widen(SkinnyMethodAdapter mv, Class from, Class to, NativeTyp public static void narrow(SkinnyMethodAdapter mv, Class from, Class to) { if (!from.equals(to)) { if (byte.class == to || short.class == to || char.class == to || int.class == to || boolean.class == to) { - if (long.class == from) { - mv.l2i(); - } + if (boolean.class == to) { + if (long.class == from) { + mv.lconst_0(); + mv.lcmp(); + + } else { + /* Equivalent to + return result == 0 ? true : false; + */ + Label zero = new Label(); + Label ret = new Label(); + mv.iconst_0(); + mv.if_icmpeq(zero); + mv.iconst_1(); + mv.go_to(ret); + mv.label(zero); + mv.iconst_0(); + mv.label(ret); + } + } else { + if (long.class == from) { + mv.l2i(); + } - if (byte.class == to) { - mv.i2b(); + if (byte.class == to) { + mv.i2b(); - } else if (short.class == to) { - mv.i2s(); + } else if (short.class == to) { + mv.i2s(); - } else if (char.class == to) { - mv.i2c(); + } else if (char.class == to) { + mv.i2c(); - } else if (boolean.class == to) { - // Ensure only 0x0 and 0x1 values are used for boolean - mv.iconst_1(); - mv.iand(); + } } } } diff --git a/src/test/java/jnr/ffi/NumberTest.java b/src/test/java/jnr/ffi/NumberTest.java index 10f1c506f..353ad9bfe 100644 --- a/src/test/java/jnr/ffi/NumberTest.java +++ b/src/test/java/jnr/ffi/NumberTest.java @@ -18,16 +18,16 @@ package jnr.ffi; +import jnr.ffi.annotations.LongLong; +import jnr.ffi.types.int32_t; +import jnr.ffi.types.pid_t; +import jnr.ffi.types.u_int32_t; +import org.junit.*; + import java.util.Random; -import jnr.ffi.annotations.LongLong; -import jnr.ffi.types.*; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; /** * @@ -35,6 +35,8 @@ */ public class NumberTest { + public static final long LONG_WITH_ONLY_THIRD_WORD_NOT_ZERO = 0xFF00000000L; + public NumberTest() { } @@ -70,6 +72,7 @@ public static interface TestLib { public static interface TestBoolean { public boolean ret_int32_t(int l); + public @LongLong boolean ret_int64_t(@LongLong long l); } static TestBoolean testboolean; @@ -357,4 +360,13 @@ public long n(long i1, long i2) { assertEquals(true, testboolean.ret_int32_t(1)); assertEquals(true, testboolean.ret_int32_t(2)); } + + @Test public void testBooleanFromLong() throws Exception { + assertEquals(false, testboolean.ret_int64_t(0)); + assertEquals(true, testboolean.ret_int64_t(-1)); + assertEquals(true, testboolean.ret_int64_t(-5)); + assertEquals(true, testboolean.ret_int64_t(1)); + assertEquals(true, testboolean.ret_int64_t(2)); + assertEquals(true, testboolean.ret_int64_t(LONG_WITH_ONLY_THIRD_WORD_NOT_ZERO)); + } }