-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
60 changed files
with
1,118 additions
and
382 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
241 changes: 131 additions & 110 deletions
241
scx-common/src/main/java/cool/scx/common/ffm/FFMHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,146 +1,167 @@ | ||
package cool.scx.common.ffm; | ||
|
||
import cool.scx.common.ffm.type.*; | ||
import cool.scx.common.reflect.ReflectFactory; | ||
import cool.scx.common.ffm.type.callback.Callback; | ||
import cool.scx.common.ffm.type.mapper.*; | ||
import cool.scx.common.ffm.type.paramter.*; | ||
import cool.scx.common.ffm.type.struct.Struct; | ||
import cool.scx.common.ffm.type.wrapper.*; | ||
|
||
import java.lang.foreign.*; | ||
import java.lang.invoke.MethodHandle; | ||
import java.lang.reflect.Method; | ||
import java.util.Arrays; | ||
import java.lang.foreign.MemoryLayout; | ||
import java.lang.foreign.MemorySegment; | ||
|
||
import static java.lang.foreign.Linker.nativeLinker; | ||
import static java.lang.foreign.ValueLayout.*; | ||
import static java.lang.invoke.MethodHandles.lookup; | ||
|
||
public final class FFMHelper { | ||
|
||
/** | ||
* 从指定的 SymbolLookup 中寻找 MethodHandle | ||
* | ||
* @param symbolLookup symbolLookup | ||
* @param name 方法名称 | ||
* @param functionDescriptor 方法描述 | ||
* @return MethodHandle | ||
*/ | ||
public static MethodHandle findMethodHandle(SymbolLookup symbolLookup, String name, FunctionDescriptor functionDescriptor) { | ||
var memorySegment = symbolLookup.find(name).orElseThrow(() -> new IllegalArgumentException("未找到 " + name)); | ||
return nativeLinker().downcallHandle(memorySegment, functionDescriptor); | ||
} | ||
|
||
/** | ||
* 根据 Method 获取 对应的方法描述 | ||
* | ||
* @param method method | ||
* @return 对应的方法描述 | ||
*/ | ||
public static FunctionDescriptor getFunctionDescriptor(Method method) { | ||
return FunctionDescriptor.of(getMemoryLayout(method.getReturnType()), getMemoryLayouts(method.getParameterTypes())); | ||
} | ||
|
||
/** | ||
* 根据 Class 获取对应的 MemoryLayout 类型 | ||
* | ||
* @param type 类型 | ||
* @return 对应的 MemoryLayout 类型 | ||
*/ | ||
public static MemoryLayout getMemoryLayout(Class<?> type) { | ||
//1, 先处理可以直接映射的基本类型 | ||
if (type == Byte.class || type == byte.class) { | ||
return JAVA_BYTE; | ||
} | ||
if (type == Boolean.class || type == boolean.class) { | ||
return JAVA_BOOLEAN; | ||
} | ||
if (type == Character.class || type == char.class) { | ||
return JAVA_CHAR; | ||
} | ||
if (type == Short.class || type == short.class) { | ||
return JAVA_SHORT; | ||
} | ||
if (type == Integer.class || type == int.class) { | ||
return JAVA_INT; | ||
} | ||
if (type == Long.class || type == long.class) { | ||
return JAVA_LONG; | ||
} else if (type == Integer.class || type == int.class) { | ||
return JAVA_INT; | ||
} else if (type == Boolean.class || type == boolean.class) { | ||
} | ||
if (type == Float.class || type == float.class) { | ||
return JAVA_FLOAT; | ||
} | ||
if (type == Double.class || type == double.class) { | ||
return JAVA_DOUBLE; | ||
} | ||
if (type == MemorySegment.class) { | ||
return ADDRESS; | ||
} | ||
//2, 处理基本类型的简单包装类型 | ||
if (ByteWrapper.class.isAssignableFrom(type)) { | ||
return JAVA_BYTE; | ||
} | ||
if (BooleanWrapper.class.isAssignableFrom(type)) { | ||
return JAVA_BOOLEAN; | ||
} else if (type == String.class || | ||
type == MemorySegment.class || | ||
type.isArray() || | ||
Ref.class.isAssignableFrom(type) || | ||
Callback.class.isAssignableFrom(type) || | ||
Struct.class.isAssignableFrom(type)) { | ||
} | ||
if (CharWrapper.class.isAssignableFrom(type)) { | ||
return JAVA_CHAR; | ||
} | ||
if (ShortWrapper.class.isAssignableFrom(type)) { | ||
return JAVA_SHORT; | ||
} | ||
if (IntWrapper.class.isAssignableFrom(type)) { | ||
return JAVA_INT; | ||
} | ||
if (LongWrapper.class.isAssignableFrom(type)) { | ||
return JAVA_LONG; | ||
} | ||
if (FloatWrapper.class.isAssignableFrom(type)) { | ||
return JAVA_FLOAT; | ||
} | ||
if (DoubleWrapper.class.isAssignableFrom(type)) { | ||
return JAVA_DOUBLE; | ||
} | ||
if (AddressWrapper.class.isAssignableFrom(type)) { | ||
return ADDRESS; | ||
} | ||
//3, 处理字符串 | ||
if (String.class == type) { | ||
return ADDRESS; | ||
} | ||
//4, 处理映射类型 | ||
if (Mapper.class.isAssignableFrom(type)) { | ||
return ADDRESS; | ||
} | ||
//5, 处理 结构体类型 这里我们使用 ADDRESS 而不使用 MemoryLayout.structLayout(), 因为需要在运行时才知道具体结构 | ||
if (Struct.class.isAssignableFrom(type)) { | ||
return ADDRESS; | ||
} | ||
//6, 处理 Callback 类型 | ||
if (Callback.class.isAssignableFrom(type)) { | ||
return ADDRESS; | ||
} | ||
//7, 处理基本类型的数组类型 这里我们使用 ADDRESS 而不使用 MemoryLayout.sequenceLayout() , 因为我们不知道数组长度 | ||
if (type.isArray() && type.getComponentType().isPrimitive()) { | ||
return ADDRESS; | ||
} | ||
//8, Parameter 类型 这里一定要放在最后 因为其子类 Wrapper 需要单独处理 | ||
if (Parameter.class.isAssignableFrom(type)) { | ||
return ADDRESS; | ||
} | ||
throw new IllegalArgumentException("不支持的参数类型 !!! " + type); | ||
} | ||
|
||
/** | ||
* 根据 Class 获取对应的 MemoryLayout 类型 | ||
* | ||
* @param types 类型 | ||
* @return 对应的 MemoryLayout 类型 | ||
*/ | ||
public static MemoryLayout[] getMemoryLayouts(Class<?>[] types) { | ||
var array = new MemoryLayout[types.length]; | ||
var memoryLayouts = new MemoryLayout[types.length]; | ||
for (var i = 0; i < types.length; i = i + 1) { | ||
array[i] = getMemoryLayout(types[i]); | ||
memoryLayouts[i] = getMemoryLayout(types[i]); | ||
} | ||
return array; | ||
return memoryLayouts; | ||
} | ||
|
||
//todo 需要内部改变的数据 如 数组 等等如何处理 | ||
public static Object convertParameter(Arena arena, Object o) throws NoSuchMethodException, IllegalAccessException { | ||
public static Parameter convertToParameter(Object o) throws NoSuchMethodException, IllegalAccessException { | ||
return switch (o) { | ||
case null -> MemorySegment.NULL; | ||
case Long _, MemorySegment _, Ref _, Integer _ -> o; | ||
case String s -> arena.allocateFrom(s); | ||
case char[] c -> new CharArrayRef(c); | ||
case Callback c -> convertCallback(arena, c); | ||
case Struct c -> new StructRef(c); | ||
//0, 空值 | ||
case null -> new RawValueParameter(MemorySegment.NULL); | ||
//1, 基本值 | ||
case Byte _, | ||
Boolean _, | ||
Character _, | ||
Short _, | ||
Integer _, | ||
Long _, | ||
Float _, | ||
Double _, | ||
MemorySegment _ -> new RawValueParameter(o); | ||
//2, 基本值包装值 | ||
case Wrapper<?> w -> w; | ||
//3, 字符串 | ||
case String s -> new StringParameter(s); | ||
//4, 映射类型 | ||
case Mapper m -> new MapperParameter(m); | ||
//5, 结构体 | ||
case Struct c -> new StructParameter(c); | ||
//6, Callback 类型 | ||
case Callback c -> new CallbackParameter(c); | ||
//7, 数组类型 | ||
case byte[] c -> new ArrayParameter(c, new ByteArrayMapper(c)); | ||
case char[] c -> new ArrayParameter(c, new CharArrayMapper(c)); | ||
case short[] c -> new ArrayParameter(c, new ShortArrayMapper(c)); | ||
case int[] c -> new ArrayParameter(c, new IntArrayMapper(c)); | ||
case long[] c -> new ArrayParameter(c, new LongArrayMapper(c)); | ||
case float[] c -> new ArrayParameter(c, new FloatArrayMapper(c)); | ||
case double[] c -> new ArrayParameter(c, new DoubleArrayMapper(c)); | ||
//8, Parameter 类型 | ||
case Parameter r -> r; | ||
default -> throw new RuntimeException("无法转换的类型 !!! " + o.getClass()); | ||
}; | ||
} | ||
|
||
public static MemorySegment convertCallback(Arena arena, Callback c) throws NoSuchMethodException, IllegalAccessException { | ||
//todo 此处待处理 | ||
var cc = c.getClass().getInterfaces()[0]; | ||
var s = ReflectFactory.getClassInfo(cc); | ||
var methodInfo = Arrays.stream(s.methods()).filter(method -> c.callbackMethodName().equals(method.name())).findFirst().orElseThrow(() -> new NoSuchMethodException("callback")); | ||
var _handle = lookup().unreflect(methodInfo.method()).bindTo(c); | ||
var r = getMemoryLayout(methodInfo.method().getReturnType()); | ||
var p = getMemoryLayouts(methodInfo.method().getParameterTypes()); | ||
return nativeLinker().upcallStub(_handle, FunctionDescriptor.of(r, p), arena); | ||
} | ||
|
||
public static Object[] convertParameters(Arena arena, Object[] o) throws NoSuchMethodException, IllegalAccessException { | ||
var array = new Object[o.length]; | ||
for (var i = 0; i < o.length; i = i + 1) { | ||
array[i] = convertParameter(arena, o[i]); | ||
public static Parameter[] convertToParameters(Object[] objs) throws NoSuchMethodException, IllegalAccessException { | ||
var result = new Parameter[objs.length]; | ||
for (var i = 0; i < objs.length; i = i + 1) { | ||
result[i] = convertToParameter(objs[i]); | ||
} | ||
return array; | ||
return result; | ||
} | ||
|
||
public static String toString(char[] buf) { | ||
int len = buf.length; | ||
|
||
public static Object[] initRefParameters(Arena arena, Object[] parameters) { | ||
var array = new Object[parameters.length]; | ||
for (var i = 0; i < parameters.length; i = i + 1) { | ||
array[i] = initRef(arena, parameters[i]); | ||
} | ||
return array; | ||
} | ||
|
||
/** | ||
* 如果类型属于引用 则调用 init 方法 | ||
* | ||
* @param arena a | ||
* @param parameter a | ||
* @return a | ||
*/ | ||
private static Object initRef(Arena arena, Object parameter) { | ||
if (parameter instanceof Ref r) { | ||
return r.writeToMemorySegment(arena); | ||
} | ||
return parameter; | ||
} | ||
|
||
/** | ||
* 如果类型属于引用 则调用 end 方法 | ||
* | ||
* @param parameters p | ||
*/ | ||
public static void refreshRefs(Object[] parameters) { | ||
for (var parameter : parameters) { | ||
if (parameter instanceof Ref r) { | ||
r.readFromMemorySegment(); | ||
for (int index = 0; index < len; index = index + 1) { | ||
if (buf[index] == 0) { | ||
len = index; | ||
break; | ||
} | ||
} | ||
|
||
return len == 0 ? "" : new String(buf, 0, len); | ||
} | ||
|
||
} |
Oops, something went wrong.