Skip to content

Commit

Permalink
Merge pull request #23 from Over-Run/update
Browse files Browse the repository at this point in the history
  • Loading branch information
squid233 authored Nov 23, 2024
2 parents d20068d + c40ee8e commit 7f8cad3
Show file tree
Hide file tree
Showing 35 changed files with 1,413 additions and 1,022 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.run/
run/
*.class

.gradle
build/
Expand Down
4 changes: 0 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,6 @@ tasks.withType<Jar> {
)
}

tasks.withType<JavaCompile> {
options.compilerArgs.add("-proc:none")
}

java {
if (hasJavadocJar.toBoolean()) withJavadocJar()
if (hasSourcesJar.toBoolean()) withSourcesJar()
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
43 changes: 35 additions & 8 deletions src/main/java/overrun/marshal/DirectAccessData.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,47 @@
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.SymbolLookup;
import java.lang.invoke.MethodHandle;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
* The data for {@link DirectAccess}.
*
* @param functionDescriptors an unmodifiable map of the function descriptors for each method
* @param methodHandles an unmodifiable map of the method handles for each method
* @param symbolLookup the symbol lookup of this library
* @author squid233
* @since 0.1.0
*/
public record DirectAccessData(
Map<String, FunctionDescriptor> functionDescriptors,
Map<String, MethodHandle> methodHandles,
SymbolLookup symbolLookup
) {
public final class DirectAccessData {
private final Map<String, FunctionDescriptor> functionDescriptors;
private final Function<String, MethodHandle> methodHandleGetter;
private final Map<String, MethodHandle> methodHandles = new HashMap<>();
private final SymbolLookup symbolLookup;

DirectAccessData(
Map<String, FunctionDescriptor> functionDescriptors,
Function<String, MethodHandle> methodHandleGetter,
SymbolLookup symbolLookup
) {
this.functionDescriptors = functionDescriptors;
this.methodHandleGetter = methodHandleGetter;
this.symbolLookup = symbolLookup;
}

/// {@return an unmodifiable map of the function descriptors for each method}
public Map<String, FunctionDescriptor> functionDescriptors() {
return functionDescriptors;
}

/// Gets or loads a method handle with the given entrypoint.
///
/// @param entrypoint the entrypoint
/// @return the loaded method handle
public MethodHandle methodHandle(String entrypoint) {
return methodHandles.computeIfAbsent(entrypoint, methodHandleGetter);
}

/// {@return the symbol lookup of this library}
public SymbolLookup symbolLookup() {
return symbolLookup;
}
}
382 changes: 132 additions & 250 deletions src/main/java/overrun/marshal/Downcall.java

Large diffs are not rendered by default.

199 changes: 199 additions & 0 deletions src/main/java/overrun/marshal/DowncallFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*
* MIT License
*
* Copyright (c) 2024 Overrun Organization
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*/

package overrun.marshal;

import io.github.overrun.memstack.MemoryStack;
import overrun.marshal.gen.DowncallMethodParameter;
import overrun.marshal.gen.DowncallMethodType;
import overrun.marshal.gen.ConvertedClassType;
import overrun.marshal.gen.processor.ReturnValueTransformer;

import java.lang.invoke.*;
import java.util.Arrays;

/// The downcall factory creates method handle and call sites for the generated native function invoker.
///
/// The factory provides bootstrap methods where [Downcall] uses `invokedynamic`, which enables to create the method
/// handles on demand.
///
/// @author squid233
/// @since 0.1.0
public final class DowncallFactory {
private static final MethodHandles.Lookup privateLookup = MethodHandles.lookup();
private static final MethodHandle
MH_throwISE,
MH_popStack,
MH_popStackVoid;

static {
try {
MH_throwISE = privateLookup.findStatic(DowncallFactory.class, "throwISE", MethodType.methodType(Object.class, Throwable.class, Class.class, String.class, MethodType.class));
MH_popStack = privateLookup.findStatic(DowncallFactory.class, "popStack", MethodType.methodType(Object.class, Throwable.class, Object.class));
MH_popStackVoid = privateLookup.findStatic(DowncallFactory.class, "popStack", MethodType.methodType(void.class, Throwable.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}

private DowncallFactory() {
}

/// Accesses downcall method handle with the given entrypoint.
///
/// @param caller the caller
/// @param entrypoint the entrypoint name
/// @param type the type
/// @param data the direct access data
/// @return the obtained method handle
public static MethodHandle downcallHandle(
MethodHandles.Lookup caller,
String entrypoint,
Class<?> type,
DirectAccessData data
) {
return data.methodHandle(entrypoint);
}

/// Creates a call site for the downcall method handle specified with the given entrypoint.
///
/// This method wraps the target handle with exception handling and memory stack popping as well as return value
/// transforming.
///
/// @param caller the caller
/// @param entrypoint the entrypoint name
/// @param type the method type of java method
/// @param data the direct access data
/// @param downcallMethodType the downcall method handle type
/// @param popStack `true` if the memory stack should be popped
/// @return the call site which targets to the new method handle
public static CallSite downcallCallSite(
MethodHandles.Lookup caller,
String entrypoint,
MethodType type,
DirectAccessData data,
DowncallMethodType downcallMethodType,
boolean popStack
) {
MethodHandle methodHandle = data.methodHandle(entrypoint);
Class<?> returnType = type.returnType();
methodHandle = ReturnValueTransformer.getInstance().process(methodHandle, new ReturnValueTransformer.Context(returnType, downcallMethodType));
methodHandle = MethodHandles.catchException(methodHandle, Throwable.class, MethodHandles.insertArguments(MH_throwISE.asType(MH_throwISE.type().changeReturnType(returnType)), 1, caller.lookupClass(), entrypoint, type));
if (popStack) {
if (returnType == void.class) {
methodHandle = MethodHandles.tryFinally(methodHandle, MH_popStackVoid);
} else {
methodHandle = MethodHandles.tryFinally(methodHandle, MH_popStack.asType(MethodType.methodType(returnType, Throwable.class, returnType)));
}
}
return new ConstantCallSite(methodHandle);
}

private static Object throwISE(Throwable t, Class<?> caller, String entrypoint, MethodType type) {
throw new IllegalStateException(caller.getName() + "." + entrypoint + type, t);
}

private static Object popStack(Throwable t, Object result) {
MemoryStack.popLocal();
return result;
}

private static void popStack(Throwable t) {
MemoryStack.popLocal();
}

/// BSM for [DowncallMethodParameter]
///
/// @param lookup unused
/// @param name unused
/// @param type unused
/// @param parameterType parameterType
/// @param byValue byValue
/// @param ref ref
/// @param sized sized
/// @param charset charset
/// @param canonicalType canonicalType
/// @return the created [DowncallMethodParameter]
public static DowncallMethodParameter createDowncallMethodParameter(
MethodHandles.Lookup lookup,
String name,
Class<?> type,
ConvertedClassType parameterType,
boolean byValue,
boolean ref,
long sized,
String charset,
String canonicalType
) {
return new DowncallMethodParameter(parameterType, byValue, ref, sized, charset, canonicalType);
}

/// BSM for [DowncallMethodType]
///
/// @param lookup unused
/// @param entrypoint entrypoint
/// @param type unused
/// @param returnType returnType
/// @param byValue byValue
/// @param critical critical
/// @param criticalAllowHeapAccess criticalAllowHeapAccess
/// @param sized sized
/// @param charset charset
/// @param canonicalType canonicalType
/// @param args parameters
/// @return the created [DowncallMethodType]
public static DowncallMethodType createDowncallMethodType(
MethodHandles.Lookup lookup,
String entrypoint,
Class<?> type,
ConvertedClassType returnType,
boolean byValue,
boolean critical,
boolean criticalAllowHeapAccess,
long sized,
String charset,
String canonicalType,
Object... args
) {
return new DowncallMethodType(entrypoint,
returnType,
Arrays.stream(args).map(o -> (DowncallMethodParameter) o).toArray(DowncallMethodParameter[]::new),
byValue,
critical,
criticalAllowHeapAccess,
sized,
charset,
canonicalType);
}

/// BSM for [ConvertedClassType]
///
/// @param lookup unused
/// @param name unused
/// @param type unused
/// @param javaClass javaClass
/// @param downcallClass downcallClass
/// @return the created [ConvertedClassType]
public static ConvertedClassType createConvertedClassType(
MethodHandles.Lookup lookup,
String name,
Class<?> type,
Class<?> javaClass,
Class<?> downcallClass
) {
return new ConvertedClassType(javaClass, downcallClass);
}
}
44 changes: 0 additions & 44 deletions src/main/java/overrun/marshal/DowncallMethodData.java

This file was deleted.

4 changes: 2 additions & 2 deletions src/main/java/overrun/marshal/Upcall.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import overrun.marshal.gen.processor.ProcessorType;
import overrun.marshal.gen.processor.ProcessorTypes;
import overrun.marshal.gen.processor.UnmarshalProcessor;
import overrun.marshal.gen.processor.ReturnValueTransformer;

import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
Expand All @@ -35,7 +35,7 @@
* <p>
* Returning an {@code Upcall} from a downcall method requires a
* {@linkplain ProcessorTypes#registerUpcall(Class, ProcessorType.Upcall.Factory) registration} to tell
* {@link UnmarshalProcessor} how to create an instance of the {@code Upcall}.
* {@link ReturnValueTransformer} how to create an instance of the {@code Upcall}.
* <h2>Example</h2>
* <pre>{@code
* // The implementation must be public if you use Type
Expand Down
Loading

0 comments on commit 7f8cad3

Please sign in to comment.