├── Core ├── .gitignore ├── consumer-rules.pro ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── v7878 │ │ │ └── foreign │ │ │ ├── PortAPI.java │ │ │ ├── _MhUtil.java │ │ │ ├── _LLVMStorageDescriptor.java │ │ │ └── _JavaForeignAccessImpl.java │ └── openjdk │ │ └── java │ │ └── com │ │ └── v7878 │ │ └── foreign │ │ ├── StructLayout.java │ │ ├── UnionLayout.java │ │ ├── _ArenaImpl.java │ │ ├── _SlicingAllocator.java │ │ ├── PaddingLayout.java │ │ ├── _UnionLayoutImpl.java │ │ ├── _StructLayoutImpl.java │ │ ├── WrongThreadException.java │ │ ├── _PaddingLayoutImpl.java │ │ ├── _CapturableState.java │ │ ├── _ImplicitSession.java │ │ ├── GroupLayout.java │ │ ├── _NativeMemorySegmentImpl.java │ │ ├── _GlobalSession.java │ │ ├── _MappedMemorySegmentImpl.java │ │ └── _ConfinedSession.java └── build.gradle.kts ├── LLVM ├── .gitignore ├── consumer-rules.pro ├── src │ └── main │ │ └── java │ │ └── com │ │ └── v7878 │ │ └── llvm │ │ ├── BitReader.TODO │ │ ├── BitWriter.TODO │ │ ├── Support.TODO │ │ ├── OrcBindings.TODO │ │ ├── LLVMException.java │ │ ├── _LibLLVM.java │ │ ├── Extra.java │ │ ├── Linker.java │ │ ├── Vectorize.java │ │ └── IRReader.java └── build.gradle.kts ├── Unsafe ├── .gitignore ├── consumer-rules.pro ├── src │ └── main │ │ └── java │ │ └── com │ │ └── v7878 │ │ └── unsafe │ │ ├── cpp_std │ │ ├── LibCpp.java │ │ ├── unique_ptr.java │ │ ├── shared_ptr.java │ │ ├── CLayouts.java │ │ ├── vector.java │ │ └── basic_string.java │ │ ├── foreign │ │ ├── NativeLibrary.java │ │ ├── LibArt.java │ │ ├── ExtraLayouts.java │ │ ├── NativeCodeException.java │ │ ├── Errno.java │ │ └── PThread.java │ │ ├── DangerLevel.java │ │ ├── Stack.java │ │ ├── ApiSensitive.java │ │ ├── access │ │ ├── AsynchronousFileChannelHook.java │ │ ├── DirectSegmentByteBufferBase.raung │ │ ├── AsynchronousSocketChannelHook.java │ │ ├── DexFileAccess.java │ │ ├── JavaForeignAccess.java │ │ ├── VMAccess.java │ │ └── MappedMemoryUtils.java │ │ ├── InstructionSet.java │ │ ├── invoke │ │ └── MethodTypeForm.java │ │ ├── io │ │ └── Maps.java │ │ ├── EarlyNativeUtils.java │ │ ├── llvm │ │ ├── LLVMGlobals.java │ │ └── LLVMTypes.java │ │ ├── ArtVersion.java │ │ ├── ArtModifiers.java │ │ └── ArtFieldUtils.java └── build.gradle.kts ├── VarHandles ├── .gitignore ├── consumer-rules.pro ├── src │ └── main │ │ └── java │ │ └── com │ │ └── v7878 │ │ └── invoke │ │ └── VarHandles.java └── build.gradle.kts ├── stubs ├── llvm │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── v7878 │ │ └── llvm │ │ ├── Linker.java │ │ ├── Extra.java │ │ ├── LLVMException.java │ │ ├── Vectorize.java │ │ ├── IRReader.java │ │ ├── ErrorHandling.java │ │ ├── Analysis.java │ │ ├── Initialization.java │ │ ├── IPO.java │ │ ├── PassManagerBuilder.java │ │ └── Types.java ├── buffers │ ├── .gitignore │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── v7878 │ │ │ └── unsafe │ │ │ ├── FakeHeapByteBuffer.raung │ │ │ ├── FakeMappedByteBuffer.raung │ │ │ ├── AsynchronousFileChannelBase.java │ │ │ └── AsynchronousSocketChannelBase.java │ └── build.gradle.kts ├── invoke │ ├── .gitignore │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── v7878 │ │ │ ├── invoke │ │ │ └── VarHandle.java │ │ │ └── unsafe │ │ │ └── invoke │ │ │ ├── VarHandleImpl.java │ │ │ └── VarHandlesImpl.java │ └── build.gradle.kts └── panama │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ └── main │ └── java │ └── com │ └── v7878 │ └── foreign │ ├── PaddingLayout.java │ ├── UnionLayout.java │ ├── StructLayout.java │ ├── GroupLayout.java │ ├── SequenceLayout.java │ ├── AddressLayout.java │ ├── WrongThreadException.java │ ├── Arena.java │ ├── SymbolLookup.java │ ├── FunctionDescriptor.java │ ├── Linker.java │ └── MemoryLayout.java ├── gradle.properties ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── .gitattributes ├── NOTICE ├── settings.gradle.kts ├── .gitignore ├── .github └── workflows │ └── publish.yml ├── LICENSE ├── README.md └── gradlew.bat /Core/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /Core/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LLVM/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /LLVM/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Unsafe/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /VarHandles/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /stubs/llvm/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /VarHandles/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /stubs/buffers/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /stubs/invoke/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /stubs/panama/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /LLVM/src/main/java/com/v7878/llvm/BitReader.TODO: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LLVM/src/main/java/com/v7878/llvm/BitWriter.TODO: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LLVM/src/main/java/com/v7878/llvm/Support.TODO: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LLVM/src/main/java/com/v7878/llvm/OrcBindings.TODO: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Dfile.encoding=UTF-8 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vova7878/PanamaPort/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /stubs/invoke/src/main/java/com/v7878/invoke/VarHandle.java: -------------------------------------------------------------------------------- 1 | package com.v7878.invoke; 2 | 3 | public class VarHandle { 4 | } 5 | -------------------------------------------------------------------------------- /stubs/invoke/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.library) 3 | } 4 | 5 | android { 6 | namespace = "com.v7878.invoke" 7 | } 8 | 9 | dependencies { 10 | } 11 | -------------------------------------------------------------------------------- /stubs/panama/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.library) 3 | } 4 | 5 | android { 6 | namespace = "com.v7878.foreign" 7 | } 8 | dependencies { 9 | api(project(":VarHandles")) 10 | } 11 | 12 | -------------------------------------------------------------------------------- /stubs/llvm/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.library) 3 | } 4 | 5 | android { 6 | namespace = "com.v7878.llvm" 7 | } 8 | dependencies { 9 | compileOnly(project(":stubs:panama")) 10 | } 11 | 12 | -------------------------------------------------------------------------------- /stubs/buffers/src/main/java/com/v7878/unsafe/FakeHeapByteBuffer.raung: -------------------------------------------------------------------------------- 1 | .version 52 2 | .class public com/v7878/unsafe/FakeHeapByteBuffer 3 | .super java/nio/ByteBuffer 4 | .auto frames 5 | 6 | .method public ()V 7 | return 8 | .end method 9 | -------------------------------------------------------------------------------- /stubs/buffers/src/main/java/com/v7878/unsafe/FakeMappedByteBuffer.raung: -------------------------------------------------------------------------------- 1 | .version 52 2 | .class public com/v7878/unsafe/FakeMappedByteBuffer 3 | .super java/nio/MappedByteBuffer 4 | .auto frames 5 | 6 | .method public ()V 7 | return 8 | .end method 9 | -------------------------------------------------------------------------------- /stubs/buffers/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.library) 3 | alias(libs.plugins.raung) 4 | } 5 | 6 | android { 7 | namespace = "com.v7878.nio" 8 | } 9 | 10 | dependencies { 11 | implementation(libs.sun.cleaner) 12 | } 13 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /Unsafe/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -dontwarn sun.misc.Cleaner 2 | 3 | -dontwarn com.v7878.unsafe.AsynchronousFileChannelBase 4 | -dontwarn com.v7878.unsafe.AsynchronousSocketChannelBase 5 | 6 | -dontwarn com.v7878.unsafe.DirectByteBuffer$MemoryRef 7 | -dontwarn com.v7878.unsafe.DirectByteBuffer 8 | -dontwarn com.v7878.unsafe.HeapByteBuffer -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # Linux start script should use lf 5 | /gradlew text eol=lf 6 | 7 | # These are Windows script files and should use crlf 8 | *.bat text eol=crlf 9 | 10 | # Binary files should be left untouched 11 | *.jar binary 12 | 13 | -------------------------------------------------------------------------------- /Core/src/main/java/com/v7878/foreign/PortAPI.java: -------------------------------------------------------------------------------- 1 | package com.v7878.foreign; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.SOURCE) 9 | @Target({ElementType.METHOD, ElementType.TYPE}) 10 | public @interface PortAPI { 11 | } 12 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/Linker.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import com.v7878.llvm.Types.LLVMModuleRef; 4 | 5 | public final class Linker { 6 | private Linker() { 7 | throw new UnsupportedOperationException("Stub!"); 8 | } 9 | 10 | public static boolean LLVMLinkModules2(LLVMModuleRef Dest, LLVMModuleRef Src) { 11 | throw new UnsupportedOperationException("Stub!"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/cpp_std/LibCpp.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.cpp_std; 2 | 3 | import com.v7878.foreign.Arena; 4 | import com.v7878.foreign.SymbolLookup; 5 | import com.v7878.r8.annotations.DoNotShrink; 6 | 7 | public class LibCpp { 8 | @DoNotShrink 9 | private static final Arena CPP_SCOPE = Arena.ofAuto(); 10 | public static final SymbolLookup CPP = SymbolLookup.libraryLookup("libc++.so", CPP_SCOPE); 11 | } 12 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/cpp_std/unique_ptr.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.cpp_std; 2 | 3 | import static com.v7878.foreign.MemoryLayout.structLayout; 4 | import static com.v7878.foreign.ValueLayout.ADDRESS; 5 | 6 | import com.v7878.foreign.MemoryLayout; 7 | 8 | //TODO: access methods 9 | public final class unique_ptr { 10 | private unique_ptr() { 11 | } 12 | 13 | public static final MemoryLayout LAYOUT = structLayout(ADDRESS); 14 | } 15 | -------------------------------------------------------------------------------- /LLVM/src/main/java/com/v7878/llvm/LLVMException.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | public class LLVMException extends Exception { 4 | public LLVMException() { 5 | super(); 6 | } 7 | 8 | public LLVMException(String message) { 9 | super(message); 10 | } 11 | 12 | public LLVMException(String message, Throwable cause) { 13 | super(message, cause); 14 | } 15 | 16 | public LLVMException(Throwable cause) { 17 | super(cause); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/foreign/NativeLibrary.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.foreign; 2 | 3 | public abstract class NativeLibrary { 4 | public abstract String name(); 5 | 6 | public abstract long find(String name); 7 | 8 | public final long lookup(String name) { 9 | long addr = find(name); 10 | if (0 == addr) { 11 | throw new IllegalArgumentException("Cannot find symbol " + name + " in library " + name()); 12 | } 13 | return addr; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | This project incorporates code derived from OpenJDK in the directory `Core/src/openjdk`. 2 | - Source: https://openjdk.org 3 | - License: GNU General Public License v2.0 with Classpath Exception (see `Core/src/openjdk/LICENSE`) 4 | - Copyright: Copyright (c) 1997-2025 Oracle and/or its affiliates 5 | - Modifications: Copyright (c) 2025 Vladimir Kozelkov 6 | 7 | All other code in this project, including build scripts, is original work by Vladimir Kozelkov 8 | and licensed under the MIT License (see `LICENSE` in the project root). 9 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | } 15 | rootProject.name = "PanamaPort" 16 | include(":Core", ":Unsafe", ":LLVM", ":VarHandles") 17 | include(":stubs:panama", ":stubs:buffers", ":stubs:invoke", ":stubs:llvm") 18 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/cpp_std/shared_ptr.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.cpp_std; 2 | 3 | import static com.v7878.foreign.MemoryLayout.sequenceLayout; 4 | import static com.v7878.foreign.MemoryLayout.structLayout; 5 | import static com.v7878.foreign.ValueLayout.ADDRESS; 6 | 7 | import com.v7878.foreign.MemoryLayout; 8 | 9 | //TODO: access methods 10 | public final class shared_ptr { 11 | private shared_ptr() { 12 | } 13 | 14 | public static final MemoryLayout LAYOUT = structLayout(sequenceLayout(2, ADDRESS)); 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle files 2 | .gradle/ 3 | build/ 4 | 5 | # Local configuration file (sdk path, etc) 6 | local.properties 7 | 8 | # Log/OS Files 9 | *.log 10 | 11 | # Android Studio generated files and folders 12 | captures/ 13 | .externalNativeBuild/ 14 | .cxx/ 15 | *.apk 16 | output.json 17 | 18 | # IntelliJ 19 | *.iml 20 | .idea/ 21 | misc.xml 22 | deploymentTargetDropDown.xml 23 | render.experimental.xml 24 | 25 | # Keystore files 26 | *.jks 27 | *.keystore 28 | 29 | # Google Services (e.g. APIs or Firebase) 30 | google-services.json 31 | 32 | # Android Profiling 33 | *.hprof 34 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/Extra.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | public final class Extra { 4 | private Extra() { 5 | throw new UnsupportedOperationException("Stub!"); 6 | } 7 | 8 | public static String LLVMGetHostCPUFeatures() { 9 | throw new UnsupportedOperationException("Stub!"); 10 | } 11 | 12 | public static String LLVMGetHostCPUName() { 13 | throw new UnsupportedOperationException("Stub!"); 14 | } 15 | 16 | public static String LLVMGetHostTriple() { 17 | throw new UnsupportedOperationException("Stub!"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/DangerLevel.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.SOURCE) 9 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD}) 10 | public @interface DangerLevel { 11 | int VERY_CAREFUL = Integer.MAX_VALUE / 2; 12 | int ONLY_NONMOVABLE_OBJECTS = VERY_CAREFUL + 1; 13 | int MAX = Integer.MAX_VALUE; 14 | 15 | int value(); 16 | } 17 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/foreign/LibArt.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.foreign; 2 | 3 | import static com.v7878.unsafe.VM.vmLibrary; 4 | 5 | import com.v7878.foreign.Arena; 6 | import com.v7878.foreign.SymbolLookup; 7 | import com.v7878.r8.annotations.DoNotShrink; 8 | import com.v7878.unsafe.access.JavaForeignAccess; 9 | 10 | public class LibArt { 11 | @DoNotShrink 12 | private static final Arena ART_SCOPE = Arena.ofAuto(); 13 | public static final SymbolLookup ART = JavaForeignAccess.libraryLookup( 14 | RawNativeLibraries.cload(vmLibrary(), LibDL.ART_CALLER), ART_SCOPE); 15 | } 16 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/LLVMException.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | public class LLVMException extends Exception { 4 | public LLVMException() { 5 | throw new UnsupportedOperationException("Stub!"); 6 | } 7 | 8 | public LLVMException(String message) { 9 | throw new UnsupportedOperationException("Stub!"); 10 | } 11 | 12 | public LLVMException(String message, Throwable cause) { 13 | throw new UnsupportedOperationException("Stub!"); 14 | } 15 | 16 | public LLVMException(Throwable cause) { 17 | throw new UnsupportedOperationException("Stub!"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /LLVM/src/main/java/com/v7878/llvm/_LibLLVM.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import static android.os.Build.VERSION.SDK_INT; 4 | 5 | import com.v7878.foreign.Arena; 6 | import com.v7878.foreign.SymbolLookup; 7 | import com.v7878.r8.annotations.DoNotShrink; 8 | import com.v7878.unsafe.ApiSensitive; 9 | 10 | final class _LibLLVM { 11 | private _LibLLVM() { 12 | } 13 | 14 | @DoNotShrink 15 | private static final Arena LLVM_SCOPE = Arena.ofAuto(); 16 | @ApiSensitive 17 | public static final SymbolLookup LLVM = SymbolLookup.libraryLookup( 18 | SDK_INT < 28 ? "libLLVM.so" : "libLLVM_android.so", LLVM_SCOPE); 19 | } 20 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/foreign/ExtraLayouts.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.foreign; 2 | 3 | import static com.v7878.foreign.MemoryLayout.structLayout; 4 | import static com.v7878.foreign.ValueLayout.JAVA_INT; 5 | import static com.v7878.foreign.ValueLayout.JAVA_LONG; 6 | import static com.v7878.unsafe.AndroidUnsafe.IS64BIT; 7 | 8 | import com.v7878.foreign.MemoryLayout; 9 | import com.v7878.foreign.ValueLayout; 10 | 11 | public class ExtraLayouts { 12 | public static final ValueLayout WORD = IS64BIT ? JAVA_LONG : JAVA_INT; 13 | public static final MemoryLayout JAVA_OBJECT = structLayout(JAVA_INT); 14 | public static final MemoryLayout JNI_OBJECT = structLayout(WORD); 15 | } 16 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/Vectorize.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import com.v7878.llvm.Types.LLVMPassManagerRef; 4 | 5 | public final class Vectorize { 6 | private Vectorize() { 7 | throw new UnsupportedOperationException("Stub!"); 8 | } 9 | 10 | public static void LLVMAddBBVectorizePass(LLVMPassManagerRef PM) { 11 | throw new UnsupportedOperationException("Stub!"); 12 | } 13 | 14 | public static void LLVMAddLoopVectorizePass(LLVMPassManagerRef PM) { 15 | throw new UnsupportedOperationException("Stub!"); 16 | } 17 | 18 | public static void LLVMAddSLPVectorizePass(LLVMPassManagerRef PM) { 19 | throw new UnsupportedOperationException("Stub!"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /stubs/invoke/src/main/java/com/v7878/unsafe/invoke/VarHandleImpl.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.invoke; 2 | 3 | import com.v7878.invoke.VarHandle; 4 | 5 | import java.lang.invoke.MethodType; 6 | 7 | public abstract class VarHandleImpl extends VarHandle { 8 | public enum AccessType { 9 | GET, 10 | SET, 11 | 12 | GET_ATOMIC, 13 | SET_ATOMIC, 14 | 15 | COMPARE_AND_SET, 16 | COMPARE_AND_EXCHANGE, 17 | GET_AND_UPDATE, 18 | 19 | GET_AND_UPDATE_BITWISE, 20 | GET_AND_UPDATE_NUMERIC; 21 | 22 | public MethodType accessModeType(Class value, Class... coordinates) { 23 | throw new UnsupportedOperationException("Stub!"); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/foreign/NativeCodeException.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.foreign; 2 | 3 | public class NativeCodeException extends RuntimeException { 4 | private final String functionName; 5 | public final int code; 6 | 7 | public NativeCodeException(String functionName, int code) { 8 | this.functionName = functionName; 9 | this.code = code; 10 | } 11 | 12 | public NativeCodeException(String functionName, int code, Throwable cause) { 13 | super(cause); 14 | this.functionName = functionName; 15 | this.code = code; 16 | } 17 | 18 | @Override 19 | public String getMessage() { 20 | return functionName + " failed with code: " + code; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/IRReader.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import static com.v7878.llvm.Types.LLVMContextRef; 4 | import static com.v7878.llvm.Types.LLVMMemoryBufferRef; 5 | 6 | import com.v7878.llvm.Types.LLVMModuleRef; 7 | 8 | public final class IRReader { 9 | private IRReader() { 10 | throw new UnsupportedOperationException("Stub!"); 11 | } 12 | 13 | public static LLVMModuleRef LLVMParseIRInContext(LLVMContextRef ContextRef, LLVMMemoryBufferRef MemBuf) throws LLVMException { 14 | throw new UnsupportedOperationException("Stub!"); 15 | } 16 | 17 | public static LLVMModuleRef LLVMParseIRInContext(LLVMContextRef ContextRef, String Data) throws LLVMException { 18 | throw new UnsupportedOperationException("Stub!"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/ErrorHandling.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | public final class ErrorHandling { 4 | private ErrorHandling() { 5 | throw new UnsupportedOperationException("Stub!"); 6 | } 7 | 8 | @FunctionalInterface 9 | public interface LLVMFatalErrorHandler { 10 | void invoke(String reason); 11 | } 12 | 13 | public static void LLVMEnablePrettyStackTrace() { 14 | throw new UnsupportedOperationException("Stub!"); 15 | } 16 | 17 | public static void LLVMInstallFatalErrorHandler(LLVMFatalErrorHandler Handler) { 18 | throw new UnsupportedOperationException("Stub!"); 19 | } 20 | 21 | public static void LLVMResetFatalErrorHandler() { 22 | throw new UnsupportedOperationException("Stub!"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | agp = "8.13.1" 3 | maven-publish = "0.35.0" 4 | 5 | dexfile = "v1.2.1" 6 | raung = "v1.0.0" 7 | r8-annotations = "v1.0.0" 8 | sun-cleaner = "v1.0.0" 9 | sun-unsafe = "v1.0.1" 10 | 11 | [libraries] 12 | dexfile = { module = "io.github.vova7878:DexFile", version.ref = "dexfile" } 13 | r8-annotations = { module = "io.github.vova7878:R8Annotations", version.ref = "r8-annotations" } 14 | sun-cleaner = { module = "io.github.vova7878:SunCleanerStub", version.ref = "sun-cleaner" } 15 | sun-unsafe = { module = "io.github.vova7878:SunUnsafeWrapper", version.ref = "sun-unsafe" } 16 | 17 | [plugins] 18 | android-library = { id = "com.android.library", version.ref = "agp" } 19 | maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "maven-publish" } 20 | 21 | raung = { id = "io.github.vova7878.RaungPlugin", version.ref = "raung" } 22 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/Stack.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe; 2 | 3 | import static com.v7878.unsafe.ArtMethodUtils.getExecutableData; 4 | import static com.v7878.unsafe.ArtMethodUtils.registerNativeMethod; 5 | import static com.v7878.unsafe.Reflection.getHiddenMethod; 6 | 7 | import com.v7878.r8.annotations.DoNotObfuscate; 8 | import com.v7878.r8.annotations.DoNotShrink; 9 | 10 | public class Stack { 11 | static { 12 | registerNativeMethod( 13 | getHiddenMethod(Stack.class, "getStackClass2"), 14 | getExecutableData(getHiddenMethod(ClassUtils.sysClass( 15 | "dalvik.system.VMStack"), "getStackClass2"))); 16 | } 17 | 18 | @DoNotObfuscate 19 | @DoNotShrink 20 | public static native Class getStackClass2(); 21 | 22 | @DoNotShrink // TODO: DoNotInline 23 | public static Class getStackClass1() { 24 | return getStackClass2(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/cpp_std/CLayouts.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.cpp_std; 2 | 3 | import static com.v7878.foreign.ValueLayout.JAVA_DOUBLE; 4 | import static com.v7878.foreign.ValueLayout.JAVA_INT; 5 | import static com.v7878.foreign.ValueLayout.JAVA_LONG; 6 | import static com.v7878.foreign.ValueLayout.OfDouble; 7 | import static com.v7878.foreign.ValueLayout.OfLong; 8 | import static com.v7878.unsafe.InstructionSet.CURRENT_INSTRUCTION_SET; 9 | 10 | import com.v7878.foreign.ValueLayout; 11 | import com.v7878.unsafe.foreign.ExtraLayouts; 12 | 13 | public class CLayouts { 14 | public static final ValueLayout C_WCHAR_T = JAVA_INT; 15 | public static final ValueLayout C_LONG = ExtraLayouts.WORD; 16 | public static final OfLong C_LONG_LONG = JAVA_LONG.withByteAlignment( 17 | CURRENT_INSTRUCTION_SET.alignofLongLong()); 18 | public static final OfDouble C_DOUBLE = JAVA_DOUBLE.withByteAlignment( 19 | CURRENT_INSTRUCTION_SET.alignofDouble()); 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | on: 3 | release: 4 | types: [ released, prereleased ] 5 | jobs: 6 | publish: 7 | name: Release build and publish 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Check out code 11 | uses: actions/checkout@v4 12 | - name: Set up JDK 13 | uses: actions/setup-java@v4 14 | with: 15 | distribution: 'zulu' 16 | java-version: 21 17 | - name: Make gradlew executable 18 | run: chmod +x ./gradlew 19 | - name: Publish to MavenCentral 20 | run: ./gradlew publishToMavenCentral -Pversion=${{ github.event.release.tag_name }} 21 | env: 22 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 23 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 24 | ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }} 25 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }} 26 | ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY_CONTENTS }} 27 | -------------------------------------------------------------------------------- /stubs/buffers/src/main/java/com/v7878/unsafe/AsynchronousFileChannelBase.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.channels.CompletionHandler; 5 | import java.util.concurrent.Future; 6 | 7 | // Compile-time stub, real class will be generated at runtime 8 | public class AsynchronousFileChannelBase { 9 | public void read(ByteBuffer dst, 10 | long position, 11 | A attachment, 12 | CompletionHandler handler) { 13 | throw new UnsupportedOperationException("Stub!"); 14 | } 15 | 16 | public Future read(ByteBuffer dst, long position) { 17 | throw new UnsupportedOperationException("Stub!"); 18 | } 19 | 20 | public void write(ByteBuffer src, 21 | long position, 22 | A attachment, 23 | CompletionHandler handler) { 24 | throw new UnsupportedOperationException("Stub!"); 25 | } 26 | 27 | public Future write(ByteBuffer src, long position) { 28 | throw new UnsupportedOperationException("Stub!"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Core/src/main/java/com/v7878/foreign/_MhUtil.java: -------------------------------------------------------------------------------- 1 | package com.v7878.foreign; 2 | 3 | 4 | import java.lang.invoke.MethodHandle; 5 | import java.lang.invoke.MethodHandles; 6 | import java.lang.invoke.MethodType; 7 | 8 | final class _MhUtil { 9 | private _MhUtil() { 10 | } 11 | 12 | public static MethodHandle findVirtual(MethodHandles.Lookup lookup, 13 | Class refc, 14 | String name, 15 | MethodType type) { 16 | try { 17 | return lookup.findVirtual(refc, name, type); 18 | } catch (ReflectiveOperationException e) { 19 | throw new InternalError(e); 20 | } 21 | } 22 | 23 | public static MethodHandle findStatic(MethodHandles.Lookup lookup, 24 | Class refc, 25 | String name, 26 | MethodType type) { 27 | try { 28 | return lookup.findStatic(refc, name, type); 29 | } catch (ReflectiveOperationException e) { 30 | throw new InternalError(e); 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Vladimir Kozelkov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | This license applies to all parts of this project, 24 | except for the code in `Core/src/openjdk` folder. 25 | (see Core/src/openjdk/LICENSE for additional info) 26 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/ApiSensitive.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe; 2 | 3 | import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 4 | import static java.lang.annotation.ElementType.CONSTRUCTOR; 5 | import static java.lang.annotation.ElementType.FIELD; 6 | import static java.lang.annotation.ElementType.LOCAL_VARIABLE; 7 | import static java.lang.annotation.ElementType.METHOD; 8 | import static java.lang.annotation.ElementType.MODULE; 9 | import static java.lang.annotation.ElementType.PACKAGE; 10 | import static java.lang.annotation.ElementType.PARAMETER; 11 | import static java.lang.annotation.ElementType.RECORD_COMPONENT; 12 | import static java.lang.annotation.ElementType.TYPE; 13 | import static java.lang.annotation.ElementType.TYPE_PARAMETER; 14 | import static java.lang.annotation.ElementType.TYPE_USE; 15 | 16 | import java.lang.annotation.Retention; 17 | import java.lang.annotation.RetentionPolicy; 18 | import java.lang.annotation.Target; 19 | 20 | @Target({TYPE, 21 | FIELD, 22 | METHOD, 23 | PARAMETER, 24 | CONSTRUCTOR, 25 | LOCAL_VARIABLE, 26 | ANNOTATION_TYPE, 27 | PACKAGE, 28 | TYPE_PARAMETER, 29 | TYPE_USE, 30 | MODULE, 31 | RECORD_COMPONENT}) 32 | @Retention(RetentionPolicy.SOURCE) 33 | public @interface ApiSensitive { 34 | } 35 | -------------------------------------------------------------------------------- /stubs/invoke/src/main/java/com/v7878/unsafe/invoke/VarHandlesImpl.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.invoke; 2 | 3 | import com.v7878.invoke.VarHandle; 4 | 5 | import java.lang.invoke.MethodHandle; 6 | import java.util.List; 7 | 8 | public final class VarHandlesImpl { 9 | private VarHandlesImpl() { 10 | } 11 | 12 | public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget) { 13 | throw new UnsupportedOperationException("Stub!"); 14 | } 15 | 16 | public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters) { 17 | throw new UnsupportedOperationException("Stub!"); 18 | } 19 | 20 | public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter) { 21 | throw new UnsupportedOperationException("Stub!"); 22 | } 23 | 24 | public static VarHandle insertCoordinates(VarHandle target, int pos, Object... values) { 25 | throw new UnsupportedOperationException("Stub!"); 26 | } 27 | 28 | public static VarHandle permuteCoordinates(VarHandle target, List> newCoordinates, int... reorder) { 29 | throw new UnsupportedOperationException("Stub!"); 30 | } 31 | 32 | public static VarHandle dropCoordinates(VarHandle target, int pos, Class... valueTypes) { 33 | throw new UnsupportedOperationException("Stub!"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /VarHandles/src/main/java/com/v7878/invoke/VarHandles.java: -------------------------------------------------------------------------------- 1 | package com.v7878.invoke; 2 | 3 | 4 | import java.lang.invoke.MethodHandle; 5 | import java.util.List; 6 | 7 | // Class for backward compatibility 8 | public final class VarHandles { 9 | private VarHandles() { 10 | } 11 | 12 | public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget) { 13 | return Handles.filterValue(target, filterToTarget, filterFromTarget); 14 | } 15 | 16 | public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters) { 17 | return Handles.filterCoordinates(target, pos, filters); 18 | } 19 | 20 | public static VarHandle insertCoordinates(VarHandle target, int pos, Object... values) { 21 | return Handles.insertCoordinates(target, pos, values); 22 | } 23 | 24 | public static VarHandle permuteCoordinates(VarHandle target, List> newCoordinates, int... reorder) { 25 | return Handles.permuteCoordinates(target, newCoordinates, reorder); 26 | } 27 | 28 | public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter) { 29 | return Handles.collectCoordinates(target, pos, filter); 30 | } 31 | 32 | public static VarHandle dropCoordinates(VarHandle target, int pos, Class... valueTypes) { 33 | return Handles.dropCoordinates(target, pos, valueTypes); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/PaddingLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | public interface PaddingLayout extends MemoryLayout { 26 | @Override 27 | PaddingLayout withName(String name); 28 | 29 | @Override 30 | PaddingLayout withoutName(); 31 | 32 | PaddingLayout withByteAlignment(long byteAlignment); 33 | } 34 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/UnionLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | public interface UnionLayout extends GroupLayout { 26 | @Override 27 | UnionLayout withName(String name); 28 | 29 | @Override 30 | UnionLayout withoutName(); 31 | 32 | @Override 33 | UnionLayout withByteAlignment(long byteAlignment); 34 | } 35 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/StructLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | public interface StructLayout extends GroupLayout { 26 | 27 | @Override 28 | StructLayout withName(String name); 29 | 30 | @Override 31 | StructLayout withoutName(); 32 | 33 | @Override 34 | StructLayout withByteAlignment(long byteAlignment); 35 | } 36 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/foreign/Errno.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.foreign; 2 | 3 | import static com.v7878.unsafe.AndroidUnsafe.getIntN; 4 | import static com.v7878.unsafe.AndroidUnsafe.putIntN; 5 | import static com.v7878.unsafe.foreign.BulkLinker.CallType.CRITICAL; 6 | import static com.v7878.unsafe.foreign.BulkLinker.MapType.LONG_AS_WORD; 7 | 8 | import android.system.Os; 9 | 10 | import com.v7878.foreign.Arena; 11 | import com.v7878.r8.annotations.DoNotOptimize; 12 | import com.v7878.r8.annotations.DoNotShrink; 13 | import com.v7878.r8.annotations.DoNotShrinkType; 14 | import com.v7878.unsafe.foreign.BulkLinker.CallSignature; 15 | import com.v7878.unsafe.foreign.BulkLinker.LibrarySymbol; 16 | 17 | public class Errno { 18 | @DoNotShrinkType 19 | @DoNotOptimize 20 | private abstract static class Native { 21 | @DoNotShrink 22 | private static final Arena SCOPE = Arena.ofAuto(); 23 | 24 | @LibrarySymbol(name = "__errno") 25 | @CallSignature(type = CRITICAL, ret = LONG_AS_WORD, args = {}) 26 | abstract long __errno(); 27 | 28 | static final Native INSTANCE = BulkLinker.generateImpl(SCOPE, Native.class); 29 | } 30 | 31 | public static long __errno() { 32 | return Native.INSTANCE.__errno(); 33 | } 34 | 35 | public static int errno() { 36 | return getIntN(__errno()); 37 | } 38 | 39 | public static void errno(int value) { 40 | putIntN(__errno(), value); 41 | } 42 | 43 | public static String strerror(int errno) { 44 | return Os.strerror(errno); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/access/AsynchronousFileChannelHook.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.access; 2 | 3 | import com.v7878.r8.annotations.DoNotObfuscate; 4 | import com.v7878.r8.annotations.DoNotShrink; 5 | import com.v7878.unsafe.AsynchronousFileChannelBase; 6 | 7 | import java.nio.ByteBuffer; 8 | import java.nio.channels.CompletionHandler; 9 | import java.util.concurrent.Future; 10 | 11 | @DoNotShrink 12 | @DoNotObfuscate 13 | final class AsynchronousFileChannelHook extends AsynchronousFileChannelBase { 14 | @Override 15 | public void read(ByteBuffer dst, 16 | long position, 17 | A attachment, 18 | CompletionHandler handler) { 19 | JavaNioAccess.checkAsyncScope(dst); 20 | super.read(dst, position, attachment, handler); 21 | } 22 | 23 | @Override 24 | public Future read(ByteBuffer dst, long position) { 25 | JavaNioAccess.checkAsyncScope(dst); 26 | return super.read(dst, position); 27 | } 28 | 29 | @Override 30 | public void write(ByteBuffer src, 31 | long position, 32 | A attachment, 33 | CompletionHandler handler) { 34 | JavaNioAccess.checkAsyncScope(src); 35 | super.write(src, position, attachment, handler); 36 | } 37 | 38 | @Override 39 | public Future write(ByteBuffer src, long position) { 40 | JavaNioAccess.checkAsyncScope(src); 41 | return super.write(src, position); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LLVM/src/main/java/com/v7878/llvm/Extra.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import static com.v7878.unsafe.InstructionSet.CURRENT_INSTRUCTION_SET; 4 | 5 | public final class Extra { 6 | private Extra() { 7 | } 8 | 9 | public static String LLVMGetHostTriple() { 10 | // TODO _ZN4llvm3sys16getProcessTripleEv 11 | return LLVMGetHostCPUName() + "-unknown-linux-android"; 12 | } 13 | 14 | public static String LLVMGetHostCPUName() { 15 | // TODO _ZN4llvm3sys14getHostCPUNameEv 16 | return switch (CURRENT_INSTRUCTION_SET) { 17 | case X86 -> "i386"; 18 | case X86_64 -> "x86_64"; 19 | case ARM -> "arm"; 20 | case ARM64 -> "aarch64"; 21 | //TODO: RISCV64 22 | default -> throw new IllegalStateException( 23 | "unsupported instruction set: " + CURRENT_INSTRUCTION_SET); 24 | }; 25 | } 26 | 27 | public static String LLVMGetHostCPUFeatures() { 28 | // TODO _ZN4llvm3sys18getHostCPUFeaturesERNS_9StringMapIbNS_15MallocAllocatorEEE 29 | return switch (CURRENT_INSTRUCTION_SET) { 30 | case X86 -> "+x87,+mmx,+sse,+sse2,+sse3,+ssse3"; 31 | case X86_64 -> "+x87,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt"; 32 | case ARM -> "+armv7-a,+neon,-thumb-mode,+soft-float-abi"; 33 | case ARM64 -> "+fp-armv8,+neon,+v8a,+reserve-x18"; 34 | //TODO: RISCV64 35 | default -> throw new IllegalStateException( 36 | "unsupported instruction set: " + CURRENT_INSTRUCTION_SET); 37 | }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/GroupLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | import java.util.List; 26 | 27 | public interface GroupLayout extends MemoryLayout { 28 | List memberLayouts(); 29 | 30 | @Override 31 | GroupLayout withName(String name); 32 | 33 | @Override 34 | GroupLayout withoutName(); 35 | 36 | @Override 37 | GroupLayout withByteAlignment(long byteAlignment); 38 | } 39 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/Analysis.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import com.v7878.llvm.Types.LLVMModuleRef; 4 | import com.v7878.llvm.Types.LLVMValueRef; 5 | 6 | @SuppressWarnings("RedundantThrows") 7 | public final class Analysis { 8 | private Analysis() { 9 | throw new UnsupportedOperationException("Stub!"); 10 | } 11 | 12 | public enum LLVMVerifierFailureAction { 13 | LLVMAbortProcessAction, 14 | LLVMPrintMessageAction, 15 | LLVMReturnStatusAction 16 | } 17 | 18 | public static void LLVMVerifyFunction(LLVMValueRef Fn) throws LLVMException { 19 | throw new UnsupportedOperationException("Stub!"); 20 | } 21 | 22 | public static void LLVMVerifyFunction(LLVMValueRef Fn, LLVMVerifierFailureAction Action) throws LLVMException { 23 | throw new UnsupportedOperationException("Stub!"); 24 | } 25 | 26 | public static void LLVMVerifyModule(LLVMModuleRef M) throws LLVMException { 27 | throw new UnsupportedOperationException("Stub!"); 28 | } 29 | 30 | public static void LLVMVerifyModule(LLVMModuleRef M, LLVMVerifierFailureAction Action) throws LLVMException { 31 | throw new UnsupportedOperationException("Stub!"); 32 | } 33 | 34 | public static void LLVMViewFunctionCFG(LLVMValueRef Fn) { 35 | throw new UnsupportedOperationException("Stub!"); 36 | } 37 | 38 | public static void LLVMViewFunctionCFGOnly(LLVMValueRef Fn) { 39 | throw new UnsupportedOperationException("Stub!"); 40 | } 41 | 42 | public static boolean nLLVMVerifyFunction(LLVMValueRef Fn, LLVMVerifierFailureAction Action) { 43 | throw new UnsupportedOperationException("Stub!"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/InstructionSet.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe; 2 | 3 | public enum InstructionSet { 4 | ARM(8, 8, 8), 5 | ARM64(16, 8, 16), 6 | X86(16, 4, 8), 7 | X86_64(16, 8, 16), 8 | RISCV64(16, 8, 16); 9 | 10 | public static final InstructionSet CURRENT_INSTRUCTION_SET; 11 | 12 | static { 13 | String iset = VM.getCurrentInstructionSet(); 14 | CURRENT_INSTRUCTION_SET = switch (iset) { 15 | case "arm" -> InstructionSet.ARM; 16 | case "arm64" -> InstructionSet.ARM64; 17 | case "x86" -> InstructionSet.X86; 18 | case "x86_64" -> InstructionSet.X86_64; 19 | case "riscv64" -> InstructionSet.RISCV64; 20 | default -> throw new IllegalStateException("unsupported instruction set: " + iset); 21 | }; 22 | } 23 | 24 | private final int code_alignment; 25 | private final int alignof_long_long; 26 | private final int alignof_double; 27 | private final int stdcpp_default_new_alignment; 28 | 29 | InstructionSet(int code_alignment, int alignof_ll_and_d, int stdcpp_default_new_alignment) { 30 | this.code_alignment = code_alignment; 31 | this.alignof_long_long = alignof_ll_and_d; 32 | this.alignof_double = alignof_ll_and_d; 33 | this.stdcpp_default_new_alignment = stdcpp_default_new_alignment; 34 | } 35 | 36 | public int codeAlignment() { 37 | return code_alignment; 38 | } 39 | 40 | public int alignofLongLong() { 41 | return alignof_long_long; 42 | } 43 | 44 | public int alignofDouble() { 45 | return alignof_double; 46 | } 47 | 48 | public int stdcppDefaultNewAlignment() { 49 | return stdcpp_default_new_alignment; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/SequenceLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | public interface SequenceLayout extends MemoryLayout { 26 | 27 | MemoryLayout elementLayout(); 28 | 29 | long elementCount(); 30 | 31 | SequenceLayout withElementCount(long elementCount); 32 | 33 | SequenceLayout reshape(long... elementCounts); 34 | 35 | SequenceLayout flatten(); 36 | 37 | @Override 38 | SequenceLayout withName(String name); 39 | 40 | @Override 41 | MemoryLayout withoutName(); 42 | 43 | SequenceLayout withByteAlignment(long byteAlignment); 44 | } 45 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/AddressLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | import java.nio.ByteOrder; 26 | import java.util.Optional; 27 | 28 | public interface AddressLayout extends ValueLayout { 29 | 30 | @Override 31 | AddressLayout withName(String name); 32 | 33 | @Override 34 | AddressLayout withoutName(); 35 | 36 | @Override 37 | AddressLayout withByteAlignment(long byteAlignment); 38 | 39 | @Override 40 | AddressLayout withOrder(ByteOrder order); 41 | 42 | AddressLayout withTargetLayout(MemoryLayout layout); 43 | 44 | AddressLayout withoutTargetLayout(); 45 | 46 | Optional targetLayout(); 47 | } 48 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/WrongThreadException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | public final class WrongThreadException extends RuntimeException { 26 | public WrongThreadException() { 27 | throw new UnsupportedOperationException("Stub!"); 28 | } 29 | 30 | public WrongThreadException(String s) { 31 | throw new UnsupportedOperationException("Stub!"); 32 | } 33 | 34 | public WrongThreadException(String message, Throwable cause) { 35 | throw new UnsupportedOperationException("Stub!"); 36 | } 37 | 38 | public WrongThreadException(Throwable cause) { 39 | throw new UnsupportedOperationException("Stub!"); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/Arena.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | public interface Arena extends SegmentAllocator, AutoCloseable { 26 | 27 | static Arena ofAuto() { 28 | throw new UnsupportedOperationException("Stub!"); 29 | } 30 | 31 | static Arena global() { 32 | throw new UnsupportedOperationException("Stub!"); 33 | } 34 | 35 | static Arena ofConfined() { 36 | throw new UnsupportedOperationException("Stub!"); 37 | } 38 | 39 | static Arena ofShared() { 40 | throw new UnsupportedOperationException("Stub!"); 41 | } 42 | 43 | @Override 44 | MemorySegment allocate(long byteSize, long byteAlignment); 45 | 46 | MemorySegment.Scope scope(); 47 | 48 | @Override 49 | void close(); 50 | } 51 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/Initialization.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import com.v7878.llvm.Types.LLVMPassRegistryRef; 4 | 5 | public final class Initialization { 6 | private Initialization() { 7 | throw new UnsupportedOperationException("Stub!"); 8 | } 9 | 10 | public static void LLVMInitializeAnalysis(LLVMPassRegistryRef R) { 11 | throw new UnsupportedOperationException("Stub!"); 12 | } 13 | 14 | public static void LLVMInitializeCodeGen(LLVMPassRegistryRef R) { 15 | throw new UnsupportedOperationException("Stub!"); 16 | } 17 | 18 | public static void LLVMInitializeCore(LLVMPassRegistryRef R) { 19 | throw new UnsupportedOperationException("Stub!"); 20 | } 21 | 22 | public static void LLVMInitializeIPA(LLVMPassRegistryRef R) { 23 | throw new UnsupportedOperationException("Stub!"); 24 | } 25 | 26 | public static void LLVMInitializeIPO(LLVMPassRegistryRef R) { 27 | throw new UnsupportedOperationException("Stub!"); 28 | } 29 | 30 | public static void LLVMInitializeInstCombine(LLVMPassRegistryRef R) { 31 | throw new UnsupportedOperationException("Stub!"); 32 | } 33 | 34 | public static void LLVMInitializeInstrumentation(LLVMPassRegistryRef R) { 35 | throw new UnsupportedOperationException("Stub!"); 36 | } 37 | 38 | public static void LLVMInitializeObjCARCOpts(LLVMPassRegistryRef R) { 39 | throw new UnsupportedOperationException("Stub!"); 40 | } 41 | 42 | public static void LLVMInitializeScalarOpts(LLVMPassRegistryRef R) { 43 | throw new UnsupportedOperationException("Stub!"); 44 | } 45 | 46 | public static void LLVMInitializeTarget(LLVMPassRegistryRef R) { 47 | throw new UnsupportedOperationException("Stub!"); 48 | } 49 | 50 | public static void LLVMInitializeTransformUtils(LLVMPassRegistryRef R) { 51 | throw new UnsupportedOperationException("Stub!"); 52 | } 53 | 54 | public static void LLVMInitializeVectorization(LLVMPassRegistryRef R) { 55 | throw new UnsupportedOperationException("Stub!"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /stubs/buffers/src/main/java/com/v7878/unsafe/AsynchronousSocketChannelBase.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.channels.CompletionHandler; 5 | import java.util.concurrent.Future; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | // Compile-time stub, real class will be generated at runtime 9 | public class AsynchronousSocketChannelBase { 10 | public void read(ByteBuffer dst, 11 | long timeout, 12 | TimeUnit unit, 13 | A attachment, 14 | CompletionHandler handler) { 15 | throw new UnsupportedOperationException("Stub!"); 16 | } 17 | 18 | public Future read(ByteBuffer dst) { 19 | throw new UnsupportedOperationException("Stub!"); 20 | } 21 | 22 | public void read(ByteBuffer[] dsts, 23 | int offset, 24 | int length, 25 | long timeout, 26 | TimeUnit unit, 27 | A attachment, 28 | CompletionHandler handler) { 29 | throw new UnsupportedOperationException("Stub!"); 30 | } 31 | 32 | public void write(ByteBuffer src, 33 | long timeout, 34 | TimeUnit unit, 35 | A attachment, 36 | CompletionHandler handler) { 37 | throw new UnsupportedOperationException("Stub!"); 38 | } 39 | 40 | public Future write(ByteBuffer src) { 41 | throw new UnsupportedOperationException("Stub!"); 42 | } 43 | 44 | public void write(ByteBuffer[] srcs, 45 | int offset, 46 | int length, 47 | long timeout, 48 | TimeUnit unit, 49 | A attachment, 50 | CompletionHandler handler) { 51 | throw new UnsupportedOperationException("Stub!"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/SymbolLookup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | import java.nio.file.Path; 26 | import java.util.Optional; 27 | 28 | @FunctionalInterface 29 | public interface SymbolLookup { 30 | 31 | Optional find(String name); 32 | 33 | default SymbolLookup or(SymbolLookup other) { 34 | throw new UnsupportedOperationException("Stub!"); 35 | } 36 | 37 | default MemorySegment findOrThrow(String name) { 38 | throw new UnsupportedOperationException("Stub!"); 39 | } 40 | 41 | static SymbolLookup loaderLookup() { 42 | throw new UnsupportedOperationException("Stub!"); 43 | } 44 | 45 | static SymbolLookup libraryLookup(String name, Arena arena) { 46 | throw new UnsupportedOperationException("Stub!"); 47 | } 48 | 49 | static SymbolLookup libraryLookup(Path path, Arena arena) { 50 | throw new UnsupportedOperationException("Stub!"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/FunctionDescriptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | import java.lang.invoke.MethodType; 26 | import java.util.List; 27 | import java.util.Optional; 28 | 29 | public interface FunctionDescriptor { 30 | Optional returnLayout(); 31 | 32 | List argumentLayouts(); 33 | 34 | FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts); 35 | 36 | FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts); 37 | 38 | FunctionDescriptor changeReturnLayout(MemoryLayout newReturn); 39 | 40 | FunctionDescriptor dropReturnLayout(); 41 | 42 | MethodType toMethodType(); 43 | 44 | static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) { 45 | throw new UnsupportedOperationException("Stub!"); 46 | } 47 | 48 | static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) { 49 | throw new UnsupportedOperationException("Stub!"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/cpp_std/vector.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.cpp_std; 2 | 3 | import static com.v7878.foreign.MemoryLayout.sequenceLayout; 4 | import static com.v7878.foreign.MemoryLayout.structLayout; 5 | import static com.v7878.foreign.ValueLayout.ADDRESS; 6 | 7 | import com.v7878.foreign.MemoryLayout; 8 | import com.v7878.foreign.MemorySegment; 9 | 10 | import java.util.Objects; 11 | 12 | public final class vector { 13 | 14 | public final MemoryLayout ELEMENT; 15 | public final MemoryLayout LAYOUT; 16 | 17 | public vector(MemoryLayout element) { 18 | this.ELEMENT = Objects.requireNonNull(element); 19 | this.LAYOUT = structLayout(sequenceLayout(3, ADDRESS)); 20 | } 21 | 22 | public class impl { 23 | private final MemorySegment vec; 24 | 25 | public impl(MemorySegment vec) { 26 | this.vec = vec.asSlice(0, LAYOUT); 27 | } 28 | 29 | public MemorySegment begin() { 30 | return vec.get(ADDRESS, 0); 31 | } 32 | 33 | public MemorySegment end() { 34 | return vec.get(ADDRESS, ADDRESS.byteSize()); 35 | } 36 | 37 | public MemorySegment end_of_storage() { 38 | return vec.get(ADDRESS, ADDRESS.byteSize() * 2); 39 | } 40 | 41 | public long byte_size() { 42 | return end().nativeAddress() - begin().nativeAddress(); 43 | } 44 | 45 | public long size() { 46 | return byte_size() / ELEMENT.byteSize(); 47 | } 48 | 49 | public long byte_capacity() { 50 | return end_of_storage().nativeAddress() - begin().nativeAddress(); 51 | } 52 | 53 | public long capacity() { 54 | return byte_capacity() / ELEMENT.byteSize(); 55 | } 56 | 57 | public MemorySegment data() { 58 | return begin().reinterpret(byte_size()); 59 | } 60 | 61 | public void destruct() { 62 | long data = begin().nativeAddress(); 63 | if (data != 0) { 64 | MemoryOperators.delete(data, ELEMENT.byteAlignment()); 65 | } 66 | } 67 | 68 | // TODO: public void assign(MemorySegment data) {} 69 | } 70 | } -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/invoke/MethodTypeForm.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.invoke; 2 | 3 | import static com.v7878.unsafe.invoke.EmulatedStackFrame.RETURN_VALUE_IDX; 4 | 5 | import com.v7878.r8.annotations.DoNotObfuscate; 6 | import com.v7878.r8.annotations.DoNotShrink; 7 | import com.v7878.unsafe.DangerLevel; 8 | 9 | import java.lang.invoke.MethodType; 10 | 11 | @DoNotObfuscate 12 | public interface MethodTypeForm { 13 | MethodType erasedType(); 14 | 15 | MethodType basicType(); 16 | 17 | int parameterCount(); 18 | 19 | int parameterSlotCount(); 20 | 21 | int returnCount(); 22 | 23 | int returnSlotCount(); 24 | 25 | int primitiveParameterCount(); 26 | 27 | int longPrimitiveParameterCount(); 28 | 29 | int primitiveReturnCount(); 30 | 31 | int longPrimitiveReturnCount(); 32 | 33 | boolean hasPrimitives(); 34 | 35 | boolean hasNonVoidPrimitives(); 36 | 37 | boolean hasLongPrimitives(); 38 | 39 | int parameterToArgSlot(int i); 40 | 41 | int argSlotToParameter(int argSlot); 42 | 43 | @DangerLevel(DangerLevel.VERY_CAREFUL) 44 | @DoNotShrink 45 | int[] primitivesOffsets(); 46 | 47 | default int primitivesCount() { 48 | var prims = primitivesOffsets(); 49 | return prims[prims.length - 1]; 50 | } 51 | 52 | default int parameterToPrimitivesOffset(int i) { 53 | int[] offsets = primitivesOffsets(); 54 | if (i == RETURN_VALUE_IDX) { 55 | return offsets[offsets.length - 1]; 56 | } 57 | return offsets[i]; 58 | } 59 | 60 | @DangerLevel(DangerLevel.VERY_CAREFUL) 61 | @DoNotShrink 62 | int[] referencesOffsets(); 63 | 64 | default int referencesCount() { 65 | var refs = referencesOffsets(); 66 | return refs[refs.length - 1]; 67 | } 68 | 69 | default int parameterToReferencesOffset(int i) { 70 | int[] offsets = referencesOffsets(); 71 | if (i == RETURN_VALUE_IDX) { 72 | return offsets[offsets.length - 1]; 73 | } 74 | return offsets[i]; 75 | } 76 | 77 | // reverse-shorty, where return type is stored after parameter types 78 | @DoNotShrink 79 | String rshorty(); 80 | } 81 | -------------------------------------------------------------------------------- /Core/src/main/java/com/v7878/foreign/_LLVMStorageDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.v7878.foreign; 2 | 3 | import java.util.Objects; 4 | 5 | final class _LLVMStorageDescriptor { 6 | public static sealed class LLVMStorage { 7 | public final MemoryLayout layout; 8 | 9 | LLVMStorage(MemoryLayout layout) { 10 | this.layout = layout; 11 | } 12 | } 13 | 14 | // void or empty struct 15 | public static final class NoStorage extends LLVMStorage { 16 | NoStorage(MemoryLayout layout) { 17 | super(layout); 18 | } 19 | } 20 | 21 | // primitive types 22 | public static final class RawStorage extends LLVMStorage { 23 | RawStorage(MemoryLayout layout) { 24 | super(Objects.requireNonNull(layout)); 25 | assert layout instanceof ValueLayout; 26 | } 27 | } 28 | 29 | // struct with 'byval' or 'sret' attribute 30 | public static final class MemoryStorage extends LLVMStorage { 31 | public final boolean add_attr; 32 | 33 | MemoryStorage(MemoryLayout layout, boolean add_attr) { 34 | super(Objects.requireNonNull(layout)); 35 | assert layout instanceof GroupLayout; 36 | this.add_attr = add_attr; 37 | } 38 | } 39 | 40 | // struct in registers 41 | public static final class WrapperStorage extends LLVMStorage { 42 | public final MemoryLayout wrapper; 43 | 44 | WrapperStorage(MemoryLayout layout, MemoryLayout wrapper) { 45 | super(Objects.requireNonNull(layout)); 46 | assert layout instanceof GroupLayout; 47 | this.wrapper = Objects.requireNonNull(wrapper); 48 | } 49 | } 50 | 51 | private final LLVMStorage ret; 52 | private final LLVMStorage[] args; 53 | 54 | _LLVMStorageDescriptor(LLVMStorage ret, LLVMStorage[] args) { 55 | this.ret = ret; 56 | this.args = args; 57 | } 58 | 59 | public LLVMStorage returnStorage() { 60 | return ret; 61 | } 62 | 63 | public LLVMStorage argumentStorage(int index) { 64 | return args[index]; 65 | } 66 | 67 | public LLVMStorage[] argumentStorages() { 68 | return args.clone(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /LLVM/src/main/java/com/v7878/llvm/Linker.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import static com.v7878.llvm._LibLLVM.LLVM; 4 | import static com.v7878.unsafe.foreign.BulkLinker.CallType.CRITICAL; 5 | import static com.v7878.unsafe.foreign.BulkLinker.MapType.BOOL_AS_INT; 6 | import static com.v7878.unsafe.foreign.BulkLinker.MapType.LONG_AS_WORD; 7 | 8 | import android.annotation.SuppressLint; 9 | 10 | import com.v7878.foreign.Arena; 11 | import com.v7878.llvm.Types.LLVMModuleRef; 12 | import com.v7878.r8.annotations.DoNotOptimize; 13 | import com.v7878.r8.annotations.DoNotShrink; 14 | import com.v7878.r8.annotations.DoNotShrinkType; 15 | import com.v7878.unsafe.foreign.BulkLinker; 16 | import com.v7878.unsafe.foreign.BulkLinker.CallSignature; 17 | import com.v7878.unsafe.foreign.BulkLinker.LibrarySymbol; 18 | 19 | /*===-- llvm-c/Linker.h - Module Linker C Interface -------------*- C++ -*-===*\ 20 | |* *| 21 | |* This file defines the C interface to the module/file/archive linker. *| 22 | |* *| 23 | \*===----------------------------------------------------------------------===*/ 24 | @SuppressLint("WrongCommentType") 25 | public final class Linker { 26 | private Linker() { 27 | } 28 | 29 | @DoNotShrinkType 30 | @DoNotOptimize 31 | private abstract static class Native { 32 | @DoNotShrink 33 | private static final Arena SCOPE = Arena.ofAuto(); 34 | 35 | @LibrarySymbol(name = "LLVMLinkModules2") 36 | @CallSignature(type = CRITICAL, ret = BOOL_AS_INT, args = {LONG_AS_WORD, LONG_AS_WORD}) 37 | abstract boolean LLVMLinkModules2(long Dest, long Src); 38 | 39 | static final Native INSTANCE = BulkLinker.generateImpl(SCOPE, Native.class, LLVM); 40 | } 41 | 42 | /** 43 | * Links the source module into the destination module. The source module is destroyed. 44 | * The return value is true if an error occurred, false otherwise. 45 | * Use the diagnostic handler to get any diagnostic message. 46 | */ 47 | public static boolean LLVMLinkModules2(LLVMModuleRef Dest, LLVMModuleRef Src) { 48 | return Native.INSTANCE.LLVMLinkModules2(Dest.value(), Src.value()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/StructLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | /** 32 | * A group layout whose member layouts are laid out one after the other. 33 | * 34 | * @implSpec Implementing classes are immutable, thread-safe and 35 | * value-based. 36 | */ 37 | public sealed interface StructLayout extends GroupLayout permits _StructLayoutImpl { 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | @Override 43 | StructLayout withName(String name); 44 | 45 | /** 46 | * {@inheritDoc} 47 | */ 48 | @Override 49 | StructLayout withoutName(); 50 | 51 | /** 52 | * {@inheritDoc} 53 | * 54 | * @throws IllegalArgumentException {@inheritDoc} 55 | */ 56 | @Override 57 | StructLayout withByteAlignment(long byteAlignment); 58 | } 59 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/UnionLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | /** 32 | * A group layout whose member layouts are laid out at the same starting offset. 33 | * 34 | * @implSpec Implementing classes are immutable, thread-safe and 35 | * value-based. 36 | */ 37 | public sealed interface UnionLayout extends GroupLayout permits _UnionLayoutImpl { 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | @Override 43 | UnionLayout withName(String name); 44 | 45 | /** 46 | * {@inheritDoc} 47 | */ 48 | @Override 49 | UnionLayout withoutName(); 50 | 51 | /** 52 | * {@inheritDoc} 53 | * 54 | * @throws IllegalArgumentException {@inheritDoc} 55 | */ 56 | @Override 57 | UnionLayout withByteAlignment(long byteAlignment); 58 | } 59 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_ArenaImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | final class _ArenaImpl implements Arena { 32 | 33 | private final _MemorySessionImpl session; 34 | 35 | _ArenaImpl(_MemorySessionImpl session) { 36 | this.session = session; 37 | } 38 | 39 | @Override 40 | public MemorySegment.Scope scope() { 41 | return session; 42 | } 43 | 44 | @Override 45 | public void close() { 46 | session.close(); 47 | } 48 | 49 | public _NativeMemorySegmentImpl allocateNoInit(long byteSize, long byteAlignment) { 50 | return _SegmentFactories.allocateNativeSegment(byteSize, byteAlignment, session, false); 51 | } 52 | 53 | @Override 54 | public _NativeMemorySegmentImpl allocate(long byteSize, long byteAlignment) { 55 | return _SegmentFactories.allocateNativeSegment(byteSize, byteAlignment, session, true); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_SlicingAllocator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | final class _SlicingAllocator implements SegmentAllocator { 32 | 33 | private final MemorySegment segment; 34 | 35 | private long sp = 0L; 36 | 37 | public _SlicingAllocator(MemorySegment segment) { 38 | this.segment = segment; 39 | } 40 | 41 | MemorySegment trySlice(long byteSize, long byteAlignment) { 42 | long min = segment.address(); 43 | long start = _Utils.alignUp(min + sp, byteAlignment) - min; 44 | MemorySegment slice = segment.asSlice(start, byteSize, byteAlignment); 45 | sp = start + byteSize; 46 | return slice; 47 | } 48 | 49 | @Override 50 | public MemorySegment allocate(long byteSize, long byteAlignment) { 51 | _Utils.checkAllocationSizeAndAlign(byteSize, byteAlignment); 52 | // try to slice from current segment first... 53 | return trySlice(byteSize, byteAlignment); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/IPO.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import com.v7878.llvm.Types.LLVMPassManagerRef; 4 | 5 | public final class IPO { 6 | private IPO() { 7 | throw new UnsupportedOperationException("Stub!"); 8 | } 9 | 10 | public static void LLVMAddAlwaysInlinerPass(LLVMPassManagerRef PM) { 11 | throw new UnsupportedOperationException("Stub!"); 12 | } 13 | 14 | public static void LLVMAddArgumentPromotionPass(LLVMPassManagerRef PM) { 15 | throw new UnsupportedOperationException("Stub!"); 16 | } 17 | 18 | public static void LLVMAddConstantMergePass(LLVMPassManagerRef PM) { 19 | throw new UnsupportedOperationException("Stub!"); 20 | } 21 | 22 | public static void LLVMAddDeadArgEliminationPass(LLVMPassManagerRef PM) { 23 | throw new UnsupportedOperationException("Stub!"); 24 | } 25 | 26 | public static void LLVMAddFunctionAttrsPass(LLVMPassManagerRef PM) { 27 | throw new UnsupportedOperationException("Stub!"); 28 | } 29 | 30 | public static void LLVMAddFunctionInliningPass(LLVMPassManagerRef PM) { 31 | throw new UnsupportedOperationException("Stub!"); 32 | } 33 | 34 | public static void LLVMAddGlobalDCEPass(LLVMPassManagerRef PM) { 35 | throw new UnsupportedOperationException("Stub!"); 36 | } 37 | 38 | public static void LLVMAddGlobalOptimizerPass(LLVMPassManagerRef PM) { 39 | throw new UnsupportedOperationException("Stub!"); 40 | } 41 | 42 | public static void LLVMAddIPConstantPropagationPass(LLVMPassManagerRef PM) { 43 | throw new UnsupportedOperationException("Stub!"); 44 | } 45 | 46 | public static void LLVMAddIPSCCPPass(LLVMPassManagerRef PM) { 47 | throw new UnsupportedOperationException("Stub!"); 48 | } 49 | 50 | public static void LLVMAddInternalizePass(LLVMPassManagerRef PM, int AllButMain) { 51 | throw new UnsupportedOperationException("Stub!"); 52 | } 53 | 54 | public static void LLVMAddPruneEHPass(LLVMPassManagerRef PM) { 55 | throw new UnsupportedOperationException("Stub!"); 56 | } 57 | 58 | public static void LLVMAddStripDeadPrototypesPass(LLVMPassManagerRef PM) { 59 | throw new UnsupportedOperationException("Stub!"); 60 | } 61 | 62 | public static void LLVMAddStripSymbolsPass(LLVMPassManagerRef PM) { 63 | throw new UnsupportedOperationException("Stub!"); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/PaddingLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | /** 32 | * A padding layout. A padding layout specifies the size of extra space which is 33 | * typically not accessed by applications, and is typically used for aligning member 34 | * layouts around word boundaries. 35 | * 36 | * @implSpec Implementing classes are immutable, thread-safe and 37 | * value-based. 38 | */ 39 | public sealed interface PaddingLayout extends MemoryLayout permits _PaddingLayoutImpl { 40 | 41 | /** 42 | * {@inheritDoc} 43 | */ 44 | @Override 45 | PaddingLayout withName(String name); 46 | 47 | /** 48 | * {@inheritDoc} 49 | */ 50 | @Override 51 | PaddingLayout withoutName(); 52 | 53 | /** 54 | * {@inheritDoc} 55 | * 56 | * @throws IllegalArgumentException {@inheritDoc} 57 | */ 58 | PaddingLayout withByteAlignment(long byteAlignment); 59 | } 60 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/io/Maps.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.io; 2 | 3 | import static com.v7878.unsafe.Utils.shouldNotHappen; 4 | 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Paths; 8 | import java.util.regex.Pattern; 9 | import java.util.stream.Stream; 10 | 11 | public class Maps { 12 | public record MMapEntry(long start, long end, String perms, 13 | long offset, int dev_major, int dev_minor, 14 | long inode, String path) { 15 | } 16 | 17 | public static Stream maps(String pid) { 18 | var file = Paths.get((String.format("/proc/%s/maps", pid))); 19 | 20 | try { 21 | //noinspection resource 22 | return Files.lines(file).map(line -> { 23 | var parts = line.split(" ", 6); 24 | assert parts.length >= 5; 25 | 26 | var range = parts[0].split("-"); 27 | long start = Long.parseUnsignedLong(range[0], 16); 28 | long end = Long.parseUnsignedLong(range[1], 16); 29 | 30 | String parms = parts[1]; 31 | 32 | long offset = Long.parseUnsignedLong(parts[2], 16); 33 | 34 | var dev = parts[3].split(":"); 35 | int devMajor = Integer.parseUnsignedInt(dev[0], 16); 36 | int devMinor = Integer.parseUnsignedInt(dev[1], 16); 37 | 38 | long inode = Long.parseUnsignedLong(parts[4], 16); 39 | 40 | String path; 41 | if (parts.length < 6) { 42 | path = null; 43 | } else { 44 | path = parts[5].trim(); 45 | if (path.isEmpty()) { 46 | path = null; 47 | } 48 | } 49 | 50 | return new MMapEntry(start, end, parms, offset, devMajor, devMinor, inode, path); 51 | }); 52 | } catch (IOException e) { 53 | throw shouldNotHappen(e); 54 | } 55 | } 56 | 57 | public static MMapEntry findFirstByPath(String path) { 58 | var pattern = Pattern.compile(path); 59 | try (var maps = maps("self")) { 60 | return maps.filter(entry -> entry.path() != null 61 | && pattern.matcher(entry.path()).matches()) 62 | .findFirst().orElse(null); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /LLVM/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.vanniktech.maven.publish.AndroidMultiVariantLibrary 2 | 3 | plugins { 4 | alias(libs.plugins.android.library) 5 | alias(libs.plugins.maven.publish) 6 | } 7 | 8 | android { 9 | namespace = "com.v7878.llvm" 10 | 11 | defaultConfig { 12 | consumerProguardFiles("consumer-rules.pro") 13 | } 14 | } 15 | 16 | dependencies { 17 | api(project(":Core")) 18 | 19 | implementation(project(":Unsafe")) 20 | implementation(libs.r8.annotations) 21 | } 22 | 23 | mavenPublishing { 24 | publishToMavenCentral(automaticRelease = false) 25 | signAllPublications() 26 | configure( 27 | AndroidMultiVariantLibrary( 28 | sourcesJar = true, 29 | publishJavadocJar = false, 30 | ) 31 | ) 32 | 33 | coordinates( 34 | groupId = "io.github.vova7878.panama", 35 | artifactId = "LLVM", 36 | version = project.version.toString() 37 | ) 38 | 39 | pom { 40 | name.set("PanamaPort-LLVM") 41 | description.set("Implementation of FFM API for Android 8.0+") 42 | inceptionYear.set("2025") 43 | url.set("https://github.com/vova7878/PanamaPort") 44 | 45 | licenses { 46 | license { 47 | name.set("MIT AND GPL-2.0-with-classpath-exception") 48 | url.set("https://github.com/vova7878/PanamaPort/blob/main/NOTICE") 49 | distribution.set("repository") 50 | comments.set( 51 | """ 52 | This artifact is licensed under both MIT and GPL-2.0 with Classpath Exception concurrently. 53 | - MIT applies to all parts of this project except for the code in `Core/src/openjdk` folder. 54 | - GPL-2.0 with Classpath Exception applies to code derived from OpenJDK in `Core/src/openjdk`. 55 | """.trimIndent() 56 | ) 57 | } 58 | } 59 | 60 | developers { 61 | developer { 62 | id.set("vova7878") 63 | name.set("Vladimir Kozelkov") 64 | url.set("https://github.com/vova7878") 65 | } 66 | } 67 | 68 | scm { 69 | url.set("https://github.com/vova7878/PanamaPort") 70 | connection.set("scm:git:git://github.com/vova7878/PanamaPort.git") 71 | developerConnection.set("scm:git:ssh://git@github.com/vova7878/PanamaPort.git") 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_UnionLayoutImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | import java.util.List; 32 | 33 | final class _UnionLayoutImpl extends _AbstractGroupLayout<_UnionLayoutImpl> implements UnionLayout { 34 | 35 | private _UnionLayoutImpl(List elements, long byteSize, long byteAlignment, long minByteAlignment, String name) { 36 | super(Kind.UNION, elements, byteSize, byteAlignment, minByteAlignment, name); 37 | } 38 | 39 | @Override 40 | _UnionLayoutImpl dup(long byteAlignment, String name) { 41 | return new _UnionLayoutImpl(memberLayouts(), byteSize(), byteAlignment, minByteAlignment, name); 42 | } 43 | 44 | public static UnionLayout of(List elements) { 45 | long size = 0; 46 | long align = 1; 47 | for (MemoryLayout elem : elements) { 48 | size = Math.max(size, elem.byteSize()); 49 | align = Math.max(align, elem.byteAlignment()); 50 | } 51 | return new _UnionLayoutImpl(elements, size, align, align, null); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /VarHandles/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.vanniktech.maven.publish.AndroidMultiVariantLibrary 2 | 3 | plugins { 4 | alias(libs.plugins.android.library) 5 | alias(libs.plugins.maven.publish) 6 | } 7 | 8 | android { 9 | namespace = "com.v7878.invoke" 10 | 11 | defaultConfig { 12 | consumerProguardFiles("consumer-rules.pro") 13 | } 14 | } 15 | 16 | dependencies { 17 | compileOnly(project(":stubs:invoke")) 18 | 19 | implementation(libs.r8.annotations) 20 | 21 | runtimeOnly(project(":Unsafe")) 22 | } 23 | 24 | mavenPublishing { 25 | publishToMavenCentral(automaticRelease = false) 26 | signAllPublications() 27 | configure( 28 | AndroidMultiVariantLibrary( 29 | sourcesJar = true, 30 | publishJavadocJar = false, 31 | ) 32 | ) 33 | 34 | coordinates( 35 | groupId = "io.github.vova7878.panama", 36 | artifactId = "VarHandles", 37 | version = project.version.toString() 38 | ) 39 | 40 | pom { 41 | name.set("PanamaPort-VarHandles") 42 | description.set("Implementation of FFM API for Android 8.0+") 43 | inceptionYear.set("2025") 44 | url.set("https://github.com/vova7878/PanamaPort") 45 | 46 | licenses { 47 | license { 48 | name.set("MIT AND GPL-2.0-with-classpath-exception") 49 | url.set("https://github.com/vova7878/PanamaPort/blob/main/NOTICE") 50 | distribution.set("repository") 51 | comments.set( 52 | """ 53 | This artifact is licensed under both MIT and GPL-2.0 with Classpath Exception concurrently. 54 | - MIT applies to all parts of this project except for the code in `Core/src/openjdk` folder. 55 | - GPL-2.0 with Classpath Exception applies to code derived from OpenJDK in `Core/src/openjdk`. 56 | """.trimIndent() 57 | ) 58 | } 59 | } 60 | 61 | developers { 62 | developer { 63 | id.set("vova7878") 64 | name.set("Vladimir Kozelkov") 65 | url.set("https://github.com/vova7878") 66 | } 67 | } 68 | 69 | scm { 70 | url.set("https://github.com/vova7878/PanamaPort") 71 | connection.set("scm:git:git://github.com/vova7878/PanamaPort.git") 72 | developerConnection.set("scm:git:ssh://git@github.com/vova7878/PanamaPort.git") 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_StructLayoutImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | import java.util.List; 32 | 33 | final class _StructLayoutImpl extends _AbstractGroupLayout<_StructLayoutImpl> implements StructLayout { 34 | 35 | private _StructLayoutImpl(List elements, long byteSize, long byteAlignment, long minByteAlignment, String name) { 36 | super(Kind.STRUCT, elements, byteSize, byteAlignment, minByteAlignment, name); 37 | } 38 | 39 | @Override 40 | _StructLayoutImpl dup(long byteAlignment, String name) { 41 | return new _StructLayoutImpl(memberLayouts(), byteSize(), byteAlignment, minByteAlignment, name); 42 | } 43 | 44 | public static StructLayout of(List elements) { 45 | long size = 0; 46 | long align = 1; 47 | for (MemoryLayout elem : elements) { 48 | if (size % elem.byteAlignment() != 0) { 49 | throw new IllegalArgumentException("Invalid alignment constraint for member layout: " + elem); 50 | } 51 | size = Math.addExact(size, elem.byteSize()); 52 | align = Math.max(align, elem.byteAlignment()); 53 | } 54 | return new _StructLayoutImpl(elements, size, align, align, null); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/Linker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | import java.lang.invoke.MethodHandle; 26 | import java.util.Map; 27 | 28 | public interface Linker { 29 | static Linker nativeLinker() { 30 | throw new UnsupportedOperationException("Stub!"); 31 | } 32 | 33 | MethodHandle downcallHandle(MemorySegment address, 34 | FunctionDescriptor function, 35 | Option... options); 36 | 37 | MethodHandle downcallHandle(FunctionDescriptor function, Option... options); 38 | 39 | MemorySegment upcallStub(MethodHandle target, 40 | FunctionDescriptor function, 41 | Arena arena, 42 | Linker.Option... options); 43 | 44 | SymbolLookup defaultLookup(); 45 | 46 | Map canonicalLayouts(); 47 | 48 | interface Option { 49 | static Option firstVariadicArg(int index) { 50 | throw new UnsupportedOperationException("Stub!"); 51 | } 52 | 53 | static Option captureCallState(String... capturedState) { 54 | throw new UnsupportedOperationException("Stub!"); 55 | } 56 | 57 | static StructLayout captureStateLayout() { 58 | throw new UnsupportedOperationException("Stub!"); 59 | } 60 | 61 | static Option critical(boolean allowHeapAccess) { 62 | throw new UnsupportedOperationException("Stub!"); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/EarlyNativeUtils.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe; 2 | 3 | import static com.v7878.unsafe.AndroidUnsafe.ARRAY_BYTE_BASE_OFFSET; 4 | 5 | import com.v7878.foreign.Arena; 6 | import com.v7878.foreign.MemorySegment; 7 | import com.v7878.unsafe.access.JavaForeignAccess; 8 | 9 | import java.io.ByteArrayOutputStream; 10 | import java.nio.charset.StandardCharsets; 11 | import java.util.Arrays; 12 | 13 | // TODO: refactor? 14 | public class EarlyNativeUtils { 15 | public static MemorySegment allocString(Arena arena, String value) { 16 | if (value == null) return MemorySegment.NULL; 17 | if (ExtraMemoryAccess.isEarlyNativeInitialized()) { 18 | return arena.allocateFrom(value); 19 | } 20 | 21 | byte[] data = value.getBytes(StandardCharsets.UTF_8); 22 | data = Arrays.copyOf(data, data.length + 1); 23 | MemorySegment out = JavaForeignAccess.allocateNoInit(data.length, 1, arena); 24 | AndroidUnsafe.copyMemory(data, ARRAY_BYTE_BASE_OFFSET, 25 | null, out.nativeAddress(), data.length); 26 | return out; 27 | } 28 | 29 | public static String segmentToString(MemorySegment segment) { 30 | if (MemorySegment.NULL.equals(segment)) return null; 31 | if (ExtraMemoryAccess.isEarlyNativeInitialized()) { 32 | return segment.reinterpret(Long.MAX_VALUE).getString(0); 33 | } 34 | 35 | ByteArrayOutputStream data = new ByteArrayOutputStream(); 36 | var base = JavaForeignAccess.unsafeGetBase(segment); 37 | var offset = JavaForeignAccess.unsafeGetOffset(segment); 38 | 39 | for (int i = 0; ; i++) { 40 | byte value = AndroidUnsafe.getByte(base, offset + i); 41 | if (value == 0) break; 42 | data.write(value); 43 | } 44 | 45 | return data.toString(); 46 | } 47 | 48 | public static void copy(MemorySegment srcSegment, long srcOffset, 49 | MemorySegment dstSegment, long dstOffset, long bytes) { 50 | if (bytes == 0) { 51 | return; 52 | } 53 | if (ExtraMemoryAccess.isEarlyNativeInitialized()) { 54 | MemorySegment.copy(srcSegment, srcOffset, dstSegment, dstOffset, bytes); 55 | } else { 56 | Object src_base = JavaForeignAccess.unsafeGetBase(srcSegment); 57 | long src_offset = JavaForeignAccess.unsafeGetOffset(srcSegment) + srcOffset; 58 | Object dst_base = JavaForeignAccess.unsafeGetBase(dstSegment); 59 | long dst_offset = JavaForeignAccess.unsafeGetOffset(dstSegment) + dstOffset; 60 | AndroidUnsafe.copyMemory(src_base, src_offset, dst_base, dst_offset, bytes); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.vanniktech.maven.publish.AndroidMultiVariantLibrary 2 | 3 | plugins { 4 | alias(libs.plugins.android.library) 5 | alias(libs.plugins.maven.publish) 6 | } 7 | 8 | android { 9 | namespace = "com.v7878.foreign" 10 | 11 | sourceSets { 12 | named("main") { 13 | java.srcDir("src/openjdk/java") 14 | } 15 | } 16 | 17 | defaultConfig { 18 | consumerProguardFiles("consumer-rules.pro") 19 | } 20 | } 21 | 22 | dependencies { 23 | compileOnly(project(":stubs:llvm")) 24 | 25 | api(project(":VarHandles")) 26 | 27 | implementation(project(":Unsafe")) 28 | 29 | implementation(libs.sun.cleaner) 30 | implementation(libs.r8.annotations) 31 | implementation(libs.dexfile) 32 | } 33 | 34 | mavenPublishing { 35 | publishToMavenCentral(automaticRelease = false) 36 | signAllPublications() 37 | configure( 38 | AndroidMultiVariantLibrary( 39 | sourcesJar = true, 40 | publishJavadocJar = false, 41 | ) 42 | ) 43 | 44 | coordinates( 45 | groupId = "io.github.vova7878.panama", 46 | artifactId = "Core", 47 | version = project.version.toString() 48 | ) 49 | 50 | pom { 51 | name.set("PanamaPort-Core") 52 | description.set("Implementation of FFM API for Android 8.0+") 53 | inceptionYear.set("2025") 54 | url.set("https://github.com/vova7878/PanamaPort") 55 | 56 | licenses { 57 | license { 58 | name.set("MIT AND GPL-2.0-with-classpath-exception") 59 | url.set("https://github.com/vova7878/PanamaPort/blob/main/NOTICE") 60 | distribution.set("repository") 61 | comments.set( 62 | """ 63 | This artifact is licensed under both MIT and GPL-2.0 with Classpath Exception concurrently. 64 | - MIT applies to all parts of this project except for the code in `Core/src/openjdk` folder. 65 | - GPL-2.0 with Classpath Exception applies to code derived from OpenJDK in `Core/src/openjdk`. 66 | """.trimIndent() 67 | ) 68 | } 69 | } 70 | 71 | developers { 72 | developer { 73 | id.set("vova7878") 74 | name.set("Vladimir Kozelkov") 75 | url.set("https://github.com/vova7878") 76 | } 77 | } 78 | 79 | scm { 80 | url.set("https://github.com/vova7878/PanamaPort") 81 | connection.set("scm:git:git://github.com/vova7878/PanamaPort.git") 82 | developerConnection.set("scm:git:ssh://git@github.com/vova7878/PanamaPort.git") 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## About 2 | 3 | `PanamaPort` is a library implementing the [Foreign Function & Memory API](https://openjdk.org/jeps/454) for Android 8.0+ (API level 26) 4 | 5 | ### Components 6 | 7 | This project contains 4 sublibraries: 8 | 9 | - Core - the entire public API and implementation of the Panama project 10 | - Unsafe - low-level implementation details and additional capabilities not provided by the original API 11 | - LLVM - bindings to the built-in libLLVM.so Android library 12 | - VarHandles - backport of java.lang.invoke.VarHandle which didn't exist in android 8.x 13 | 14 | ### Requirements 15 | 16 | - JDK 21+ 17 | - Gradle 8.7+ 18 | - Android Gradle plugin 8.6.0+ 19 | - compileSdk 35+ 20 | 21 | ### Get started 22 | 23 | Just add this library to the list of dependencies: 24 | 25 | ``` 26 | dependencies { 27 | implementation 'io.github.vova7878.panama:Core:v0.1.0' 28 | } 29 | ``` 30 | 31 | --- 32 | 33 | ### Supported features 34 | 35 | PanamaPort implements full Foreign Function & Memory API support, including: 36 | 37 | - Downcall handles - allows Java code to call foreign functions 38 | - Upcall stubs - allows foreign functions to call Java method handles 39 | - Linker options such as captureCallState("errno") and even critical(allowHeapAccess: true) 40 | - Access to native memory via VarHandles 41 | - Management of memory segments via Arenas 42 | - And much more 43 | 44 | ### Differences from the original API 45 | 46 | - Package java.lang.foreign moved to com.v7878.foreign package because it is a port and not part of the Java core library 47 | - WrongThreadException class is also in the com.v7878.foreign package because it doesn't exist on android 48 | - My implementation of VarHandle is used instead of java.lang.invoke.VarHandle 49 | 50 | ### What was added 51 | 52 | All non-standard apis added to the port are marked with `@PortAPI` annotation 53 | 54 | This includes just useful methods: 55 | 56 | - `MemoryLayout.valueLayout(Class, ByteOrder)` 57 | - `MemoryLayout.sequenceLayout(MemoryLayout)` 58 | - `MemoryLayout.paddedStructLayout(MemoryLayout...)` 59 | - `MemorySegment.nativeAddress()` 60 | 61 | Android-specific linker options: 62 | 63 | - `Option.allowExceptions()` and `Option.JNIEnvArg(int)` 64 | 65 | Port of methods outside the java.lang.foreign package: 66 | 67 | - `FileChannelUtils.map(FileChannel, MapMode, long, long, Arena)` 68 | 69 | ### Interaction with jextract 70 | 71 | Usually, to use the output of jextract, it is enough to fix package names. If something doesn't work properly, please create an issue 72 | 73 | ### Examples and tests 74 | 75 | Examples are available in [this](https://github.com/vova7878/PanamaExamples) repository. The same repository is where tests are ported from the OpenJ9 and Hotspot implementations 76 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/PassManagerBuilder.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import com.v7878.llvm.Types.LLVMPassManagerRef; 4 | 5 | public final class PassManagerBuilder { 6 | private PassManagerBuilder() { 7 | throw new UnsupportedOperationException("Stub!"); 8 | } 9 | 10 | public static final class LLVMPassManagerBuilderRef implements AutoCloseable { 11 | private LLVMPassManagerBuilderRef() { 12 | throw new UnsupportedOperationException("Stub!"); 13 | } 14 | 15 | public void close() { 16 | throw new UnsupportedOperationException("Stub!"); 17 | } 18 | } 19 | 20 | public static LLVMPassManagerBuilderRef LLVMPassManagerBuilderCreate() { 21 | throw new UnsupportedOperationException("Stub!"); 22 | } 23 | 24 | public static void LLVMPassManagerBuilderDispose(LLVMPassManagerBuilderRef PMB) { 25 | throw new UnsupportedOperationException("Stub!"); 26 | } 27 | 28 | public static void LLVMPassManagerBuilderPopulateFunctionPassManager(LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) { 29 | throw new UnsupportedOperationException("Stub!"); 30 | } 31 | 32 | public static void LLVMPassManagerBuilderPopulateLTOPassManager(LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM, boolean Internalize, boolean RunInliner) { 33 | throw new UnsupportedOperationException("Stub!"); 34 | } 35 | 36 | public static void LLVMPassManagerBuilderPopulateModulePassManager(LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) { 37 | throw new UnsupportedOperationException("Stub!"); 38 | } 39 | 40 | public static void LLVMPassManagerBuilderSetDisableSimplifyLibCalls(LLVMPassManagerBuilderRef PMB, boolean Value) { 41 | throw new UnsupportedOperationException("Stub!"); 42 | } 43 | 44 | public static void LLVMPassManagerBuilderSetDisableUnitAtATime(LLVMPassManagerBuilderRef PMB, boolean Value) { 45 | throw new UnsupportedOperationException("Stub!"); 46 | } 47 | 48 | public static void LLVMPassManagerBuilderSetDisableUnrollLoops(LLVMPassManagerBuilderRef PMB, boolean Value) { 49 | throw new UnsupportedOperationException("Stub!"); 50 | } 51 | 52 | public static void LLVMPassManagerBuilderSetOptLevel(LLVMPassManagerBuilderRef PMB, int OptLevel) { 53 | throw new UnsupportedOperationException("Stub!"); 54 | } 55 | 56 | public static void LLVMPassManagerBuilderSetSizeLevel(LLVMPassManagerBuilderRef PMB, int SizeLevel) { 57 | throw new UnsupportedOperationException("Stub!"); 58 | } 59 | 60 | public static void LLVMPassManagerBuilderUseInlinerWithThreshold(LLVMPassManagerBuilderRef PMB, int Threshold) { 61 | throw new UnsupportedOperationException("Stub!"); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Unsafe/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.vanniktech.maven.publish.AndroidMultiVariantLibrary 2 | 3 | plugins { 4 | alias(libs.plugins.android.library) 5 | alias(libs.plugins.maven.publish) 6 | alias(libs.plugins.raung) 7 | } 8 | 9 | android { 10 | namespace = "com.v7878.unsafe" 11 | 12 | defaultConfig { 13 | consumerProguardFiles("consumer-rules.pro") 14 | } 15 | 16 | buildFeatures { 17 | buildConfig = true 18 | } 19 | } 20 | 21 | dependencies { 22 | compileOnly(project(":stubs:buffers")) 23 | compileOnly(project(":stubs:panama")) 24 | compileOnly(project(":stubs:llvm")) 25 | 26 | api(libs.dexfile) 27 | 28 | implementation(libs.r8.annotations) 29 | implementation(libs.sun.unsafe) 30 | 31 | runtimeOnly(project(":LLVM")) 32 | runtimeOnly(project(":Core")) 33 | } 34 | 35 | mavenPublishing { 36 | publishToMavenCentral(automaticRelease = false) 37 | signAllPublications() 38 | configure( 39 | AndroidMultiVariantLibrary( 40 | sourcesJar = true, 41 | publishJavadocJar = false, 42 | ) 43 | ) 44 | 45 | coordinates( 46 | groupId = "io.github.vova7878.panama", 47 | artifactId = "Unsafe", 48 | version = project.version.toString() 49 | ) 50 | 51 | pom { 52 | name.set("PanamaPort-Unsafe") 53 | description.set("Implementation of FFM API for Android 8.0+") 54 | inceptionYear.set("2025") 55 | url.set("https://github.com/vova7878/PanamaPort") 56 | 57 | licenses { 58 | license { 59 | name.set("MIT AND GPL-2.0-with-classpath-exception") 60 | url.set("https://github.com/vova7878/PanamaPort/blob/main/NOTICE") 61 | distribution.set("repository") 62 | comments.set( 63 | """ 64 | This artifact is licensed under both MIT and GPL-2.0 with Classpath Exception concurrently. 65 | - MIT applies to all parts of this project except for the code in `Core/src/openjdk` folder. 66 | - GPL-2.0 with Classpath Exception applies to code derived from OpenJDK in `Core/src/openjdk`. 67 | """.trimIndent() 68 | ) 69 | } 70 | } 71 | 72 | developers { 73 | developer { 74 | id.set("vova7878") 75 | name.set("Vladimir Kozelkov") 76 | url.set("https://github.com/vova7878") 77 | } 78 | } 79 | 80 | scm { 81 | url.set("https://github.com/vova7878/PanamaPort") 82 | connection.set("scm:git:git://github.com/vova7878/PanamaPort.git") 83 | developerConnection.set("scm:git:ssh://git@github.com/vova7878/PanamaPort.git") 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/access/DirectSegmentByteBufferBase.raung: -------------------------------------------------------------------------------- 1 | .version 52 2 | .class public abstract com/v7878/unsafe/access/DirectSegmentByteBufferBase 3 | .super com/v7878/unsafe/DirectByteBuffer 4 | .auto frames 5 | 6 | .annotation build Lcom/v7878/r8/annotations/DoNotShrink; 7 | .end annotation 8 | 9 | .annotation build Lcom/v7878/r8/annotations/DoNotObfuscate; 10 | .end annotation 11 | 12 | .method public (Lcom/v7878/unsafe/DirectByteBuffer$MemoryRef;IIIIIZ)V 13 | aload 0 14 | aload 1 15 | iload 2 16 | iload 3 17 | iload 4 18 | iload 5 19 | iload 6 20 | iload 7 21 | invokespecial com/v7878/unsafe/DirectByteBuffer (Lcom/v7878/unsafe/DirectByteBuffer$MemoryRef;IIIIIZ)V 22 | return 23 | .end method 24 | 25 | .method protected abstract isLoadedImpl()Z 26 | .end method 27 | 28 | .method protected abstract loadImpl()Ljava/nio/MappedByteBuffer; 29 | .end method 30 | 31 | .method protected abstract forceImpl()Ljava/nio/MappedByteBuffer; 32 | .end method 33 | 34 | .method protected abstract forceImpl(II)Ljava/nio/MappedByteBuffer; 35 | .end method 36 | 37 | .method protected isLoadedSuper()Z 38 | aload 0 39 | invokespecial com/v7878/unsafe/DirectByteBuffer isLoaded ()Z 40 | ireturn 41 | .end method 42 | 43 | .method protected loadSuper()Ljava/nio/MappedByteBuffer; 44 | aload 0 45 | invokespecial com/v7878/unsafe/DirectByteBuffer load ()Ljava/nio/MappedByteBuffer; 46 | areturn 47 | .end method 48 | 49 | .method protected forceSuper()Ljava/nio/MappedByteBuffer; 50 | aload 0 51 | invokespecial com/v7878/unsafe/DirectByteBuffer force ()Ljava/nio/MappedByteBuffer; 52 | areturn 53 | .end method 54 | 55 | .method protected forceSuper(II)Ljava/nio/MappedByteBuffer; 56 | aload 0 57 | iload 1 58 | iload 2 59 | invokespecial com/v7878/unsafe/DirectByteBuffer force (II)Ljava/nio/MappedByteBuffer; 60 | areturn 61 | .end method 62 | 63 | .method public final isLoaded()Z 64 | aload 0 65 | invokevirtual com/v7878/unsafe/access/DirectSegmentByteBufferBase isLoadedImpl ()Z 66 | ireturn 67 | .end method 68 | 69 | .method public final load()Ljava/nio/MappedByteBuffer; 70 | aload 0 71 | invokevirtual com/v7878/unsafe/access/DirectSegmentByteBufferBase loadImpl ()Ljava/nio/MappedByteBuffer; 72 | areturn 73 | .end method 74 | 75 | .method public final force()Ljava/nio/MappedByteBuffer; 76 | aload 0 77 | invokevirtual com/v7878/unsafe/access/DirectSegmentByteBufferBase forceImpl ()Ljava/nio/MappedByteBuffer; 78 | areturn 79 | .end method 80 | 81 | .method public final force(II)Ljava/nio/MappedByteBuffer; 82 | aload 0 83 | iload 1 84 | iload 2 85 | invokevirtual com/v7878/unsafe/access/DirectSegmentByteBufferBase forceImpl (II)Ljava/nio/MappedByteBuffer; 86 | areturn 87 | .end method 88 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/WrongThreadException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | /** 32 | * Thrown to indicate that a method has been called on the wrong thread. 33 | */ 34 | public final class WrongThreadException extends RuntimeException { 35 | 36 | /** 37 | * Constructs a WrongThreadException with no detail message. 38 | */ 39 | public WrongThreadException() { 40 | super(); 41 | } 42 | 43 | /** 44 | * Constructs a WrongThreadException with the given detail message. 45 | * 46 | * @param s the String that contains a detailed message, can be null 47 | */ 48 | public WrongThreadException(String s) { 49 | super(s); 50 | } 51 | 52 | /** 53 | * Constructs a WrongThreadException with the given detail message and cause. 54 | * 55 | * @param message the detail message, can be null 56 | * @param cause the cause, can be null 57 | */ 58 | public WrongThreadException(String message, Throwable cause) { 59 | super(message, cause); 60 | } 61 | 62 | /** 63 | * Constructs a WrongThreadException with the given cause and a detail 64 | * message of {@code (cause==null ? null : cause.toString())} (which 65 | * typically contains the class and detail message of {@code cause}). 66 | * 67 | * @param cause the cause, can be null 68 | */ 69 | public WrongThreadException(Throwable cause) { 70 | super(cause); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_PaddingLayoutImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | import java.util.Objects; 32 | 33 | final class _PaddingLayoutImpl extends _AbstractLayout<_PaddingLayoutImpl> implements PaddingLayout { 34 | 35 | private _PaddingLayoutImpl(long byteSize) { 36 | this(byteSize, 1, null); 37 | } 38 | 39 | private _PaddingLayoutImpl(long byteSize, long byteAlignment, String name) { 40 | super(byteSize, byteAlignment, name); 41 | } 42 | 43 | // Port-changed 44 | @Override 45 | public String toString() { 46 | return decorateLayoutString("x"); 47 | } 48 | 49 | @Override 50 | public boolean equals(Object other) { 51 | return this == other || 52 | other instanceof _PaddingLayoutImpl otherPadding && 53 | super.equals(other) && 54 | byteSize() == otherPadding.byteSize(); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return Objects.hash(super.hashCode(), byteSize()); 60 | } 61 | 62 | @Override 63 | _PaddingLayoutImpl dup(long byteAlignment, String name) { 64 | return new _PaddingLayoutImpl(byteSize(), byteAlignment, name); 65 | } 66 | 67 | @Override 68 | public boolean hasNaturalAlignment() { 69 | return true; 70 | } 71 | 72 | public static PaddingLayout of(long byteSize) { 73 | return new _PaddingLayoutImpl(byteSize); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/foreign/PThread.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.foreign; 2 | 3 | import static com.v7878.foreign.ValueLayout.JAVA_INT; 4 | import static com.v7878.unsafe.foreign.BulkLinker.CallType.CRITICAL; 5 | import static com.v7878.unsafe.foreign.BulkLinker.MapType.INT; 6 | import static com.v7878.unsafe.foreign.BulkLinker.MapType.LONG_AS_WORD; 7 | 8 | import com.v7878.foreign.Arena; 9 | import com.v7878.foreign.MemorySegment; 10 | import com.v7878.r8.annotations.DoNotOptimize; 11 | import com.v7878.r8.annotations.DoNotShrink; 12 | import com.v7878.r8.annotations.DoNotShrinkType; 13 | import com.v7878.unsafe.foreign.BulkLinker.CallSignature; 14 | import com.v7878.unsafe.foreign.BulkLinker.LibrarySymbol; 15 | 16 | public class PThread { 17 | @DoNotShrinkType 18 | @DoNotOptimize 19 | private abstract static class Native { 20 | @DoNotShrink 21 | private static final Arena SCOPE = Arena.ofAuto(); 22 | 23 | @LibrarySymbol(name = "pthread_key_create") 24 | @CallSignature(type = CRITICAL, ret = INT, args = {LONG_AS_WORD, LONG_AS_WORD}) 25 | abstract int pthread_key_create(long key_ptr, long destructor); 26 | 27 | @LibrarySymbol(name = "pthread_key_delete") 28 | @CallSignature(type = CRITICAL, ret = INT, args = {INT}) 29 | abstract int pthread_key_delete(int key); 30 | 31 | @LibrarySymbol(name = "pthread_getspecific") 32 | @CallSignature(type = CRITICAL, ret = LONG_AS_WORD, args = {INT}) 33 | abstract long pthread_getspecific(int key); 34 | 35 | @LibrarySymbol(name = "pthread_setspecific") 36 | @CallSignature(type = CRITICAL, ret = INT, args = {INT, LONG_AS_WORD}) 37 | abstract int pthread_setspecific(int key, long value); 38 | 39 | static final Native INSTANCE = BulkLinker.generateImpl(SCOPE, Native.class); 40 | } 41 | 42 | public static int pthread_key_create(long destructor) { 43 | try (Arena arena = Arena.ofConfined()) { 44 | MemorySegment key = arena.allocate(JAVA_INT); 45 | int err = Native.INSTANCE.pthread_key_create(key.nativeAddress(), destructor); 46 | if (err != 0) { 47 | throw new NativeCodeException("pthread_key_create", err); 48 | } 49 | return key.get(JAVA_INT, 0); 50 | } 51 | } 52 | 53 | public static void pthread_key_delete(int key) { 54 | int err = Native.INSTANCE.pthread_key_delete(key); 55 | if (err != 0) { 56 | throw new NativeCodeException("pthread_key_delete", err); 57 | } 58 | } 59 | 60 | public static long pthread_getspecific(int key) { 61 | return Native.INSTANCE.pthread_getspecific(key); 62 | } 63 | 64 | public static void pthread_setspecific(int key, long value) { 65 | int err = Native.INSTANCE.pthread_setspecific(key, value); 66 | if (err != 0) { 67 | throw new NativeCodeException("pthread_setspecific", err); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/llvm/LLVMGlobals.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.llvm; 2 | 3 | import static com.v7878.llvm.Core.LLVMContextCreate; 4 | import static com.v7878.llvm.ErrorHandling.LLVMEnablePrettyStackTrace; 5 | import static com.v7878.llvm.Extra.LLVMGetHostCPUFeatures; 6 | import static com.v7878.llvm.Extra.LLVMGetHostCPUName; 7 | import static com.v7878.llvm.Extra.LLVMGetHostTriple; 8 | import static com.v7878.llvm.Target.LLVMInitializeNativeAsmParser; 9 | import static com.v7878.llvm.Target.LLVMInitializeNativeAsmPrinter; 10 | import static com.v7878.llvm.Target.LLVMInitializeNativeDisassembler; 11 | import static com.v7878.llvm.Target.LLVMInitializeNativeTarget; 12 | import static com.v7878.llvm.Target.LLVMInitializeNativeTargetInfo; 13 | import static com.v7878.llvm.Target.LLVMInitializeNativeTargetMC; 14 | import static com.v7878.llvm.TargetMachine.LLVMCodeGenOptLevel.LLVMCodeGenLevelDefault; 15 | import static com.v7878.llvm.TargetMachine.LLVMCodeModel.LLVMCodeModelDefault; 16 | import static com.v7878.llvm.TargetMachine.LLVMCreateTargetMachine; 17 | import static com.v7878.llvm.TargetMachine.LLVMGetTargetFromTriple; 18 | import static com.v7878.llvm.TargetMachine.LLVMRelocMode.LLVMRelocDefault; 19 | import static com.v7878.unsafe.Utils.DEBUG_BUILD; 20 | import static com.v7878.unsafe.Utils.nothrows_run; 21 | 22 | import com.v7878.llvm.Core; 23 | import com.v7878.llvm.TargetMachine.LLVMCodeGenOptLevel; 24 | import com.v7878.llvm.TargetMachine.LLVMCodeModel; 25 | import com.v7878.llvm.TargetMachine.LLVMRelocMode; 26 | import com.v7878.llvm.TargetMachine.LLVMTargetMachineRef; 27 | import com.v7878.llvm.TargetMachine.LLVMTargetRef; 28 | import com.v7878.llvm.Types.LLVMContextRef; 29 | 30 | public class LLVMGlobals { 31 | static { 32 | if (DEBUG_BUILD) { 33 | LLVMEnablePrettyStackTrace(); 34 | } 35 | 36 | LLVMInitializeNativeTarget(); 37 | LLVMInitializeNativeTargetInfo(); 38 | LLVMInitializeNativeTargetMC(); 39 | LLVMInitializeNativeAsmParser(); 40 | LLVMInitializeNativeAsmPrinter(); 41 | LLVMInitializeNativeDisassembler(); 42 | } 43 | 44 | public static final String HOST_TRIPLE = LLVMGetHostTriple(); 45 | public static final String HOST_CPU_NAME = LLVMGetHostCPUName(); 46 | public static final String HOST_CPU_FEATURES = LLVMGetHostCPUFeatures(); 47 | public static final LLVMTargetRef HOST_TARGET = nothrows_run(() -> LLVMGetTargetFromTriple(HOST_TRIPLE)); 48 | public static final LLVMContextRef GLOBAL_CONTEXT = nothrows_run(Core::LLVMGetGlobalContext); 49 | 50 | public static LLVMContextRef newContext() { 51 | return LLVMContextCreate(); 52 | } 53 | 54 | public static LLVMTargetMachineRef newHostMachine( 55 | LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc, LLVMCodeModel CodeModel) { 56 | return LLVMCreateTargetMachine(HOST_TARGET, HOST_TRIPLE, HOST_CPU_NAME, 57 | HOST_CPU_FEATURES, Level, Reloc, CodeModel); 58 | } 59 | 60 | public static LLVMTargetMachineRef newDefaultMachine() { 61 | return newHostMachine(LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/ArtVersion.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe; 2 | 3 | import static android.os.Build.VERSION.SDK_INT; 4 | import static android.os.Build.VERSION.SDK_INT_FULL; 5 | import static com.v7878.unsafe.Utils.LOG_TAG; 6 | import static com.v7878.unsafe.Utils.searchMethod; 7 | 8 | import android.util.Log; 9 | 10 | import java.lang.reflect.Method; 11 | import java.nio.ByteBuffer; 12 | 13 | public class ArtVersion { 14 | @ApiSensitive 15 | public static final int ART_INDEX = computeIndex(); 16 | 17 | public static final int A8p0 = 1; 18 | public static final int A8p1 = 2; 19 | public static final int A9 = 3; 20 | public static final int A10 = 4; 21 | public static final int A11 = 5; 22 | public static final int A12 = 6; 23 | public static final int A13 = 7; 24 | public static final int A14 = 8; 25 | public static final int A15 = 9; 26 | public static final int A16 = 10; 27 | public static final int A16p1 = 11; 28 | 29 | private static boolean is36p1() { 30 | try { 31 | Class.forName("java.lang.invoke.VirtualThread"); 32 | return true; 33 | } catch (ClassNotFoundException e) { 34 | return false; 35 | } 36 | } 37 | 38 | private static boolean is36() { 39 | try { 40 | Class.forName("java.lang.invoke.DirectMethodHandle"); 41 | return true; 42 | } catch (ClassNotFoundException e) { 43 | return false; 44 | } 45 | } 46 | 47 | private static boolean is35() { 48 | Method method = searchMethod(ByteBuffer.class.getDeclaredMethods(), 49 | "get", false, int.class, byte[].class); 50 | return method != null; 51 | } 52 | 53 | private static boolean is34() { 54 | Method method = searchMethod(Class.class.getDeclaredMethods(), 55 | "isSealed", false); 56 | return method != null; 57 | } 58 | 59 | private static boolean is33() { 60 | Method method = searchMethod(String.class.getDeclaredMethods(), 61 | "isBlank", false); 62 | return method != null; 63 | } 64 | 65 | private static int computeIndex() { 66 | int tmp = SDK_INT; 67 | 68 | if (tmp < 26) { 69 | throw new UnsupportedOperationException("SDK versions below 26 are not supported"); 70 | } 71 | 72 | // Android 12 introduces mainline project 73 | if (tmp <= 30) return tmp - 26 + A8p0; 74 | if (tmp > 36) { 75 | tmp = 36; 76 | Log.w(LOG_TAG, String.format("SDK version is too new: %s, maximum supported: %s", SDK_INT, 36)); 77 | } 78 | 79 | // At the moment, there is nothing above 36.1 80 | if (SDK_INT_FULL > 3600000 || is36p1()) return A16p1; 81 | 82 | if (tmp == 36 || is36()) return A16; 83 | if (tmp == 35 || is35()) return A15; 84 | if (tmp == 34 || is34()) return A14; 85 | if (tmp == 33 || is33()) return A13; 86 | 87 | //noinspection ConstantValue 88 | assert tmp == 31 || tmp == 32; 89 | // Art module is the same for api 32 and 31 90 | return A12; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_CapturableState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | import static com.v7878.foreign.ValueLayout.JAVA_INT; 32 | 33 | import com.v7878.unsafe.foreign.Errno; 34 | 35 | import java.util.ArrayList; 36 | import java.util.Map; 37 | 38 | final class _CapturableState { 39 | public static final StructLayout LAYOUT; 40 | private static final Map MASKS; 41 | 42 | static { 43 | LAYOUT = MemoryLayout.structLayout( 44 | JAVA_INT.withName("errno")); 45 | MASKS = Map.of( 46 | "errno", 1 << 2 47 | ); 48 | // Init errno 49 | Errno.errno(); 50 | } 51 | 52 | private _CapturableState() { 53 | } 54 | 55 | /** 56 | * Returns the mask for a supported capturable state, or throw an 57 | * IllegalArgumentException if no supported state with this name exists. 58 | */ 59 | public static int maskFromName(String name) { 60 | var ret = MASKS.get(name); 61 | if (ret == null) { 62 | throw new IllegalArgumentException( 63 | "Unknown name: " + name + ", must be one of: " 64 | + MASKS.keySet()); 65 | } 66 | return ret; 67 | } 68 | 69 | /** 70 | * Returns a collection-like display string for a captured state mask. 71 | * Enclosed with brackets. 72 | */ 73 | public static String displayString(int mask) { 74 | var displayList = new ArrayList<>(); // unordered 75 | for (var e : MASKS.entrySet()) { 76 | if ((mask & e.getValue()) != 0) { 77 | displayList.add(e.getKey()); 78 | } 79 | } 80 | return displayList.toString(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/access/AsynchronousSocketChannelHook.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.access; 2 | 3 | import com.v7878.r8.annotations.DoNotObfuscate; 4 | import com.v7878.r8.annotations.DoNotShrink; 5 | import com.v7878.unsafe.AsynchronousSocketChannelBase; 6 | 7 | import java.nio.ByteBuffer; 8 | import java.nio.channels.CompletionHandler; 9 | import java.util.Objects; 10 | import java.util.concurrent.Future; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | @DoNotShrink 14 | @DoNotObfuscate 15 | final class AsynchronousSocketChannelHook extends AsynchronousSocketChannelBase { 16 | private static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) { 17 | Objects.checkFromIndexSize(offset, length, bs.length); 18 | if ((offset == 0) && (length == bs.length)) { 19 | return bs; 20 | } 21 | ByteBuffer[] bs2 = new ByteBuffer[length]; 22 | System.arraycopy(bs, offset, bs2, 0, length); 23 | return bs2; 24 | } 25 | 26 | @Override 27 | public void read(ByteBuffer[] dsts, 28 | int offset, 29 | int length, 30 | long timeout, 31 | TimeUnit unit, 32 | A attachment, 33 | CompletionHandler handler) { 34 | dsts = subsequence(dsts, offset, length); 35 | JavaNioAccess.checkAsyncScope(dsts); 36 | super.read(dsts, 0, dsts.length, timeout, unit, attachment, handler); 37 | } 38 | 39 | @Override 40 | public void read(ByteBuffer dst, 41 | long timeout, 42 | TimeUnit unit, 43 | A attachment, 44 | CompletionHandler handler) { 45 | JavaNioAccess.checkAsyncScope(dst); 46 | super.read(dst, timeout, unit, attachment, handler); 47 | } 48 | 49 | @Override 50 | public Future read(ByteBuffer dst) { 51 | JavaNioAccess.checkAsyncScope(dst); 52 | return super.read(dst); 53 | } 54 | 55 | @Override 56 | public void write(ByteBuffer[] srcs, 57 | int offset, 58 | int length, 59 | long timeout, 60 | TimeUnit unit, 61 | A attachment, 62 | CompletionHandler handler) { 63 | srcs = subsequence(srcs, offset, length); 64 | JavaNioAccess.checkAsyncScope(srcs); 65 | super.write(srcs, 0, srcs.length, timeout, unit, attachment, handler); 66 | } 67 | 68 | @Override 69 | public void write(ByteBuffer src, 70 | long timeout, 71 | TimeUnit unit, 72 | A attachment, 73 | CompletionHandler handler) { 74 | JavaNioAccess.checkAsyncScope(src); 75 | super.write(src, timeout, unit, attachment, handler); 76 | } 77 | 78 | @Override 79 | public Future write(ByteBuffer src) { 80 | JavaNioAccess.checkAsyncScope(src); 81 | return super.write(src); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | 74 | 75 | @rem Execute Gradle 76 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 77 | 78 | :end 79 | @rem End local scope for the variables with windows NT shell 80 | if %ERRORLEVEL% equ 0 goto mainEnd 81 | 82 | :fail 83 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 84 | rem the _cmd.exe /c_ return code! 85 | set EXIT_CODE=%ERRORLEVEL% 86 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 87 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 88 | exit /b %EXIT_CODE% 89 | 90 | :mainEnd 91 | if "%OS%"=="Windows_NT" endlocal 92 | 93 | :omega 94 | -------------------------------------------------------------------------------- /LLVM/src/main/java/com/v7878/llvm/Vectorize.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import static com.v7878.llvm._LibLLVM.LLVM; 4 | import static com.v7878.unsafe.foreign.BulkLinker.CallType.CRITICAL; 5 | import static com.v7878.unsafe.foreign.BulkLinker.MapType.LONG_AS_WORD; 6 | import static com.v7878.unsafe.foreign.BulkLinker.MapType.VOID; 7 | 8 | import android.annotation.SuppressLint; 9 | 10 | import com.v7878.foreign.Arena; 11 | import com.v7878.llvm.Types.LLVMPassManagerRef; 12 | import com.v7878.r8.annotations.DoNotOptimize; 13 | import com.v7878.r8.annotations.DoNotShrink; 14 | import com.v7878.r8.annotations.DoNotShrinkType; 15 | import com.v7878.unsafe.foreign.BulkLinker; 16 | import com.v7878.unsafe.foreign.BulkLinker.CallSignature; 17 | import com.v7878.unsafe.foreign.BulkLinker.LibrarySymbol; 18 | 19 | /*===---------------------------Vectorize.h --------------------- -*- C -*-===*\ 20 | |*===----------- Vectorization Transformation Library C Interface ---------===*| 21 | |* *| 22 | |* This header declares the C interface to libLLVMVectorize.a, which *| 23 | |* implements various vectorization transformations of the LLVM IR. *| 24 | |* *| 25 | |* Many exotic languages can interoperate with C code but have a harder time *| 26 | |* with C++ due to name mangling. So in addition to C, this interface enables *| 27 | |* tools written in such languages. *| 28 | |* *| 29 | \*===----------------------------------------------------------------------===*/ 30 | @SuppressLint("WrongCommentType") 31 | public final class Vectorize { 32 | private Vectorize() { 33 | } 34 | 35 | /* 36 | * @defgroup LLVMCTransformsVectorize Vectorization transformations 37 | * @ingroup LLVMCTransforms 38 | */ 39 | 40 | @DoNotShrinkType 41 | @DoNotOptimize 42 | private abstract static class Native { 43 | @DoNotShrink 44 | private static final Arena SCOPE = Arena.ofAuto(); 45 | 46 | @LibrarySymbol(name = "LLVMAddBBVectorizePass") 47 | @CallSignature(type = CRITICAL, ret = VOID, args = {LONG_AS_WORD}) 48 | abstract void LLVMAddBBVectorizePass(long PM); 49 | 50 | @LibrarySymbol(name = "LLVMAddLoopVectorizePass") 51 | @CallSignature(type = CRITICAL, ret = VOID, args = {LONG_AS_WORD}) 52 | abstract void LLVMAddLoopVectorizePass(long PM); 53 | 54 | @LibrarySymbol(name = "LLVMAddSLPVectorizePass") 55 | @CallSignature(type = CRITICAL, ret = VOID, args = {LONG_AS_WORD}) 56 | abstract void LLVMAddSLPVectorizePass(long PM); 57 | 58 | static final Native INSTANCE = BulkLinker.generateImpl(SCOPE, Native.class, LLVM); 59 | } 60 | 61 | public static void LLVMAddBBVectorizePass(LLVMPassManagerRef PM) { 62 | Native.INSTANCE.LLVMAddBBVectorizePass(PM.value()); 63 | } 64 | 65 | public static void LLVMAddLoopVectorizePass(LLVMPassManagerRef PM) { 66 | Native.INSTANCE.LLVMAddLoopVectorizePass(PM.value()); 67 | } 68 | 69 | public static void LLVMAddSLPVectorizePass(LLVMPassManagerRef PM) { 70 | Native.INSTANCE.LLVMAddSLPVectorizePass(PM.value()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_ImplicitSession.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | import com.v7878.r8.annotations.DoNotShrink; 32 | import com.v7878.r8.annotations.KeepCode; 33 | import com.v7878.sun.cleaner.SunCleaner; 34 | import com.v7878.unsafe.Utils; 35 | 36 | import java.util.Objects; 37 | 38 | /** 39 | * This is an implicit, GC-backed memory session. Implicit sessions cannot be closed explicitly. 40 | * While it would be possible to model an implicit session as a non-closeable view of a shared 41 | * session, it is better to capture the fact that an implicit session is not just a non-closeable 42 | * view of some session which might be closeable. This is useful e.g. in the implementations of 43 | * {@link sun.nio.ch.DirectBuffer#address()}, where obtaining an address of a buffer instance associated 44 | * with a potentially closeable session is forbidden. 45 | */ 46 | sealed class _ImplicitSession extends _SharedSession { 47 | 48 | public _ImplicitSession(SunCleaner cleaner) { 49 | super(); 50 | this.state = NONCLOSEABLE; 51 | cleaner.register(this, resourceList); 52 | } 53 | 54 | @Override 55 | public void release0() { 56 | Utils.reachabilityFence(this); 57 | } 58 | 59 | @Override 60 | public void acquire0() { 61 | // do nothing 62 | } 63 | 64 | @Override 65 | public void justClose() { 66 | throw nonCloseable(); 67 | } 68 | 69 | /** 70 | * This is an implicit session that wraps a heap object. 71 | * Possible objects are: Java arrays, buffers and class loaders. 72 | */ 73 | static final class ImplicitHolderSession extends _ImplicitSession { 74 | @DoNotShrink 75 | final Object ref; 76 | 77 | @DoNotShrink 78 | @KeepCode 79 | public ImplicitHolderSession(SunCleaner cleaner, Object ref) { 80 | super(cleaner); 81 | this.ref = Objects.requireNonNull(ref); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/GroupLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | import java.util.List; 32 | 33 | /** 34 | * A compound layout that is an aggregation of multiple, heterogeneous 35 | * member layouts. There are two ways in which member layouts can be combined: 36 | * if member layouts are laid out one after the other, the resulting group layout is a 37 | * {@linkplain StructLayout struct layout}; conversely, if all member layouts are laid 38 | * out at the same starting offset, the resulting group layout is a 39 | * {@linkplain UnionLayout union layout}. 40 | * 41 | * @implSpec This class is immutable, thread-safe and 42 | * value-based. 43 | */ 44 | public sealed interface GroupLayout extends MemoryLayout permits StructLayout, UnionLayout { 45 | 46 | /** 47 | * {@return the member layouts of this group layout} 48 | * 49 | * @apiNote the order in which member layouts are returned is the same order in which 50 | * member layouts have been passed to one of the group layout factory methods 51 | * (see {@link MemoryLayout#structLayout(MemoryLayout...)} and 52 | * {@link MemoryLayout#unionLayout(MemoryLayout...)}). 53 | */ 54 | List memberLayouts(); 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | GroupLayout withName(String name); 61 | 62 | /** 63 | * {@inheritDoc} 64 | */ 65 | @Override 66 | GroupLayout withoutName(); 67 | 68 | /** 69 | * {@inheritDoc} 70 | * 71 | * @throws IllegalArgumentException {@inheritDoc} 72 | * @throws IllegalArgumentException if {@code byteAlignment} is less than {@code M}, 73 | * where {@code M} is the maximum alignment constraint in any of the 74 | * member layouts associated with this group layout 75 | */ 76 | @Override 77 | GroupLayout withByteAlignment(long byteAlignment); 78 | } 79 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_NativeMemorySegmentImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | import com.v7878.unsafe.AndroidUnsafe; 32 | import com.v7878.unsafe.access.JavaNioAccess; 33 | 34 | import java.nio.ByteBuffer; 35 | import java.util.Optional; 36 | 37 | /** 38 | * Implementation for native memory segments. A native memory segment is essentially a wrapper around 39 | * a native long address. 40 | */ 41 | sealed class _NativeMemorySegmentImpl extends _AbstractMemorySegmentImpl permits _MappedMemorySegmentImpl { 42 | 43 | final long min; 44 | 45 | _NativeMemorySegmentImpl(long min, long length, boolean readOnly, _MemorySessionImpl scope) { 46 | super(length, readOnly, scope); 47 | this.min = AndroidUnsafe.IS64BIT 48 | // On 64-bit systems, all the bits are used 49 | ? min 50 | // On 32-bit systems, normalize the upper unused 32-bits to zero 51 | : min & 0x0000_0000_FFFF_FFFFL; 52 | } 53 | 54 | @Override 55 | public long address() { 56 | return min; 57 | } 58 | 59 | @Override 60 | public Optional heapBase() { 61 | return Optional.empty(); 62 | } 63 | 64 | public final long maxByteAlignment() { 65 | return address() == 0 ? 1L << 62 : Long.lowestOneBit(address()); 66 | } 67 | 68 | @Override 69 | _NativeMemorySegmentImpl dup(long offset, long size, boolean readOnly, _MemorySessionImpl scope) { 70 | return new _NativeMemorySegmentImpl(min + offset, size, readOnly, scope); 71 | } 72 | 73 | @Override 74 | ByteBuffer makeByteBuffer() { 75 | return JavaNioAccess.newDirectByteBuffer(min, (int) this.length, null, scope); 76 | } 77 | 78 | @Override 79 | public boolean isNative() { 80 | return true; 81 | } 82 | 83 | @Override 84 | public long unsafeGetOffset() { 85 | return min; 86 | } 87 | 88 | @Override 89 | public Object unsafeGetBase() { 90 | return null; 91 | } 92 | 93 | @Override 94 | public long maxAlignMask() { 95 | return 0; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/access/DexFileAccess.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.access; 2 | 3 | import static com.v7878.unsafe.Reflection.getHiddenConstructor; 4 | import static com.v7878.unsafe.Reflection.getHiddenMethod; 5 | import static com.v7878.unsafe.Reflection.unreflect; 6 | import static com.v7878.unsafe.Utils.nothrows_run; 7 | 8 | import com.v7878.unsafe.ClassUtils; 9 | 10 | import java.lang.invoke.MethodHandle; 11 | import java.nio.ByteBuffer; 12 | 13 | import dalvik.system.DexFile; 14 | 15 | public class DexFileAccess { 16 | public static DexFile openDexFile(ByteBuffer[] bufs, ClassLoader loader) { 17 | class Holder { 18 | static final MethodHandle handle; 19 | 20 | static { 21 | Class elements = ClassUtils.sysClass( 22 | "[Ldalvik.system.DexPathList$Element;"); 23 | handle = unreflect(getHiddenConstructor(DexFile.class, 24 | ByteBuffer[].class, ClassLoader.class, elements)); 25 | } 26 | } 27 | return nothrows_run(() -> (DexFile) Holder.handle.invoke(bufs, loader, null)); 28 | } 29 | 30 | public static DexFile openDexFile(ByteBuffer buf) { 31 | class Holder { 32 | static final MethodHandle handle; 33 | 34 | static { 35 | handle = unreflect(getHiddenConstructor(DexFile.class, ByteBuffer.class)); 36 | } 37 | } 38 | return nothrows_run(() -> (DexFile) Holder.handle.invoke(buf)); 39 | } 40 | 41 | public static Object openCookie(ByteBuffer[] bufs, ClassLoader loader) { 42 | class Holder { 43 | static final MethodHandle handle; 44 | 45 | static { 46 | Class elements = ClassUtils.sysClass( 47 | "[Ldalvik.system.DexPathList$Element;"); 48 | handle = unreflect(getHiddenMethod(DexFile.class, "openInMemoryDexFiles", 49 | ByteBuffer[].class, ClassLoader.class, elements)); 50 | } 51 | } 52 | return nothrows_run(() -> Holder.handle.invoke(bufs, loader, null)); 53 | } 54 | 55 | public static Object openCookie(ByteBuffer buf) { 56 | class Holder { 57 | static final MethodHandle handle; 58 | 59 | static { 60 | handle = unreflect(getHiddenMethod(DexFile.class, 61 | "openInMemoryDexFile", ByteBuffer.class)); 62 | } 63 | } 64 | return nothrows_run(() -> Holder.handle.invoke(buf)); 65 | } 66 | 67 | public static Class defineClassNative( 68 | String name, ClassLoader loader, Object cookie, DexFile dexFile) { 69 | class Holder { 70 | static final MethodHandle handle; 71 | 72 | static { 73 | handle = unreflect(getHiddenMethod(DexFile.class, "defineClassNative", 74 | String.class, ClassLoader.class, Object.class, DexFile.class)); 75 | } 76 | } 77 | return nothrows_run(() -> (Class) Holder.handle.invoke(name, loader, cookie, dexFile)); 78 | } 79 | 80 | public static String[] getClassNameList(Object cookie) { 81 | class Holder { 82 | static final MethodHandle handle; 83 | 84 | static { 85 | handle = unreflect(getHiddenMethod(DexFile.class, 86 | "getClassNameList", Object.class)); 87 | } 88 | } 89 | return nothrows_run(() -> (String[]) Holder.handle.invoke(cookie)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/llvm/LLVMTypes.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.llvm; 2 | 3 | import static com.v7878.llvm.Core.LLVMDoubleTypeInContext; 4 | import static com.v7878.llvm.Core.LLVMFP128TypeInContext; 5 | import static com.v7878.llvm.Core.LLVMFloatTypeInContext; 6 | import static com.v7878.llvm.Core.LLVMFunctionType; 7 | import static com.v7878.llvm.Core.LLVMHalfTypeInContext; 8 | import static com.v7878.llvm.Core.LLVMInt128TypeInContext; 9 | import static com.v7878.llvm.Core.LLVMInt16TypeInContext; 10 | import static com.v7878.llvm.Core.LLVMInt1TypeInContext; 11 | import static com.v7878.llvm.Core.LLVMInt32TypeInContext; 12 | import static com.v7878.llvm.Core.LLVMInt64TypeInContext; 13 | import static com.v7878.llvm.Core.LLVMInt8TypeInContext; 14 | import static com.v7878.llvm.Core.LLVMPointerType; 15 | import static com.v7878.llvm.Core.LLVMVoidTypeInContext; 16 | import static com.v7878.llvm.Types.LLVMContextRef; 17 | import static com.v7878.llvm.Types.LLVMTypeRef; 18 | import static com.v7878.unsafe.AndroidUnsafe.IS64BIT; 19 | 20 | public class LLVMTypes { 21 | public static LLVMTypeRef ptr_t(LLVMTypeRef type) { 22 | return LLVMPointerType(type, 0); 23 | } 24 | 25 | public static LLVMTypeRef void_t(LLVMContextRef context) { 26 | return LLVMVoidTypeInContext(context); 27 | } 28 | 29 | public static LLVMTypeRef void_ptr_t(LLVMContextRef context) { 30 | return ptr_t(void_t(context)); 31 | } 32 | 33 | public static LLVMTypeRef int1_t(LLVMContextRef context) { 34 | return LLVMInt1TypeInContext(context); 35 | } 36 | 37 | public static LLVMTypeRef int8_t(LLVMContextRef context) { 38 | return LLVMInt8TypeInContext(context); 39 | } 40 | 41 | public static LLVMTypeRef int16_t(LLVMContextRef context) { 42 | return LLVMInt16TypeInContext(context); 43 | } 44 | 45 | public static LLVMTypeRef int32_t(LLVMContextRef context) { 46 | return LLVMInt32TypeInContext(context); 47 | } 48 | 49 | public static LLVMTypeRef int64_t(LLVMContextRef context) { 50 | return LLVMInt64TypeInContext(context); 51 | } 52 | 53 | public static LLVMTypeRef int128_t(LLVMContextRef context) { 54 | return LLVMInt128TypeInContext(context); 55 | } 56 | 57 | public static LLVMTypeRef intptr_t(LLVMContextRef context) { 58 | return IS64BIT ? int64_t(context) : int32_t(context); 59 | } 60 | 61 | public static LLVMTypeRef half_t(LLVMContextRef context) { 62 | return LLVMHalfTypeInContext(context); 63 | } 64 | 65 | public static LLVMTypeRef float_t(LLVMContextRef context) { 66 | return LLVMFloatTypeInContext(context); 67 | } 68 | 69 | public static LLVMTypeRef double_t(LLVMContextRef context) { 70 | return LLVMDoubleTypeInContext(context); 71 | } 72 | 73 | public static LLVMTypeRef fp128_t(LLVMContextRef context) { 74 | return LLVMFP128TypeInContext(context); 75 | } 76 | 77 | public static LLVMTypeRef function_t(LLVMTypeRef ret, LLVMTypeRef... args) { 78 | return LLVMFunctionType(ret, args, false); 79 | } 80 | 81 | public static LLVMTypeRef function_ptr_t(LLVMTypeRef ret, LLVMTypeRef... args) { 82 | return ptr_t(function_t(ret, args)); 83 | } 84 | 85 | public static LLVMTypeRef variadic_function_t(LLVMTypeRef ret, LLVMTypeRef... args) { 86 | return LLVMFunctionType(ret, args, true); 87 | } 88 | 89 | public static LLVMTypeRef variadic_function_ptr_t(LLVMTypeRef ret, LLVMTypeRef... args) { 90 | return ptr_t(variadic_function_t(ret, args)); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /stubs/llvm/src/main/java/com/v7878/llvm/Types.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | public final class Types { 4 | private Types() { 5 | throw new UnsupportedOperationException("Stub!"); 6 | } 7 | 8 | public static final class LLVMDiagnosticInfoRef { 9 | private LLVMDiagnosticInfoRef() { 10 | throw new UnsupportedOperationException("Stub!"); 11 | } 12 | } 13 | 14 | public static final class LLVMAttributeRef { 15 | private LLVMAttributeRef() { 16 | throw new UnsupportedOperationException("Stub!"); 17 | } 18 | } 19 | 20 | public static final class LLVMUseRef { 21 | private LLVMUseRef() { 22 | throw new UnsupportedOperationException("Stub!"); 23 | } 24 | } 25 | 26 | public static final class LLVMPassRegistryRef { 27 | private LLVMPassRegistryRef() { 28 | throw new UnsupportedOperationException("Stub!"); 29 | } 30 | } 31 | 32 | public static final class LLVMPassManagerRef implements AutoCloseable { 33 | private LLVMPassManagerRef() { 34 | throw new UnsupportedOperationException("Stub!"); 35 | } 36 | 37 | public void close() { 38 | throw new UnsupportedOperationException("Stub!"); 39 | } 40 | } 41 | 42 | public static final class LLVMModuleProviderRef implements AutoCloseable { 43 | private LLVMModuleProviderRef() { 44 | throw new UnsupportedOperationException("Stub!"); 45 | } 46 | 47 | public void close() { 48 | throw new UnsupportedOperationException("Stub!"); 49 | } 50 | } 51 | 52 | public static final class LLVMBuilderRef implements AutoCloseable { 53 | private LLVMBuilderRef() { 54 | throw new UnsupportedOperationException("Stub!"); 55 | } 56 | 57 | public void close() { 58 | throw new UnsupportedOperationException("Stub!"); 59 | } 60 | } 61 | 62 | public static final class LLVMBasicBlockRef { 63 | private LLVMBasicBlockRef() { 64 | throw new UnsupportedOperationException("Stub!"); 65 | } 66 | } 67 | 68 | public static final class LLVMValueRef { 69 | private LLVMValueRef() { 70 | throw new UnsupportedOperationException("Stub!"); 71 | } 72 | } 73 | 74 | public static final class LLVMTypeRef { 75 | private LLVMTypeRef() { 76 | throw new UnsupportedOperationException("Stub!"); 77 | } 78 | } 79 | 80 | public static final class LLVMModuleRef implements AutoCloseable { 81 | private LLVMModuleRef() { 82 | throw new UnsupportedOperationException("Stub!"); 83 | } 84 | 85 | public void close() { 86 | throw new UnsupportedOperationException("Stub!"); 87 | } 88 | } 89 | 90 | public static final class LLVMContextRef implements AutoCloseable { 91 | private LLVMContextRef() { 92 | throw new UnsupportedOperationException("Stub!"); 93 | } 94 | 95 | public void close() { 96 | throw new UnsupportedOperationException("Stub!"); 97 | } 98 | } 99 | 100 | public static final class LLVMMemoryBufferRef implements AutoCloseable { 101 | private LLVMMemoryBufferRef() { 102 | throw new UnsupportedOperationException("Stub!"); 103 | } 104 | 105 | public void close() { 106 | throw new UnsupportedOperationException("Stub!"); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/ArtModifiers.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe; 2 | 3 | import static com.v7878.unsafe.ArtVersion.A10; 4 | import static com.v7878.unsafe.ArtVersion.A11; 5 | import static com.v7878.unsafe.ArtVersion.A12; 6 | import static com.v7878.unsafe.ArtVersion.A13; 7 | import static com.v7878.unsafe.ArtVersion.A14; 8 | import static com.v7878.unsafe.ArtVersion.A15; 9 | import static com.v7878.unsafe.ArtVersion.A16; 10 | import static com.v7878.unsafe.ArtVersion.A16p1; 11 | import static com.v7878.unsafe.ArtVersion.A8p0; 12 | import static com.v7878.unsafe.ArtVersion.A8p1; 13 | import static com.v7878.unsafe.ArtVersion.A9; 14 | import static com.v7878.unsafe.ArtVersion.ART_INDEX; 15 | import static com.v7878.unsafe.Utils.unsupportedART; 16 | 17 | // TODO: Review after android 16 qpr 2 becomes stable 18 | public class ArtModifiers { 19 | @ApiSensitive 20 | public static final int kAccSkipAccessChecks = switch (ART_INDEX) { 21 | case A16p1, A16, A15, A14, A13, A12, A11, A10, A9, A8p1, A8p0 -> 0x00080000; 22 | default -> throw unsupportedART(ART_INDEX); 23 | }; 24 | 25 | @ApiSensitive 26 | public static final int kAccCopied = switch (ART_INDEX) { 27 | case A16p1, A16, A15, A14, A13, A12 -> 0x01000000; 28 | case A11, A10, A9, A8p1, A8p0 -> 0x00100000; 29 | default -> throw unsupportedART(ART_INDEX); 30 | }; 31 | 32 | @ApiSensitive 33 | public static final int kAccSingleImplementation = switch (ART_INDEX) { 34 | case A16p1, A16, A15, A14, A13, A12, A11, A10, A9, A8p1, A8p0 -> 0x08000000; 35 | default -> throw unsupportedART(ART_INDEX); 36 | }; 37 | 38 | @ApiSensitive 39 | public static final int kAccIntrinsic = 0x80000000; 40 | 41 | @ApiSensitive 42 | public static final int kAccCompileDontBother = switch (ART_INDEX) { 43 | case A16p1, A16, A15, A14, A13, A12, A11, A10, A9, A8p1 -> 0x02000000; 44 | case A8p0 -> 0x01000000; 45 | default -> throw unsupportedART(ART_INDEX); 46 | }; 47 | 48 | @ApiSensitive 49 | public static final int kAccPreCompiled = switch (ART_INDEX) { 50 | case A16p1, A16, A15, A14, A13, A12 -> 0x00800000; 51 | case A11 -> 0x00200000; 52 | case A10, A9, A8p1, A8p0 -> 0; 53 | default -> throw unsupportedART(ART_INDEX); 54 | }; 55 | 56 | @ApiSensitive 57 | public static final int kAccFastInterpreterToInterpreterInvoke = switch (ART_INDEX) { 58 | case A16p1, A16, A15, A14, A13, A9, A8p1, A8p0 -> 0; 59 | case A12, A11, A10 -> 0x40000000; 60 | default -> throw unsupportedART(ART_INDEX); 61 | }; 62 | 63 | @ApiSensitive 64 | public static final int kAccPublicApi = switch (ART_INDEX) { 65 | case A16p1, A16, A15, A14, A13, A12, A11, A10 -> 0x10000000; 66 | case A9, A8p1, A8p0 -> 0; 67 | default -> throw unsupportedART(ART_INDEX); 68 | }; 69 | 70 | @ApiSensitive 71 | public static final int kAccCorePlatformApi = switch (ART_INDEX) { 72 | case A16p1, A16, A15, A14, A13, A12, A11, A10 -> 0x20000000; 73 | case A9, A8p1, A8p0 -> 0; 74 | default -> throw unsupportedART(ART_INDEX); 75 | }; 76 | 77 | @ApiSensitive 78 | public static final int kAccHiddenapiBits = switch (ART_INDEX) { 79 | case A16p1, A16, A15, A14, A13, A12, A11, A10, A9 -> 0x30000000; 80 | case A8p1, A8p0 -> 0; 81 | default -> throw unsupportedART(ART_INDEX); 82 | }; 83 | 84 | static int makePublicApi(int flags) { 85 | if (ART_INDEX < A9) { 86 | return flags; 87 | } 88 | flags &= ~kAccHiddenapiBits; 89 | if (ART_INDEX == A9) { 90 | return flags; 91 | } 92 | return flags | kAccPublicApi; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Core/src/main/java/com/v7878/foreign/_JavaForeignAccessImpl.java: -------------------------------------------------------------------------------- 1 | package com.v7878.foreign; 2 | 3 | import com.v7878.foreign.MemorySegment.Scope; 4 | import com.v7878.foreign._MemorySessionImpl.ResourceList.ResourceCleanup; 5 | import com.v7878.r8.annotations.AlwaysInline; 6 | import com.v7878.unsafe.Utils.FineClosable; 7 | import com.v7878.unsafe.access.JavaNioAccess.UnmapperProxy; 8 | 9 | import java.util.Objects; 10 | 11 | @SuppressWarnings("unused") 12 | final class _JavaForeignAccessImpl { 13 | @AlwaysInline 14 | public static boolean isThreadConfined(Scope scope) { 15 | return ((_MemorySessionImpl) scope).ownerThread() != null; 16 | } 17 | 18 | @AlwaysInline 19 | public static FineClosable lock(Scope scope) { 20 | record SessionLock(_MemorySessionImpl session) implements FineClosable { 21 | SessionLock { 22 | session.acquire0(); 23 | } 24 | 25 | @Override 26 | public void close() { 27 | session.release0(); 28 | } 29 | } 30 | return scope == null ? FineClosable.NOP : 31 | new SessionLock((_MemorySessionImpl) scope); 32 | } 33 | 34 | @AlwaysInline 35 | public static void checkValidState(Scope scope) { 36 | ((_MemorySessionImpl) scope).checkValidState(); 37 | } 38 | 39 | @AlwaysInline 40 | public static void addCloseAction(Scope scope, Runnable cleanup) { 41 | ((_MemorySessionImpl) scope).addCloseAction(cleanup); 42 | } 43 | 44 | @AlwaysInline 45 | public static void addOrCleanupIfFail(Scope scope, Runnable cleanup) { 46 | ((_MemorySessionImpl) scope).addOrCleanupIfFail(ResourceCleanup.ofRunnable(cleanup)); 47 | } 48 | 49 | @AlwaysInline 50 | public static MemorySegment objectSegment(Object obj) { 51 | return _SegmentFactories.fromObject(obj); 52 | } 53 | 54 | @AlwaysInline 55 | public static Arena createGlobalHolderArena(Object ref) { 56 | return _MemorySessionImpl.createGlobalHolder(ref).asArena(); 57 | } 58 | 59 | @AlwaysInline 60 | public static Arena createImplicitHolderArena(Object ref) { 61 | return _MemorySessionImpl.createImplicitHolder(ref).asArena(); 62 | } 63 | 64 | @AlwaysInline 65 | public static MemorySegment makeNativeSegmentUnchecked( 66 | long min, long byteSize, boolean readOnly, Arena scope, Runnable action) { 67 | Objects.requireNonNull(scope); 68 | _Utils.checkNonNegativeArgument(byteSize, "byteSize"); 69 | return _SegmentFactories.makeNativeSegmentUnchecked(min, byteSize, 70 | _MemorySessionImpl.toMemorySession(scope), readOnly, action); 71 | } 72 | 73 | @AlwaysInline 74 | public static MemorySegment allocateNativeSegment( 75 | long byteSize, long byteAlignment, Arena scope, boolean init) { 76 | return _SegmentFactories.allocateNativeSegment(byteSize, byteAlignment, 77 | _MemorySessionImpl.toMemorySession(scope), init); 78 | } 79 | 80 | @AlwaysInline 81 | public static MemorySegment mapSegment( 82 | UnmapperProxy unmapper, long size, boolean readOnly, Arena scope) { 83 | return _SegmentFactories.mapSegment(unmapper, size, readOnly, 84 | _MemorySessionImpl.toMemorySession(scope)); 85 | } 86 | 87 | @AlwaysInline 88 | public static boolean hasNaturalAlignment(MemoryLayout layout) { 89 | return ((_AbstractLayout) layout).hasNaturalAlignment(); 90 | } 91 | 92 | @AlwaysInline 93 | public static long unsafeGetOffset(MemorySegment segment) { 94 | return ((_AbstractMemorySegmentImpl) segment).unsafeGetOffset(); 95 | } 96 | 97 | @AlwaysInline 98 | public static Object unsafeGetBase(MemorySegment segment) { 99 | return ((_AbstractMemorySegmentImpl) segment).unsafeGetBase(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_GlobalSession.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | import com.v7878.r8.annotations.DoNotShrink; 32 | import com.v7878.r8.annotations.KeepCode; 33 | import com.v7878.r8.annotations.NoSideEffects; 34 | 35 | import java.util.Objects; 36 | 37 | /** 38 | * The global, non-closeable, shared session. Similar to a shared session, but its {@link #close()} method throws unconditionally. 39 | * Adding new resources to the global session, does nothing: as the session can never become not-alive, there is nothing to track. 40 | * Acquiring and or releasing a memory session similarly does nothing. 41 | */ 42 | sealed class _GlobalSession extends _MemorySessionImpl { 43 | @NoSideEffects 44 | public static final _GlobalSession INSTANCE = new _GlobalSession(); 45 | 46 | public _GlobalSession() { 47 | super(null, null); 48 | this.state = NONCLOSEABLE; 49 | } 50 | 51 | @Override 52 | public void release0() { 53 | // do nothing 54 | } 55 | 56 | @Override 57 | public void acquire0() { 58 | // do nothing 59 | } 60 | 61 | @Override 62 | void addInternal(ResourceList.ResourceCleanup resource) { 63 | // do nothing 64 | } 65 | 66 | @Override 67 | public void justClose() { 68 | throw nonCloseable(); 69 | } 70 | 71 | /** 72 | * This is a global session that wraps a heap object. Possible objects are: Java arrays, buffers and 73 | * class loaders. Objects of two heap sessions are compared by identity. That is, if the wrapped object is the same, 74 | * then the resulting heap sessions are also considered equals. We do not compare the objects using 75 | * {@link Object#equals(Object)}, as that would be problematic when comparing buffers, whose equality and 76 | * hash codes are content-dependent. 77 | */ 78 | static final class GlobalHolderSession extends _GlobalSession { 79 | @DoNotShrink 80 | final Object ref; 81 | 82 | @DoNotShrink 83 | @KeepCode 84 | public GlobalHolderSession(Object ref) { 85 | this.ref = Objects.requireNonNull(ref); 86 | } 87 | 88 | @Override 89 | public boolean equals(Object obj) { 90 | return obj instanceof GlobalHolderSession session && 91 | ref == session.ref; 92 | } 93 | 94 | @Override 95 | public int hashCode() { 96 | return System.identityHashCode(ref); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_MappedMemorySegmentImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | import com.v7878.unsafe.access.JavaNioAccess; 32 | import com.v7878.unsafe.access.JavaNioAccess.UnmapperProxy; 33 | 34 | import java.io.FileDescriptor; 35 | import java.nio.ByteBuffer; 36 | import java.util.Objects; 37 | 38 | /** 39 | * Implementation for a mapped memory segments. A mapped memory segment is a native memory segment, which 40 | * additionally features an {@link UnmapperProxy} object. This object provides detailed information about the 41 | * memory mapped segment, such as the file descriptor associated with the mapping. This information is crucial 42 | * in order to correctly reconstruct a byte buffer object from the segment (see {@link #makeByteBuffer()}). 43 | */ 44 | final class _MappedMemorySegmentImpl extends _NativeMemorySegmentImpl { 45 | 46 | private final UnmapperProxy unmapper; 47 | 48 | public _MappedMemorySegmentImpl(long min, UnmapperProxy unmapper, long length, boolean readOnly, _MemorySessionImpl scope) { 49 | super(min, length, readOnly, scope); 50 | this.unmapper = Objects.requireNonNull(unmapper); 51 | } 52 | 53 | private FileDescriptor fileDescriptor() { 54 | return unmapper.fileDescriptor(); 55 | } 56 | 57 | @Override 58 | ByteBuffer makeByteBuffer() { 59 | return JavaNioAccess.newMappedByteBuffer(unmapper, min, (int) length, null, scope); 60 | } 61 | 62 | @Override 63 | _MappedMemorySegmentImpl dup(long offset, long size, boolean readOnly, _MemorySessionImpl scope) { 64 | return new _MappedMemorySegmentImpl(min + offset, unmapper, size, readOnly, scope); 65 | } 66 | 67 | // mapped segment methods 68 | 69 | @Override 70 | public _MappedMemorySegmentImpl asSlice(long offset, long newSize) { 71 | return (_MappedMemorySegmentImpl) super.asSlice(offset, newSize); 72 | } 73 | 74 | @Override 75 | public boolean isMapped() { 76 | return true; 77 | } 78 | 79 | // support for mapped segments 80 | 81 | public void load() { 82 | if (fileDescriptor() != null) { 83 | _ScopedMemoryAccess.load(sessionImpl(), min, length); 84 | } 85 | } 86 | 87 | public void unload() { 88 | if (fileDescriptor() != null) { 89 | _ScopedMemoryAccess.unload(sessionImpl(), min, length); 90 | } 91 | } 92 | 93 | public boolean isLoaded() { 94 | return fileDescriptor() == null || _ScopedMemoryAccess.isLoaded(sessionImpl(), min, length); 95 | } 96 | 97 | public void force() { 98 | if (fileDescriptor() != null) { 99 | _ScopedMemoryAccess.force(sessionImpl(), fileDescriptor(), min, 0, length); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /stubs/panama/src/main/java/com/v7878/foreign/MemoryLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Vladimir Kozelkov 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.v7878.foreign; 24 | 25 | import com.v7878.invoke.VarHandle; 26 | 27 | import java.lang.invoke.MethodHandle; 28 | import java.nio.ByteOrder; 29 | import java.util.Optional; 30 | 31 | public interface MemoryLayout { 32 | long byteSize(); 33 | 34 | Optional name(); 35 | 36 | MemoryLayout withName(String name); 37 | 38 | MemoryLayout withoutName(); 39 | 40 | long byteAlignment(); 41 | 42 | MemoryLayout withByteAlignment(long byteAlignment); 43 | 44 | long scale(long offset, long index); 45 | 46 | MethodHandle scaleHandle(); 47 | 48 | long byteOffset(PathElement... elements); 49 | 50 | MethodHandle byteOffsetHandle(PathElement... elements); 51 | 52 | VarHandle varHandle(PathElement... elements); 53 | 54 | VarHandle arrayElementVarHandle(PathElement... elements); 55 | 56 | MethodHandle sliceHandle(PathElement... elements); 57 | 58 | MemoryLayout select(PathElement... elements); 59 | 60 | interface PathElement { 61 | 62 | static PathElement groupElement(String name) { 63 | throw new UnsupportedOperationException("Stub!"); 64 | } 65 | 66 | static PathElement groupElement(long index) { 67 | throw new UnsupportedOperationException("Stub!"); 68 | } 69 | 70 | static PathElement sequenceElement(long index) { 71 | throw new UnsupportedOperationException("Stub!"); 72 | } 73 | 74 | static PathElement sequenceElement(long start, long step) { 75 | throw new UnsupportedOperationException("Stub!"); 76 | } 77 | 78 | static PathElement sequenceElement() { 79 | throw new UnsupportedOperationException("Stub!"); 80 | } 81 | 82 | static PathElement dereferenceElement() { 83 | throw new UnsupportedOperationException("Stub!"); 84 | } 85 | } 86 | 87 | boolean equals(Object other); 88 | 89 | int hashCode(); 90 | 91 | @Override 92 | String toString(); 93 | 94 | static PaddingLayout paddingLayout(long byteSize) { 95 | throw new UnsupportedOperationException("Stub!"); 96 | } 97 | 98 | static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) { 99 | throw new UnsupportedOperationException("Stub!"); 100 | } 101 | 102 | static SequenceLayout sequenceLayout(MemoryLayout elementLayout) { 103 | throw new UnsupportedOperationException("Stub!"); 104 | } 105 | 106 | static StructLayout structLayout(MemoryLayout... elements) { 107 | throw new UnsupportedOperationException("Stub!"); 108 | } 109 | 110 | static StructLayout paddedStructLayout(MemoryLayout... elements) { 111 | throw new UnsupportedOperationException("Stub!"); 112 | } 113 | 114 | static UnionLayout unionLayout(MemoryLayout... elements) { 115 | throw new UnsupportedOperationException("Stub!"); 116 | } 117 | 118 | static ValueLayout valueLayout(Class carrier, ByteOrder order) { 119 | throw new UnsupportedOperationException("Stub!"); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/access/JavaForeignAccess.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.access; 2 | 3 | import com.v7878.foreign.Arena; 4 | import com.v7878.foreign.MemoryLayout; 5 | import com.v7878.foreign.MemorySegment; 6 | import com.v7878.foreign.MemorySegment.Scope; 7 | import com.v7878.foreign.RawJavaForeignAccess; 8 | import com.v7878.foreign.SymbolLookup; 9 | import com.v7878.r8.annotations.AlwaysInline; 10 | import com.v7878.unsafe.Utils.FineClosable; 11 | import com.v7878.unsafe.access.JavaNioAccess.UnmapperProxy; 12 | import com.v7878.unsafe.foreign.NativeLibrary; 13 | import com.v7878.unsafe.foreign.RawNativeLibraries; 14 | 15 | import java.util.Objects; 16 | import java.util.Optional; 17 | 18 | public final class JavaForeignAccess { 19 | @AlwaysInline 20 | public static boolean isThreadConfined(Scope scope) { 21 | return RawJavaForeignAccess.isThreadConfined(scope); 22 | } 23 | 24 | @AlwaysInline 25 | public static FineClosable lock(Scope scope) { 26 | return RawJavaForeignAccess.lock(scope); 27 | } 28 | 29 | @AlwaysInline 30 | public static void checkValidState(Scope scope) { 31 | RawJavaForeignAccess.checkValidState(scope); 32 | } 33 | 34 | @AlwaysInline 35 | public static void addCloseAction(Scope scope, Runnable cleanup) { 36 | RawJavaForeignAccess.addCloseAction(scope, cleanup); 37 | } 38 | 39 | @AlwaysInline 40 | public static void addOrCleanupIfFail(Scope scope, Runnable cleanup) { 41 | RawJavaForeignAccess.addOrCleanupIfFail(scope, cleanup); 42 | } 43 | 44 | @AlwaysInline 45 | public static MemorySegment objectSegment(Object obj) { 46 | return RawJavaForeignAccess.objectSegment(obj); 47 | } 48 | 49 | @AlwaysInline 50 | public static Arena createGlobalHolderArena(Object ref) { 51 | return RawJavaForeignAccess.createGlobalHolderArena(ref); 52 | } 53 | 54 | @AlwaysInline 55 | public static Arena createImplicitHolderArena(Object ref) { 56 | return RawJavaForeignAccess.createImplicitHolderArena(ref); 57 | } 58 | 59 | // NOTE: no @AlwaysInline 60 | public static MemorySegment makeNativeSegment(long min, long byteSize, boolean readOnly, 61 | Arena scope, Runnable action) { 62 | return RawJavaForeignAccess.makeNativeSegment(min, byteSize, readOnly, scope, action); 63 | } 64 | 65 | @AlwaysInline 66 | public static MemorySegment allocateNativeSegment( 67 | long byteSize, long byteAlignment, Arena scope, boolean init) { 68 | return RawJavaForeignAccess.allocateNativeSegment(byteSize, 69 | byteAlignment, scope, init); 70 | } 71 | 72 | @AlwaysInline 73 | public static MemorySegment allocateNoInit(long byteSize, long byteAlignment, Arena scope) { 74 | return allocateNativeSegment(byteSize, byteAlignment, scope, false); 75 | } 76 | 77 | @AlwaysInline 78 | public static MemorySegment mapSegment(UnmapperProxy unmapper, long size, boolean readOnly, Arena scope) { 79 | return RawJavaForeignAccess.mapSegment(unmapper, size, readOnly, scope); 80 | } 81 | 82 | @AlwaysInline 83 | public static SymbolLookup libraryLookup(NativeLibrary library, Arena libArena) { 84 | Objects.requireNonNull(library); 85 | Objects.requireNonNull(libArena); 86 | 87 | // register hook to unload library when 'libScope' becomes not alive 88 | addOrCleanupIfFail(libArena.scope(), () -> RawNativeLibraries.unload(library)); 89 | 90 | return name -> { 91 | long addr = library.find(name); 92 | return addr == 0L ? Optional.empty() : Optional.of( 93 | MemorySegment.ofAddress(addr).reinterpret(libArena, null)); 94 | }; 95 | } 96 | 97 | @AlwaysInline 98 | public static boolean hasNaturalAlignment(MemoryLayout layout) { 99 | return RawJavaForeignAccess.hasNaturalAlignment(layout); 100 | } 101 | 102 | @AlwaysInline 103 | public static long unsafeGetOffset(MemorySegment segment) { 104 | return RawJavaForeignAccess.unsafeGetOffset(segment); 105 | } 106 | 107 | @AlwaysInline 108 | public static Object unsafeGetBase(MemorySegment segment) { 109 | return RawJavaForeignAccess.unsafeGetBase(segment); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/cpp_std/basic_string.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.cpp_std; 2 | 3 | import static com.v7878.foreign.MemoryLayout.sequenceLayout; 4 | import static com.v7878.foreign.MemoryLayout.structLayout; 5 | import static com.v7878.foreign.MemoryLayout.unionLayout; 6 | import static com.v7878.foreign.ValueLayout.ADDRESS; 7 | import static com.v7878.foreign.ValueLayout.JAVA_BYTE; 8 | import static com.v7878.foreign.ValueLayout.JAVA_INT; 9 | import static com.v7878.foreign.ValueLayout.JAVA_LONG; 10 | import static com.v7878.unsafe.AndroidUnsafe.IS64BIT; 11 | 12 | import com.v7878.foreign.Arena; 13 | import com.v7878.foreign.MemoryLayout; 14 | import com.v7878.foreign.MemorySegment; 15 | import com.v7878.unsafe.access.JavaForeignAccess; 16 | 17 | import java.util.Objects; 18 | 19 | public final class basic_string { 20 | public static final basic_string string = new basic_string(JAVA_BYTE); 21 | 22 | public final MemoryLayout ELEMENT; 23 | public final MemoryLayout LONG_LAYOUT; 24 | public final MemoryLayout SHORT_LAYOUT; 25 | public final MemoryLayout LAYOUT; 26 | 27 | private final long min_capacity; 28 | 29 | public basic_string(MemoryLayout element) { 30 | this.ELEMENT = Objects.requireNonNull(element); 31 | if (element.byteAlignment() > 8) { 32 | throw new IllegalArgumentException("Elements with alihnment more than 8 is not supported"); 33 | } 34 | this.LONG_LAYOUT = structLayout(sequenceLayout(3, ADDRESS)); 35 | long min_cap = (LONG_LAYOUT.byteSize() - 1) / ELEMENT.byteSize(); 36 | min_cap = min_cap < 2 ? 2 : min_cap; 37 | long padding = ELEMENT.byteSize() - 1; 38 | this.SHORT_LAYOUT = padding == 0 ? structLayout(JAVA_BYTE, 39 | sequenceLayout(min_cap, ELEMENT)) : structLayout(JAVA_BYTE, 40 | sequenceLayout(padding, JAVA_BYTE), sequenceLayout(min_cap, ELEMENT)); 41 | this.LAYOUT = unionLayout(LONG_LAYOUT, SHORT_LAYOUT); 42 | this.min_capacity = min_cap; 43 | } 44 | 45 | public class impl { 46 | private final MemorySegment str; 47 | 48 | public impl(MemorySegment str) { 49 | this.str = str.asSlice(0, LAYOUT); 50 | } 51 | 52 | private static long get_word(MemorySegment ptr, long offset) { 53 | return IS64BIT ? ptr.get(JAVA_LONG, offset) : (ptr.get(JAVA_INT, offset) & 0xffffffffL); 54 | } 55 | 56 | public boolean is_short() { 57 | return (str.get(JAVA_BYTE, 0) & 1) == 0; 58 | } 59 | 60 | public MemorySegment data() { 61 | MemorySegment out = is_short() ? 62 | str.asSlice(ELEMENT.byteSize(), 0) : 63 | str.get(ADDRESS, ADDRESS.byteSize() * 2); 64 | return out.reinterpret(length() * ELEMENT.byteSize()); 65 | } 66 | 67 | public long capacity() { 68 | return is_short() ? min_capacity - 1 : (get_word(str, 0) & ~1) - 1; 69 | } 70 | 71 | public long length() { 72 | return is_short() ? str.get(JAVA_BYTE, 0) >> 1 : get_word(str, ADDRESS.byteSize()); 73 | } 74 | 75 | public void destruct() { 76 | if (!is_short()) { 77 | MemoryOperators.delete(get_word(str, ADDRESS.byteSize() * 2), ELEMENT.byteAlignment()); 78 | } 79 | } 80 | 81 | // Note: call destruct before assign 82 | public void assign(MemorySegment data) { 83 | long bytes = data.byteSize(); 84 | if (bytes % ELEMENT.byteSize() != 0) { 85 | throw new IllegalArgumentException("data size is not multiple of element size"); 86 | } 87 | long length = bytes / ELEMENT.byteSize(); 88 | MemorySegment dst; 89 | long offset; 90 | if (length < min_capacity) { 91 | (dst = str).set(JAVA_BYTE, 0, (byte) (length << 1)); 92 | offset = ELEMENT.byteSize(); 93 | } else { 94 | dst = JavaForeignAccess.allocateNativeSegment(bytes + ELEMENT.byteSize(), 95 | ELEMENT.byteAlignment(), Arena.global(), false); 96 | offset = 0; 97 | } 98 | MemorySegment.copy(data, 0, dst, offset, bytes); 99 | dst.asSlice(offset + bytes, ELEMENT.byteSize()).fill((byte) 0); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/access/VMAccess.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.access; 2 | 3 | import static com.v7878.unsafe.ArtVersion.A9; 4 | import static com.v7878.unsafe.access.AccessLinker.ExecutableAccess; 5 | import static com.v7878.unsafe.access.AccessLinker.ExecutableAccessKind.STATIC; 6 | import static com.v7878.unsafe.access.AccessLinker.ExecutableAccessKind.VIRTUAL; 7 | 8 | import com.v7878.r8.annotations.DoNotOptimize; 9 | import com.v7878.r8.annotations.DoNotShrinkType; 10 | import com.v7878.unsafe.ApiSensitive; 11 | import com.v7878.unsafe.access.AccessLinker.Conditions; 12 | 13 | public class VMAccess { 14 | @DoNotShrinkType 15 | @DoNotOptimize 16 | private abstract static class AccessI { 17 | @ExecutableAccess(kind = STATIC, klass = "dalvik.system.VMRuntime", name = "getRuntime", args = {}) 18 | abstract Object getRuntime(); 19 | 20 | @ExecutableAccess(kind = VIRTUAL, klass = "dalvik.system.VMRuntime", name = "properties", args = {}) 21 | abstract String[] properties(Object instance); 22 | 23 | @ExecutableAccess(kind = VIRTUAL, klass = "dalvik.system.VMRuntime", name = "bootClassPath", args = {}) 24 | abstract String bootClassPath(Object instance); 25 | 26 | @ExecutableAccess(kind = VIRTUAL, klass = "dalvik.system.VMRuntime", name = "classPath", args = {}) 27 | abstract String classPath(Object instance); 28 | 29 | @ExecutableAccess(kind = VIRTUAL, klass = "dalvik.system.VMRuntime", name = "vmLibrary", args = {}) 30 | abstract String vmLibrary(Object instance); 31 | 32 | @ExecutableAccess(kind = STATIC, klass = "dalvik.system.VMRuntime", name = "getCurrentInstructionSet", args = {}) 33 | abstract String getCurrentInstructionSet(); 34 | 35 | @ExecutableAccess(kind = VIRTUAL, klass = "dalvik.system.VMRuntime", name = "isCheckJniEnabled", args = {}) 36 | abstract boolean isCheckJniEnabled(Object instance); 37 | 38 | @ExecutableAccess(kind = VIRTUAL, klass = "dalvik.system.VMRuntime", name = "isNativeDebuggable", args = {}) 39 | abstract boolean isNativeDebuggable(Object instance); 40 | 41 | @ApiSensitive 42 | @ExecutableAccess(conditions = @Conditions(min_art = A9), kind = VIRTUAL, 43 | klass = "dalvik.system.VMRuntime", name = "isJavaDebuggable", args = {}) 44 | abstract boolean isJavaDebuggable(Object instance); 45 | 46 | @ExecutableAccess(kind = VIRTUAL, klass = "dalvik.system.VMRuntime", 47 | name = "newNonMovableArray", args = {"java.lang.Class", "int"}) 48 | abstract Object newNonMovableArray(Object instance, Class componentType, int length); 49 | 50 | @ExecutableAccess(kind = VIRTUAL, klass = "dalvik.system.VMRuntime", 51 | name = "addressOf", args = {"java.lang.Object"}) 52 | abstract long addressOf(Object instance, Object array); 53 | 54 | static final AccessI INSTANCE = AccessLinker.generateImpl(AccessI.class); 55 | } 56 | 57 | private static Object getInstance() { 58 | class Holder { 59 | static final Object vm = AccessI.INSTANCE.getRuntime(); 60 | } 61 | return Holder.vm; 62 | } 63 | 64 | public static String[] properties() { 65 | return AccessI.INSTANCE.properties(getInstance()); 66 | } 67 | 68 | public static String bootClassPath() { 69 | return AccessI.INSTANCE.bootClassPath(getInstance()); 70 | } 71 | 72 | public static String classPath() { 73 | return AccessI.INSTANCE.classPath(getInstance()); 74 | } 75 | 76 | public static String vmLibrary() { 77 | return AccessI.INSTANCE.vmLibrary(getInstance()); 78 | } 79 | 80 | public static String getCurrentInstructionSet() { 81 | return AccessI.INSTANCE.getCurrentInstructionSet(); 82 | } 83 | 84 | public static boolean isCheckJniEnabled() { 85 | return AccessI.INSTANCE.isCheckJniEnabled(getInstance()); 86 | } 87 | 88 | public static boolean isNativeDebuggable() { 89 | return AccessI.INSTANCE.isNativeDebuggable(getInstance()); 90 | } 91 | 92 | public static boolean isJavaDebuggable() { 93 | return AccessI.INSTANCE.isJavaDebuggable(getInstance()); 94 | } 95 | 96 | public static Object newNonMovableArray(Class componentType, int length) { 97 | return AccessI.INSTANCE.newNonMovableArray(getInstance(), componentType, length); 98 | } 99 | 100 | public static long addressOf(Object array) { 101 | return AccessI.INSTANCE.addressOf(getInstance(), array); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/ArtFieldUtils.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe; 2 | 3 | import static com.v7878.foreign.MemoryLayout.PathElement.groupElement; 4 | import static com.v7878.foreign.MemoryLayout.paddedStructLayout; 5 | import static com.v7878.foreign.ValueLayout.JAVA_INT; 6 | import static com.v7878.unsafe.AndroidUnsafe.fullFence; 7 | import static com.v7878.unsafe.AndroidUnsafe.getIntN; 8 | import static com.v7878.unsafe.AndroidUnsafe.putIntN; 9 | import static com.v7878.unsafe.ArtVersion.A16p1; 10 | import static com.v7878.unsafe.ArtVersion.A8p0; 11 | import static com.v7878.unsafe.ArtVersion.ART_INDEX; 12 | import static com.v7878.unsafe.Reflection.ART_FIELD_SIZE; 13 | import static com.v7878.unsafe.Reflection.getArtField; 14 | import static com.v7878.unsafe.Utils.dcheck; 15 | import static com.v7878.unsafe.Utils.unsupportedART; 16 | import static com.v7878.unsafe.foreign.ExtraLayouts.JAVA_OBJECT; 17 | 18 | import com.v7878.foreign.GroupLayout; 19 | import com.v7878.foreign.MemorySegment; 20 | 21 | import java.lang.reflect.Field; 22 | import java.lang.reflect.Modifier; 23 | import java.util.Objects; 24 | import java.util.function.IntUnaryOperator; 25 | 26 | public class ArtFieldUtils { 27 | private static final GroupLayout art_field_layout = paddedStructLayout( 28 | JAVA_OBJECT.withName("declaring_class_"), 29 | JAVA_INT.withName("access_flags_"), 30 | JAVA_INT.withName("field_dex_idx_"), 31 | JAVA_INT.withName("offset_") 32 | ); 33 | 34 | @ApiSensitive 35 | public static final GroupLayout ARTFIELD_LAYOUT; 36 | 37 | static { 38 | if (ART_INDEX >= A8p0 && ART_INDEX <= A16p1) { 39 | ARTFIELD_LAYOUT = art_field_layout; 40 | } else { 41 | throw unsupportedART(ART_INDEX); 42 | } 43 | dcheck(ARTFIELD_LAYOUT.byteSize() == ART_FIELD_SIZE, AssertionError::new); 44 | } 45 | 46 | public static MemorySegment getArtFieldSegment(Field f) { 47 | return MemorySegment.ofAddress(getArtField(f)).reinterpret(ARTFIELD_LAYOUT.byteSize()); 48 | } 49 | 50 | private static final long ACCESS_FLAGS_OFFSET = ARTFIELD_LAYOUT 51 | .byteOffset(groupElement("access_flags_")); 52 | 53 | @DangerLevel(DangerLevel.VERY_CAREFUL) 54 | public static int getFieldFlags(long art_field) { 55 | return getIntN(art_field + ACCESS_FLAGS_OFFSET); 56 | } 57 | 58 | public static int getFieldFlags(Field f) { 59 | return getFieldFlags(getArtField(f)); 60 | } 61 | 62 | @DangerLevel(DangerLevel.VERY_CAREFUL) 63 | public static void setFieldFlags(long art_field, int flags) { 64 | putIntN(art_field + ACCESS_FLAGS_OFFSET, flags); 65 | } 66 | 67 | @DangerLevel(DangerLevel.VERY_CAREFUL) 68 | public static void setFieldFlags(Field f, int flags) { 69 | setFieldFlags(getArtField(f), flags); 70 | } 71 | 72 | @DangerLevel(DangerLevel.VERY_CAREFUL) 73 | public static void changeFieldFlags(long art_field, int remove_flags, int add_flags) { 74 | int old_flags = getFieldFlags(art_field); 75 | int new_flags = (old_flags & ~remove_flags) | add_flags; 76 | if (new_flags != old_flags) { 77 | setFieldFlags(art_field, new_flags); 78 | fullFence(); 79 | } 80 | } 81 | 82 | @DangerLevel(DangerLevel.VERY_CAREFUL) 83 | public static void changeFieldFlags(Field f, int remove_flags, int add_flags) { 84 | changeFieldFlags(getArtField(f), remove_flags, add_flags); 85 | } 86 | 87 | @DangerLevel(DangerLevel.VERY_CAREFUL) 88 | public static void changeFieldFlags(long art_field, IntUnaryOperator filter) { 89 | Objects.requireNonNull(filter); 90 | int old_flags = getFieldFlags(art_field); 91 | int new_flags = filter.applyAsInt(old_flags); 92 | if (new_flags != old_flags) { 93 | setFieldFlags(art_field, new_flags); 94 | fullFence(); 95 | } 96 | } 97 | 98 | @DangerLevel(DangerLevel.VERY_CAREFUL) 99 | public static void changeFieldFlags(Field f, IntUnaryOperator filter) { 100 | changeFieldFlags(getArtField(f), filter); 101 | } 102 | 103 | @DangerLevel(DangerLevel.VERY_CAREFUL) 104 | public static void makeFieldPublic(Field f) { 105 | changeFieldFlags(f, Modifier.PROTECTED | Modifier.PRIVATE, Modifier.PUBLIC); 106 | } 107 | 108 | @DangerLevel(DangerLevel.VERY_CAREFUL) 109 | public static void makeFieldNonFinal(Field f) { 110 | changeFieldFlags(f, Modifier.FINAL, 0); 111 | } 112 | 113 | @DangerLevel(DangerLevel.VERY_CAREFUL) 114 | public static void makeFieldPublicApi(Field f) { 115 | changeFieldFlags(f, ArtModifiers::makePublicApi); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /LLVM/src/main/java/com/v7878/llvm/IRReader.java: -------------------------------------------------------------------------------- 1 | package com.v7878.llvm; 2 | 3 | import static com.v7878.foreign.ValueLayout.ADDRESS; 4 | import static com.v7878.llvm.Core.LLVMCreateMemoryBufferWithSegment; 5 | import static com.v7878.llvm.Types.LLVMContextRef; 6 | import static com.v7878.llvm.Types.LLVMMemoryBufferRef; 7 | import static com.v7878.llvm.Types.LLVMModuleRef; 8 | import static com.v7878.llvm._LibLLVM.LLVM; 9 | import static com.v7878.llvm._Utils.addressToLLVMString; 10 | import static com.v7878.llvm._Utils.allocString; 11 | import static com.v7878.unsafe.foreign.BulkLinker.CallType.CRITICAL; 12 | import static com.v7878.unsafe.foreign.BulkLinker.MapType.BOOL_AS_INT; 13 | import static com.v7878.unsafe.foreign.BulkLinker.MapType.LONG_AS_WORD; 14 | 15 | import android.annotation.SuppressLint; 16 | 17 | import com.v7878.foreign.Arena; 18 | import com.v7878.foreign.MemorySegment; 19 | import com.v7878.r8.annotations.DoNotOptimize; 20 | import com.v7878.r8.annotations.DoNotShrink; 21 | import com.v7878.r8.annotations.DoNotShrinkType; 22 | import com.v7878.unsafe.foreign.BulkLinker; 23 | import com.v7878.unsafe.foreign.BulkLinker.CallSignature; 24 | import com.v7878.unsafe.foreign.BulkLinker.LibrarySymbol; 25 | 26 | import java.util.function.Consumer; 27 | 28 | /*===-- llvm-c/IRReader.h - IR Reader C Interface -----------------*- C -*-===*\ 29 | |* *| 30 | |* This file defines the C interface to the IR Reader. *| 31 | |* *| 32 | \*===----------------------------------------------------------------------===*/ 33 | @SuppressLint("WrongCommentType") 34 | public final class IRReader { 35 | private IRReader() { 36 | } 37 | 38 | @DoNotShrinkType 39 | @DoNotOptimize 40 | private abstract static class Native { 41 | @DoNotShrink 42 | private static final Arena SCOPE = Arena.ofAuto(); 43 | 44 | @LibrarySymbol(name = "LLVMParseIRInContext") 45 | @CallSignature(type = CRITICAL, ret = BOOL_AS_INT, args = {LONG_AS_WORD, LONG_AS_WORD, LONG_AS_WORD, LONG_AS_WORD}) 46 | abstract boolean LLVMParseIRInContext(long ContextRef, long MemBuf, long OutM, long OutMessage); 47 | 48 | static final Native INSTANCE = BulkLinker.generateImpl(SCOPE, Native.class, LLVM); 49 | } 50 | 51 | /** 52 | * Read LLVM IR from a memory buffer and convert it into an in-memory 53 | * Module object. Returns 0 on success. Optionally returns a 54 | * human-readable description of any errors that occurred during 55 | * parsing IR. OutMessage must be disposed with LLVMDisposeMessage. 56 | */ 57 | /* package-private */ 58 | static boolean nLLVMParseIRInContext( 59 | LLVMContextRef ContextRef, LLVMMemoryBufferRef MemBuf, 60 | Consumer OutM, Consumer OutMessage) { 61 | try (Arena arena = Arena.ofConfined()) { 62 | MemorySegment c_OutM = arena.allocate(ADDRESS); 63 | MemorySegment c_OutMessage = arena.allocate(ADDRESS); 64 | boolean err = Native.INSTANCE.LLVMParseIRInContext(ContextRef.value(), 65 | MemBuf.value(), c_OutM.nativeAddress(), c_OutMessage.nativeAddress()); 66 | if (!err) { 67 | OutM.accept(LLVMModuleRef.of(c_OutM.get(ADDRESS, 0).nativeAddress())); 68 | } else { 69 | OutMessage.accept(addressToLLVMString(c_OutMessage.get(ADDRESS, 0).nativeAddress())); 70 | } 71 | return err; 72 | } 73 | } 74 | 75 | /** 76 | * Read LLVM IR from a memory buffer and convert it into an in-memory Module object. 77 | */ 78 | // Port-added 79 | public static LLVMModuleRef LLVMParseIRInContext( 80 | LLVMContextRef ContextRef, LLVMMemoryBufferRef MemBuf) throws LLVMException { 81 | String[] err = new String[1]; 82 | LLVMModuleRef[] out = new LLVMModuleRef[1]; 83 | if (nLLVMParseIRInContext(ContextRef, MemBuf, O -> out[0] = O, E -> err[0] = E)) { 84 | throw new LLVMException(err[0]); 85 | } 86 | return out[0]; 87 | } 88 | 89 | /** 90 | * Read LLVM IR from a string and convert it into an in-memory Module object. 91 | */ 92 | // Port-added 93 | public static LLVMModuleRef LLVMParseIRInContext( 94 | LLVMContextRef ContextRef, String Data) throws LLVMException { 95 | try (Arena arena = Arena.ofConfined()) { 96 | MemorySegment c_Data = allocString(arena, Data); 97 | LLVMMemoryBufferRef MemBuf = LLVMCreateMemoryBufferWithSegment( 98 | c_Data, "", true); 99 | return LLVMParseIRInContext(ContextRef, MemBuf); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Unsafe/src/main/java/com/v7878/unsafe/access/MappedMemoryUtils.java: -------------------------------------------------------------------------------- 1 | package com.v7878.unsafe.access; 2 | 3 | import static com.v7878.unsafe.ArtVersion.A14; 4 | import static com.v7878.unsafe.ArtVersion.A15; 5 | import static com.v7878.unsafe.ArtVersion.ART_INDEX; 6 | import static com.v7878.unsafe.Utils.nothrows_run; 7 | import static com.v7878.unsafe.access.AccessLinker.ExecutableAccessKind.DIRECT_HOOK_VTABLE; 8 | import static com.v7878.unsafe.io.IOUtils.MADV_DONTNEED; 9 | import static com.v7878.unsafe.io.IOUtils.MADV_WILLNEED; 10 | import static com.v7878.unsafe.io.IOUtils.madvise; 11 | 12 | import com.v7878.r8.annotations.DoNotOptimize; 13 | import com.v7878.r8.annotations.DoNotShrink; 14 | import com.v7878.r8.annotations.DoNotShrinkType; 15 | import com.v7878.unsafe.AndroidUnsafe; 16 | import com.v7878.unsafe.access.AccessLinker.Conditions; 17 | import com.v7878.unsafe.access.AccessLinker.ExecutableAccess; 18 | 19 | import java.io.FileDescriptor; 20 | 21 | class MappedMemoryUtils { 22 | private static final int PAGE_SIZE = AndroidUnsafe.PAGE_SIZE; 23 | 24 | static boolean isLoaded(long address, long length) { 25 | if (address == 0 || length == 0) return true; 26 | 27 | long offset = mappingOffset(address); 28 | address -= offset; 29 | length += offset; 30 | 31 | return isLoaded0(address, length, pageCount(length)); 32 | } 33 | 34 | // not used, but a potential target for a store, see load() for details. 35 | @DoNotShrink 36 | private static byte unused; 37 | 38 | static void load(long address, long length) { 39 | if (address == 0 || length == 0) return; 40 | 41 | long offset = mappingOffset(address); 42 | address -= offset; 43 | length += offset; 44 | load0(address, length); 45 | 46 | // Read a byte from each page to bring it into memory. A checksum 47 | // is computed as we go along to prevent the compiler from otherwise 48 | // considering the loop as dead code. 49 | long count = pageCount(length); 50 | byte x = 0; 51 | for (long i = 0; i < count; i++) { 52 | x ^= AndroidUnsafe.getByteN(address + i * PAGE_SIZE); 53 | } 54 | if (unused != 0) unused = x; 55 | } 56 | 57 | static void unload(long address, long length) { 58 | if (address == 0 || length == 0) return; 59 | 60 | long offset = mappingOffset(address); 61 | unload0(address - offset, length + offset); 62 | } 63 | 64 | static void force(FileDescriptor fd, long address, long length) { 65 | // force writeback via file descriptor 66 | long offset = mappingOffset(address); 67 | force0(fd, address - offset, length + offset); 68 | } 69 | 70 | // utility methods 71 | 72 | private static long pageCount(long size) { 73 | return (size + PAGE_SIZE - 1L) / PAGE_SIZE; 74 | } 75 | 76 | // Returns the distance (in bytes) of the buffer start from the 77 | // largest page aligned address of the mapping less than or equal 78 | // to the start address. 79 | private static long mappingOffset(long address) { 80 | return address - alignPageDown(address); 81 | } 82 | 83 | // align address down to page size 84 | private static long alignPageDown(long address) { 85 | return address & -PAGE_SIZE; 86 | } 87 | 88 | // native methods 89 | 90 | private static void load0(long address, long length) { 91 | nothrows_run(() -> madvise(address, length, MADV_WILLNEED)); 92 | } 93 | 94 | private static void unload0(long address, long length) { 95 | nothrows_run(() -> madvise(address, length, MADV_DONTNEED)); 96 | } 97 | 98 | private static boolean isLoaded0(long address, long length, long pageCount) { 99 | if (ART_INDEX < A15) { 100 | return AccessI.INSTANCE.isLoaded0b35(address, length, (int) pageCount); 101 | } else { 102 | return AccessI.INSTANCE.isLoaded0a35(address, length, pageCount); 103 | } 104 | } 105 | 106 | private static void force0(FileDescriptor fd, long length, long pageCount) { 107 | AccessI.INSTANCE.force0(fd, length, pageCount); 108 | } 109 | 110 | @DoNotShrinkType 111 | @DoNotOptimize 112 | private abstract static class AccessI { 113 | @ExecutableAccess(conditions = @Conditions(max_art = A14), kind = DIRECT_HOOK_VTABLE, 114 | klass = "java.nio.MappedByteBuffer", name = "isLoaded0", args = {"long", "long", "int"}) 115 | abstract boolean isLoaded0b35(long address, long length, int pageCount); 116 | 117 | @ExecutableAccess(conditions = @Conditions(min_art = A15), kind = DIRECT_HOOK_VTABLE, 118 | klass = "java.nio.MappedByteBuffer", name = "isLoaded0", args = {"long", "long", "long"}) 119 | abstract boolean isLoaded0a35(long address, long length, long pageCount); 120 | 121 | @ExecutableAccess(kind = DIRECT_HOOK_VTABLE, klass = "java.nio.MappedByteBuffer", 122 | name = "force0", args = {"java.io.FileDescriptor", "long", "long"}) 123 | abstract void force0(FileDescriptor fd, long length, long pageCount); 124 | 125 | static final AccessI INSTANCE = AccessLinker.generateImpl(AccessI.class); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Core/src/openjdk/java/com/v7878/foreign/_ConfinedSession.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 - 2025 Oracle and/or its affiliates. All rights reserved. 3 | * Modifications Copyright (c) 2025 Vladimir Kozelkov. 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 | * 6 | * This code is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 only, as 8 | * published by the Free Software Foundation. Oracle designates this 9 | * particular file as subject to the "Classpath" exception as provided 10 | * by Oracle in the LICENSE file that accompanied this code. 11 | * 12 | * This code is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 | * version 2 for more details (a copy is included in the LICENSE file that 16 | * accompanied this code). 17 | * 18 | * You should have received a copy of the GNU General Public License version 19 | * 2 along with this work; if not, write to the Free Software Foundation, 20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 | * 22 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 | * or visit www.oracle.com if you need additional information or have any 24 | * questions. 25 | */ 26 | 27 | // Port-changed: Extensive modifications made throughout the class for Android. 28 | 29 | package com.v7878.foreign; 30 | 31 | import com.v7878.r8.annotations.DoNotObfuscate; 32 | import com.v7878.r8.annotations.DoNotShrink; 33 | import com.v7878.unsafe.AndroidUnsafe; 34 | import com.v7878.unsafe.Reflection; 35 | 36 | /** 37 | * A confined session, which features an owner thread. The liveness check features an additional 38 | * confinement check - that is, calling any operation on this session from a thread other than the 39 | * owner thread will result in an exception. Because of this restriction, checking the liveness bit 40 | * can be performed in plain mode. 41 | */ 42 | final class _ConfinedSession extends _MemorySessionImpl { 43 | 44 | static final long ASYNC_RELEASE_COUNT_OFFSET = Reflection.instanceFieldOffset( 45 | _ConfinedSession.class, "asyncReleaseCount"); 46 | 47 | @DoNotShrink 48 | @DoNotObfuscate 49 | @SuppressWarnings({"unused", "FieldMayBeFinal"}) 50 | private int asyncReleaseCount = 0; 51 | 52 | public _ConfinedSession(Thread owner) { 53 | super(owner, new ConfinedResourceList()); 54 | } 55 | 56 | @Override 57 | public void acquire0() { 58 | checkValidState(); 59 | if (acquireCount == MAX_FORKS) { 60 | throw tooManyAcquires(); 61 | } 62 | acquireCount++; 63 | } 64 | 65 | @Override 66 | public void release0() { 67 | if (Thread.currentThread() == owner) { 68 | acquireCount--; 69 | } else { 70 | // It is possible to end up here in two cases: this session was kept alive by some other confined session 71 | // which is implicitly released (in which case the release call comes from the cleaner thread). Or, 72 | // this session might be kept alive by a shared session, which means the release call can come from any 73 | // thread. 74 | AndroidUnsafe.getAndAddIntO(this, ASYNC_RELEASE_COUNT_OFFSET, 1); 75 | } 76 | } 77 | 78 | void justClose() { 79 | checkValidState(); 80 | int asyncCount = AndroidUnsafe.getIntVolatileO(this, ASYNC_RELEASE_COUNT_OFFSET); 81 | int acquire = acquireCount - asyncCount; 82 | if (acquire == 0) { 83 | state = CLOSED; 84 | } else { 85 | throw alreadyAcquired(acquire); 86 | } 87 | } 88 | 89 | /** 90 | * A confined resource list; no races are possible here. 91 | */ 92 | static final class ConfinedResourceList extends ResourceList { 93 | // The first element of the list is pulled into a separate field 94 | // which helps escape analysis keep track of the instance, allowing 95 | // it to be scalar replaced. 96 | ResourceCleanup cache; 97 | 98 | @Override 99 | void add(ResourceCleanup cleanup) { 100 | if (fst != ResourceCleanup.CLOSED_LIST) { 101 | if (cache == null) { 102 | cache = cleanup; 103 | } else { 104 | cleanup.next = fst; 105 | fst = cleanup; 106 | } 107 | } else { 108 | throw alreadyClosed(); 109 | } 110 | } 111 | 112 | @Override 113 | void cleanup() { 114 | if (fst != ResourceCleanup.CLOSED_LIST) { 115 | ResourceCleanup prev = fst; 116 | fst = ResourceCleanup.CLOSED_LIST; 117 | RuntimeException pendingException = null; 118 | if (cache != null) { 119 | //noinspection ConstantValue 120 | pendingException = cleanupSingle(cache, pendingException); 121 | } 122 | cleanup(prev, pendingException); 123 | } else { 124 | throw alreadyClosed(); 125 | } 126 | } 127 | } 128 | } 129 | --------------------------------------------------------------------------------