static void emitToNativeConversion( AsmBuilder builder, SkinnyMethodAdapter mv, ToNativeType toNativeType) { ToNativeConverter parameterConverter = toNativeType.getToNativeConverter(); if (parameterConverter != null) { Method toNativeMethod = getToNativeMethod(toNativeType, builder.getClassLoader()); if (toNativeType.getDeclaredType().isPrimitive()) { boxValue( builder, mv, getBoxedClass(toNativeType.getDeclaredType()), toNativeType.getDeclaredType()); } if (!toNativeMethod.getParameterTypes()[0].isAssignableFrom( getBoxedClass(toNativeType.getDeclaredType()))) { mv.checkcast(toNativeMethod.getParameterTypes()[0]); } mv.aload(0); AsmBuilder.ObjectField toNativeConverterField = builder.getToNativeConverterField(parameterConverter); mv.getfield( builder.getClassNamePath(), toNativeConverterField.name, ci(toNativeConverterField.klass)); if (!toNativeMethod.getDeclaringClass().equals(toNativeConverterField.klass)) { mv.checkcast(toNativeMethod.getDeclaringClass()); } // Re-order so the value to be converted is on the top of the stack mv.swap(); // load context parameter (if there is one) if (toNativeType.getToNativeContext() != null) { getfield(mv, builder, builder.getToNativeContextField(toNativeType.getToNativeContext())); } else { mv.aconst_null(); } if (toNativeMethod.getDeclaringClass().isInterface()) { mv.invokeinterface( toNativeMethod.getDeclaringClass(), toNativeMethod.getName(), toNativeMethod.getReturnType(), toNativeMethod.getParameterTypes()); } else { mv.invokevirtual( toNativeMethod.getDeclaringClass(), toNativeMethod.getName(), toNativeMethod.getReturnType(), toNativeMethod.getParameterTypes()); } if (!parameterConverter.nativeType().isAssignableFrom(toNativeMethod.getReturnType())) { mv.checkcast(p(parameterConverter.nativeType())); } } }
private static void unboxPointerOrStruct( final SkinnyMethodAdapter mv, final Class type, final Class nativeType) { mv.invokestatic( p(AsmRuntime.class), long.class == nativeType ? "longValue" : "intValue", sig(nativeType, type)); }
static void store(SkinnyMethodAdapter mv, Class type, LocalVariable var) { if (!type.isPrimitive()) { mv.astore(var); } else if (long.class == type) { mv.lstore(var); } else if (double.class == type) { mv.dstore(var); } else if (float.class == type) { mv.fstore(var); } else { mv.istore(var); } }
static void load(SkinnyMethodAdapter mv, Class parameterType, LocalVariable parameter) { if (!parameterType.isPrimitive()) { mv.aload(parameter); } else if (long.class == parameterType) { mv.lload(parameter); } else if (float.class == parameterType) { mv.fload(parameter); } else if (double.class == parameterType) { mv.dload(parameter); } else { mv.iload(parameter); } }
static void unboxNumber( final SkinnyMethodAdapter mv, final Class boxedType, final Class unboxedType, final jnr.ffi.NativeType nativeType) { if (Number.class.isAssignableFrom(boxedType)) { switch (nativeType) { case SCHAR: case UCHAR: mv.invokevirtual(p(boxedType), "byteValue", "()B"); convertPrimitive(mv, byte.class, unboxedType, nativeType); break; case SSHORT: case USHORT: mv.invokevirtual(p(boxedType), "shortValue", "()S"); convertPrimitive(mv, short.class, unboxedType, nativeType); break; case SINT: case UINT: case SLONG: case ULONG: case ADDRESS: if (sizeof(nativeType) == 4) { mv.invokevirtual(p(boxedType), "intValue", "()I"); convertPrimitive(mv, int.class, unboxedType, nativeType); } else { mv.invokevirtual(p(boxedType), "longValue", "()J"); convertPrimitive(mv, long.class, unboxedType, nativeType); } break; case SLONGLONG: case ULONGLONG: mv.invokevirtual(p(boxedType), "longValue", "()J"); narrow(mv, long.class, unboxedType); break; case FLOAT: mv.invokevirtual(p(boxedType), "floatValue", "()F"); break; case DOUBLE: mv.invokevirtual(p(boxedType), "doubleValue", "()D"); break; } } else if (Boolean.class.isAssignableFrom(boxedType)) { unboxBoolean(mv, unboxedType); } else { throw new IllegalArgumentException("unsupported boxed type: " + boxedType); } }
static void emitFromNativeConversion( AsmBuilder builder, SkinnyMethodAdapter mv, FromNativeType fromNativeType, Class nativeClass) { // If there is a result converter, retrieve it and put on the stack FromNativeConverter fromNativeConverter = fromNativeType.getFromNativeConverter(); if (fromNativeConverter != null) { convertPrimitive( mv, nativeClass, unboxedType(fromNativeConverter.nativeType()), fromNativeType.getNativeType()); boxValue(builder, mv, fromNativeConverter.nativeType(), nativeClass); Method fromNativeMethod = getFromNativeMethod(fromNativeType, builder.getClassLoader()); getfield(mv, builder, builder.getFromNativeConverterField(fromNativeConverter)); mv.swap(); if (fromNativeType.getFromNativeContext() != null) { getfield( mv, builder, builder.getFromNativeContextField(fromNativeType.getFromNativeContext())); } else { mv.aconst_null(); } if (fromNativeMethod.getDeclaringClass().isInterface()) { mv.invokeinterface( fromNativeMethod.getDeclaringClass(), fromNativeMethod.getName(), fromNativeMethod.getReturnType(), fromNativeMethod.getParameterTypes()); } else { mv.invokevirtual( fromNativeMethod.getDeclaringClass(), fromNativeMethod.getName(), fromNativeMethod.getReturnType(), fromNativeMethod.getParameterTypes()); } if (fromNativeType.getDeclaredType().isPrimitive()) { // The actual return type is a primitive, but there was a converter for it - extract the // primitive value Class boxedType = getBoxedClass(fromNativeType.getDeclaredType()); if (!boxedType.isAssignableFrom(fromNativeMethod.getReturnType())) mv.checkcast(p(boxedType)); unboxNumber( mv, boxedType, fromNativeType.getDeclaredType(), fromNativeType.getNativeType()); } else if (!fromNativeType .getDeclaredType() .isAssignableFrom(fromNativeMethod.getReturnType())) { mv.checkcast(p(fromNativeType.getDeclaredType())); } } else if (!fromNativeType.getDeclaredType().isPrimitive()) { Class unboxedType = unboxedType(fromNativeType.getDeclaredType()); convertPrimitive(mv, nativeClass, unboxedType, fromNativeType.getNativeType()); boxValue(builder, mv, fromNativeType.getDeclaredType(), unboxedType); } }
static void emitReturn( AsmBuilder builder, SkinnyMethodAdapter mv, Class returnType, Class nativeIntType) { if (returnType.isPrimitive()) { if (long.class == returnType) { mv.lreturn(); } else if (float.class == returnType) { mv.freturn(); } else if (double.class == returnType) { mv.dreturn(); } else if (void.class == returnType) { mv.voidreturn(); } else { mv.ireturn(); } } else { boxValue(builder, mv, returnType, nativeIntType); mv.areturn(); } }
static void unboxNumber( final SkinnyMethodAdapter mv, final Class boxedType, final Class nativeType) { if (Number.class.isAssignableFrom(boxedType)) { if (byte.class == nativeType) { mv.invokevirtual(p(boxedType), "byteValue", "()B"); } else if (short.class == nativeType) { mv.invokevirtual(p(boxedType), "shortValue", "()S"); } else if (int.class == nativeType) { mv.invokevirtual(p(boxedType), "intValue", "()I"); } else if (long.class == nativeType) { mv.invokevirtual(p(boxedType), "longValue", "()J"); } else if (float.class == nativeType) { mv.invokevirtual(p(boxedType), "floatValue", "()F"); } else if (double.class == nativeType) { mv.invokevirtual(p(boxedType), "doubleValue", "()D"); } else { throw new IllegalArgumentException("unsupported Number subclass: " + boxedType); } } else if (Boolean.class.isAssignableFrom(boxedType)) { unboxBoolean(mv, nativeType); } else { throw new IllegalArgumentException("unsupported boxed type: " + boxedType); } }
static void boxValue( AsmBuilder builder, SkinnyMethodAdapter mv, Class boxedType, Class unboxedType) { if (boxedType == unboxedType || boxedType.isPrimitive()) { } else if (Boolean.class.isAssignableFrom(boxedType)) { narrow(mv, unboxedType, boolean.class); mv.invokestatic(Boolean.class, "valueOf", Boolean.class, boolean.class); } else if (Pointer.class.isAssignableFrom(boxedType)) { getfield(mv, builder, builder.getRuntimeField()); mv.invokestatic( AsmRuntime.class, "pointerValue", Pointer.class, unboxedType, jnr.ffi.Runtime.class); } else if (Address.class == boxedType) { mv.invokestatic(boxedType, "valueOf", boxedType, unboxedType); } else if (Number.class.isAssignableFrom(boxedType) && boxedType(unboxedType) == boxedType) { mv.invokestatic(boxedType, "valueOf", boxedType, unboxedType); } else { throw new IllegalArgumentException( "cannot box value of type " + unboxedType + " to " + boxedType); } }
static void tryfinally(SkinnyMethodAdapter mv, Runnable codeBlock, Runnable finallyBlock) { Label before = new Label(), after = new Label(), ensure = new Label(), done = new Label(); mv.trycatch(before, after, ensure, null); mv.label(before); codeBlock.run(); mv.label(after); if (finallyBlock != null) finallyBlock.run(); mv.go_to(done); if (finallyBlock != null) { mv.label(ensure); finallyBlock.run(); mv.athrow(); } mv.label(done); }
static void emitReturnOp(SkinnyMethodAdapter mv, Class returnType) { if (!returnType.isPrimitive()) { mv.areturn(); } else if (long.class == returnType) { mv.lreturn(); } else if (float.class == returnType) { mv.freturn(); } else if (double.class == returnType) { mv.dreturn(); } else if (void.class == returnType) { mv.voidreturn(); } else { mv.ireturn(); } }
static void getfield(SkinnyMethodAdapter mv, AsmBuilder builder, AsmBuilder.ObjectField field) { mv.aload(0); mv.getfield(builder.getClassNamePath(), field.name, ci(field.klass)); }
static void unboxBoolean(final SkinnyMethodAdapter mv, Class boxedType, final Class nativeType) { mv.invokevirtual(p(boxedType), "booleanValue", "()Z"); widen(mv, boolean.class, nativeType); }