Cómo escribir una máquina virtual Java en Java

significado

  1. Lo que he aprendido sobre el papel es, en última instancia, superficial y sé que tengo que hacerlo en detalle. Solo aprendo el mecanismo y la teoría de JVM, pero muchas veces todavía siento que me falta esa sensación de iluminación.
  2. Utilice una forma sencilla de implementar JVM para aprender y comprender los principios operativos de JVM.

Selección de tecnología principal.

Función de implementación

  • Implementé el 99% de las instrucciones de código de bytes de JVM. Implementar el conjunto de instrucciones de la máquina virtual Java con referencia a las especificaciones de código de bytes de JVM 
  • Soporta operadores aritméticos ( +, -, *, ^, %, ++, --)
  • Soporta operadores relacionales ( ==, !=, >, <, >=, <=)
  • Soporta operadores bit a bit ( &, |, ^, ~, <<, >>, >>>)
  • Operadores de asignación de soporte ( =, +=, -=, *=, %=, <<=, >>=, &=, ^=, |=)
  • Instancia de soporte del operador
  • Código de estructura de bucle de soporte ( while, do...while, for, foreach)
  • Código de estructura condicional de soporte ( if, if...else, if...else if)
  • GastosCrear clase personalizada
  • Soporte para crear objetos y acceder a ellos.
  • Apoyar clases abstractas
  • Admite herencia e interfaces polimórficas.
  • Admite acceso a métodos estáticos.
  • Admite métodos de objetos de acceso
  • Admite clases de Java que vienen con JDK
  • Reflexión de apoyo
  • Excepciones de soporte
  • Enumeración (en desarrollo...)
  • cambiar de sintaxis (en desarrollo...)
  • expresión lambda (en desarrollo...)

limitación

  • No admite subprocesos múltiples
  • No se admiten matrices multidimensionales
  • Actualmente no existe ningún mecanismo de delegación de padres implementado.
  • Sin implementación de recolector de basura. La recolección de basura depende de la JVM del host

Experiencia rápida

¿Qué necesitas preparar?

  1. Entorno de desarrollo integrado (IDE). Puede optar por incluir IntelliJ IDEA, Visual Studio Code o Eclipse, etc.
  2. JDK 17. y configurar JAVA_HOME
  3. JDK8. El objetivo principal de haidnorJVM es ejecutar archivos de código de bytes de la versión Java8. (Pero haidnorJVM no fuerza que el archivo de código de bytes sea la versión Java8)
  4. experto

Configurar haidnorJVM

Configurar el nivel de salida del registro

resources\simplelogger.properties Para modificar el nivel de salida del registro en el archivo, generalmente  use  debug,info

  • Al configurar el nivel de información, no se verá ninguna información de ejecución interna de haidnorJVM.
  • Configurar la ejecución en el nivel de depuración generará la información de la pila de la JVM que se ejecuta de una manera muy amigable.
public class Demo5 {

    public static void main(String[] args) {
        String str = method1("hello world");
        method1(str);
    }

    public static String method1(String s) {
        return method2(s);
    }

    public static String method2(String s) {
        return method3(s);
    }

    public static String method3(String s) {
        System.out.println(s);
        return "你好 世界";
    }
    
}

Cada   gráfico de estructura representa un marco de pila en una pila de subprocesos JVM.

Configurar la ruta rt.jar

Modifique  haidnorJVM.properties el contenido del archivo. Configure la ruta absoluta de rt.jar, por ejemplort.jar=D:/Program Files/Java/jdk1.8.0_361/jre/lib/rt.jar

Ejecutar casos de prueba unitaria

Abra el archivo en el directorio de prueba del proyecto en el IDE  haidnor.jvm.test.TestJVM.java . Esta es la clase de prueba principal de haidnorJVM. Los métodos de prueba internos pueden analizar, cargar y ejecutar archivos de código de bytes .class.

public class TestJVM {
   /**
    *  haidnorJVM 会加载 HelloWorld.java 在 target 目录下的编译后的字节码文件,然后运行其中的 `main(String[] args)` 方法。
    *  你可以使用打断点的方式看到 haidnorJVM 是如何解释运行 Java 字节码的。
    *  值得注意的是,这种方式编译运行的字节码文件是基于 java17 版本的。
    */
   @Test
   public void test() {
      runMainClass(HelloWorld.class);
   }
}

Ejecute el archivo .class

  1. Utilice el comando maven para compilar y empaquetar haidnorJVM y obtener  haidnorJVM.jar el archivo
  2. Escriba un programa simple como el siguiente código.
public class HelloWorld {
   public static void main(String[] args) {
     System.out.println("HelloWorld");
   }
}
  1. Compile el código y obtenga el archivo HelloWorld.class (se recomienda utilizar JDK8 para la compilación)
  2. Utilice haidnorJVM para ejecutar el programa. Ejecute el comando  java -jar haidnorJVM.jar -class R:\HelloWorld.class. Nota: Se requiere la ruta absoluta del archivo de clase.

Ejecute el archivo .jar

  1. Utilice el comando maven para compilar y empaquetar haidnorJVM y obtener  haidnorJVM.jar el archivo
  2. Escriba un proyecto Java, compílelo y empaquetelo en un archivo .jar, como demo.jar. Se requiere que el archivo META-INF/MANIFEST.MF en el archivo .jar tenga  Main-Class atributos (que contengan  public static void main(String[] args) la información de clase principal del método)
  3. Utilice haidnorJVM para ejecutar el programa. Ejecute el comando  java -jar haidnorJVM.jar -class R:\demo.jar. Nota: Se requiere la ruta absoluta del archivo jar.

Problemas

Dado que actualmente haidnorJVM usa reflexión para ejecutar las clases que vienen con el JDK, habrá algunos problemas cuando haidnorJVM use JDK17 para ejecutar algunas de las clases que vienen con el JDK. Por ejemplo, ejecutar el siguiente código generará una excepción.

public class Demo {
    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5);
        list.add(6);
    }
}
java.lang.reflect.InaccessibleObjectException: Unable to make public boolean java.util.ImmutableCollections$AbstractImmutableCollection.add(java.lang.Object) accessible: module java.base does not "opens java.util" to unnamed module @18769467

	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)

Indica un intento de acceder a un método o campo a través de la reflexión, pero las restricciones de accesibilidad en el método o campo impiden el acceso.

Esta limitación suele deberse al sistema de módulos Java. El sistema de módulos permite dividir el código en módulos independientes
y controlar los permisos de acceso entre módulos. El motivo de la excepción anterior es que el módulo java.base no "abre java.util" en el módulo sin nombre, lo que significa que el módulo java.base no abre el paquete java.util en el módulo sin nombre.

Solución:
agregue parámetros de JVM al iniciar haidnorJVM  --add-opens java.base/java.util=ALL-UNNAMED para evitar las restricciones de accesibilidad

Supongo que te gusta

Origin blog.csdn.net/2301_78834737/article/details/132004536
Recomendado
Clasificación