• [开源JVM] yvm


    中文 | English
    | Build Status | |

    YVM是用C++写的一个Java虚拟机,现在支持Java大部分功能,以及一个基于标记清除算法的并发垃圾回收器. 不过还有很多bug等待修复。
    感兴趣的朋友pull request/fork/star吧。

    Github repo

    https://github.com/racaljk/yvm

    已支持语言特性

    高级特性逐步支持中,可以开Issue提议或者直接PR

    构建和运行

    • 先决条件
      • Boost(>=1.65) 请在CMakeLists.txt中手动配置Boost库位置
      • CMake(>=3.5)
      • C++14
      • gcc/msvc/mingw均可
    • 老生常谈
    $ cd yvm
    $ cmake .
    $ make -j4
    $ make test
    
    $ ./yvm --help
    Usage:
        --help                List help documentations and usages.
        --runtime arg         Attach java runtime libraries where yvm would lookup 
                            classes at
        --run arg             Program which would be executed soon
    You must specify the "runtime" flag to tell yvm where it could find jdk classes, and also program name is required.
    $ ./yvm --runtime=C:UsersCthulhuDesktopyvmytecode ydk.test.QuickSort
    

    运行效果

    • helloworld

    • 快速排序

    • and more see its github repository readme.md...

    开发文档

    1. 从字节码到对象

    MethodArea负责管理字节码到JavaClass的完整生命周期。MethodArea的方法是自解释的:

    class MethodArea {
    public:
        // 方法区需要从运行时目录中搜索相关的*.class文件
        MethodArea(const vector<string>& libPaths);
        ~MethodArea();
    
        // 查看一个类是否存在
        JavaClass* findJavaClass(const string& jcName);
        //加载jcName类
        bool loadJavaClass(const string& jcName);
        //移除jcName(该方法用于垃圾回收器)
        bool removeJavaClass(const string& jcName);
        //链接jcName类,初始化static字段
        void linkJavaClass(const string& jcName);
        //初始化jcName,初始化静态字段,调用static{}
        void initJavaClass(CodeExecution& exec, const string& jcName);
    
    public:
        //辅助方法,如果不存在jcName则加载 
        JavaClass* loadClassIfAbsent(const string& jcName);
        //如果未链接jcName则链接
        void linkClassIfAbsent(const string& jcName);
        //如果未初始化jcName则初始化
        void initClassIfAbsent(CodeExecution& exec, const string& jcName);
    }
    

    假设磁盘存在一个Test.class文件,它会经历如下过程:

    Test.class[磁盘中]-> loadJavaClass("Test.class")[内存中] -> linkJavaClass("Test.class")->initJavaClass("Test.class")

    现在虚拟机就可以使用这个JavaClass创建对应的对象了:

    // yrt 是全局运行时对象,ma表示方法区模块,jheap表示堆模块
    JavaClass* testClass = yrt.ma->findJavaClass("Test.class");
    JObject* testInstance = yrt.jheap->createObject(*testClass);
    

    2.1 对象内部构造

    虚拟机执行时栈上存放的都是JObject,它的结构如下:

    struct JObject {
        std::size_t offset = 0; 
        const JavaClass* jc{}; 
    };
    

    offset唯一代表一个对象,所有在堆上面的操作都需要这个offset。jc指向对象的Class表示。
    堆中的对象是按照<offset,fields>方式进行存放的:

    [1]  ->  [field_a, field_b, field_c]
    [2]  ->  []
    [3]  ->  [field_a,field_b]
    [4]  ->  [field_a]
    [..] ->  [...]
    

    只要我们持有offset,就可以查找/添加/删除对应的field

    数组几乎和上面类似,只是多了长度,少了Class指针

    struct JArray {
        int length = 0;
        std::size_t offset = 0; 
    };
    [1]  ->   <3, [field_a, field_b, field_c]>
    [2]  ->   <0, []>
    [3]  ->   <2, [field_a,field_b]>
    [4]  ->   <1, [field_a]>
    [..] ->   <..,[...]>
    

    2.2 从对象创建到消亡

    上面提到,对象持有一个offset和jc,其中jc表示的JavaClass是由MethodArea负责管理的,offset则是由JavaHeap负责管理。JavaHeap提供了大量API,这里选取的是最重要的:

    class JavaHeap {
    public:
        //创建对象和数组
        JObject* createObject(const JavaClass& javaClass);
        JArray* createObjectArray(const JavaClass& jc, int length);
    
        //获取对象字段
        auto getFieldByName(const JavaClass* jc, const string& name,
                            const string& descriptor, JObject* object);
        //设置对象字段
        void putFieldByName(const JavaClass* jc, const string& name,
                            const string& descriptor, JObject* object,
                            JType* value);
        //设置数组元素
        void putElement(const JArray& array, size_t index, JType* value);
        //获取数组元素
        auto getElement(const JArray& array, size_t index);
        
        //移除对象和数组
        void removeArray(size_t offset;
        void removeObject(size_t offset);
    };
    

    还是Test.class那个例子,假设对应的Test.java构造如下:

    public class Test{
        public int k;
        private String hello;
    }
    

    在第一步我们已经获取到了Test类在虚拟机中的类表示以及对象表示,现在就可以对类的字段进行操作了:

    const JavaClass* testClass = yrt.ma->findJavaClass("Test.class");
    JObject* testInstance = yrt.jheap->createObject(*testClass);
    //获取hello字段
    JObject*  helloField = yrt.jheap->getFieldByName(testClass,"hello","Ljava/lang/String;",testInstance);
    //设置k字段
    yrt.jheap->putFieldByName(testClass,"k","I",testInstance);
    

    Ⅰ. 关于JDK

    部分JDK类是JVM运行攸关的,但由于JDK比较复杂不便于初期开发,所以这里用重写过的JDK代替,源码参见javaclass目录,可以使用compilejava.bat进行编译,编译后*.class文件位于bytecode.
    目前重写过的JDK类有:

    • java.lang.String
    • java.lang.StringBuilder
    • java.lang.Throwable
    • java.lang.Math(::random())
    • java.lang.Runnable
    • java.lang.Thread

    Wiki和源码中有很多详细的开发文档,如果想探索关于YVM的更多内容,请移步浏览.

    License

    所有代码基于MIT协议

  • 相关阅读:
    Kafka Tuning Recommendations
    ​Installing the Ranger Kafka Plug-in
    Problem of Creating Topics in Kafka with Kerberos
    Step by Step Recipe for Securing Kafka with Kerberos
    ERROR:"org.apache.zookeeper.KeeperException$NoAuthException: KeeperErrorCode = NoAuth for /config/topics/test" when creating or deleting Kafka operations authorized through the Ranger policies
    Scala操作Hbase空指针异常java.lang.NullPointerException处理
    使用ranger对kafka进行鉴权
    IBM developer:Setting up the Kafka plugin for Ranger
    IBM developer:Kafka ACLs
    Exception in thread "main" org.I0Itec.zkclient.exception.ZkAuthFailedException: Authentication failure is thrown while creating kafka topic
  • 原文地址:https://www.cnblogs.com/ysherlock/p/8688454.html
Copyright © 2020-2023  润新知