Skip to content

提供无需添加额外启动参数就可以使用JDK带来的各种内部api的解决方案 兼jvmci探索

Notifications You must be signed in to change notification settings

dreamlike-ocean/UnsafeJava

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

本项目是提供一组在虚拟线程里面很有用但是被jdk屏蔽掉的API 全部都以同名的函数/类型的形式提供 包含以下功能

  • CarrierThreadLocal
  • 自定义调度器
  • Continuation API 包含yield和run原语
  • TerminatingThreadLocal API
  • 特权LookUp
  • java.lang.LiveStackFrameInfo获取当前栈信息,比如说Monitor信息,局部变量表及获取对应引用

原理很简单 代码如下

    private static MethodHandles.Lookup fetchUnsafeHandler() {
        Class<MethodHandles.Lookup> lookupClass = MethodHandles.Lookup.class;

        try {
            Field implLookupField = lookupClass.getDeclaredField("IMPL_LOOKUP");
            long offset = UNSAFE.staticFieldOffset(implLookupField);
            return (MethodHandles.Lookup) UNSAFE.getObject(UNSAFE.staticFieldBase(implLookupField), offset);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

IMPL_LOOKUP这个是无视各种权限的lookup,从它这里获取到的MethodHandle无视任何权限 然后就可以好好玩拿到MethodHandle了

为了应对未来的Unsafe中的某些内存操作被移除的问题,在寒老板的一次群聊中提到了几个java动态库导出的符号,我们逆向了这些符号以及正向参考了openjdk源码,使用Panama API封装了大部分的JNI操作,使得可以绕开模块化之类的限制让我们继续可以hack标准库,继续能拿到IMPL_LOOKUP字段

Warning

目前只在Linux以及Windows x86_64,Mac(aarch64以及amd64)上测试过,其他平台可能需要评估兼容性问题

maven 坐标为,本库以multi-release的形式发布,所以你可以在jdk8-jdk22上使用,从jdk22开始默认使用的Panama的实现

<dependency>
  <groupId>io.github.dreamlike-ocean</groupId>
  <artifactId>unsafe-core</artifactId>
  <version>1.3</version>
</dependency>

当然你也会发现项目里面有另外一种写法,即获取到MethodHandle之后转换为java.util.function.Function,这两种形式核心原理是一样的

    private static Function<Executor, Thread.Builder.OfVirtual> fetchVirtualThreadBuilder() {
        var tmp = Thread.ofVirtual().getClass();
        try {
            MethodHandle builderMethodHandle = IMPL_LOOKUP
                    .in(tmp)
                    .findConstructor(tmp, MethodType.methodType(void.class, Executor.class));
            MethodHandle lambdaFactory = LambdaMetafactory.metafactory(
                    IMPL_LOOKUP,
                    "apply",
                    MethodType.methodType(Function.class),
                    MethodType.methodType(Object.class, Object.class),
                    builderMethodHandle,
                    builderMethodHandle.type()
            ).getTarget();
            return (Function<Executor, Thread.Builder.OfVirtual>) lambdaFactory.invoke();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

类似于lambda和sam

TerminatingThreadLocal API的则是比较复杂 这里用了内部的jdk.internal.access.JavaLangAccess的这个玩意强制打开限制,让我可以以继承的方式自定义它的销毁函数 这里使用bytebuddy继承然后转发到field上面 具体看代码吧。。。

对于给Vert.x的扩展,用的是Async/Await这种风格的,避免某些半瓶水再来烦我,我讲一下为什么要这样写 首先我写的await函数只是强制要求当前在Continuation中而已,没有传染性的 其次写AsyncScope只是帮你开启Continuation罢了

About

提供无需添加额外启动参数就可以使用JDK带来的各种内部api的解决方案 兼jvmci探索

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages