侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

用Java实现JVM第九章《本地方法调用》

2022-07-08 星期五 / 0 评论 / 0 点赞 / 36 阅读 / 41200 字

案例介绍本章主要介绍用java实现一些本地方法类库,并初始化本地方法,之后通过反射命令来调用本地方法。Java虚拟机和Java类库一起构成了Java运行时环境。Java类库主要用Java语言编写,一些

案例介绍

本章主要介绍用java实现一些本地方法类库,并初始化本地方法,之后通过反射命令来调用本地方法。

.

Java虚拟机和Java类库一起构成了Java运行时环境。Java类库主要用Java语言编写,一些无法用Java语言实现的方法则使用本地语言编写,这额方法叫作本地方法。OpenJDK类库中的本地方法是用JNI(Java Native Interface)编写的,但是要让虚拟机支持JNI规范还需要大量工作。

.

环境准备

  1. jdk 1.8.0
  2. IntelliJ IDEA Community Edition 2018.3.1 x64

配置信息

  1. 调试配置
    1. 配置位置:Run/Debug Configurations -> program arguments
    2. 配置内容:-Xjre "C:/Program Files/Java/jdk1.8.0_161/jre" E:/itstack/git/istack-demo/itstack-demo-jvm/itstack-demo-jvm-09/target/test-classes/org/itstack/demo/test/HelloWorld

代码示例

itstack-demo-jvm-09├── pom.xml└── src    └── main    │    └── java    │        └── org.itstack.demo.jvm    │             ├── _native    │             │   ├── java    │             │   │   ├── _Class.java    │             │   │   ├── _Double.java    │             │   │   ├── _Float.java    │             │   │   ├── _Object.java    │             │   │   ├── _String.java    │             │   │   └── _System.java	    │             │   └── sun	    │             ├── NativeMethod.java    │             └── Registry.java	    │             ├── classfile    │             │   ├── attributes       │             │   ├── constantpool     │             │   ├── ClassFile.java    │             │   ├── ClassReader.java    │             │   └── MemberInfo.java       │             ├── classpath    │             │   ├── impl    │             │   │   ├── CompositeEntry.java    │             │   │   ├── DirEntry.java     │             │   │   ├── WildcardEntry.java     │             │   │   └── ZipEntry.java        │             │   ├── Classpath.java    │             │   └── Entry.java       │             ├── classpath    │             │   ├── base    │             │   │   ├── BytecodeReader.java    │             │   │   ├── ClassInitLogic.java    │             │   │   ├── Instruction.java    │             │   │   ├── InstructionBranch.java    │             │   │   ├── InstructionIndex8.java    │             │   │   ├── InstructionIndex16.java    │             │   │   ├── InstructionNoOperands.java	    │             │   │   └── MethodInvokeLogic.java    │             │   ├── comparisons    │             │   ├── constants    │             │   ├── control    │             │   ├── conversions    │             │   ├── extended    │             │   ├── loads    │             │   ├── math    │             │   ├── references    │             │   │   ├── ANEW_ARRAY.java    │             │   │   ├── ARRAY_LENGTH.java    │             │   │   ├── CHECK_CAST.java    │             │   │   ├── GET_FIELD.java    │             │   │   ├── GET_STATIC.java    │             │   │   ├── INSTANCE_OF.java    │             │   │   ├── INVOKE_INTERFACE.java    │             │   │   ├── INVOKE_SPECIAL.java    │             │   │   ├── INVOKE_STATIC.java    │             │   │   ├── INVOKE_VIRTUAL.java    │             │   │   ├── MULTI_ANEW_ARRAY.java    │             │   │   ├── NEW.java    │             │   │   ├── NEW_ARRAY.java    │             │   │   ├── PUT_FIELD.java    │             │   │   └── PUT_STATIC.java    │             │   ├── reserved    │             │   │   └── INVOKE_NATIVE.java	    │             │   ├── stack    │             │   ├── store    │             │   │   └── xastore    │             │   │       ├── AASTORE.java	    │             │   │       ├── BASTORE.java	    │             │   │       ├── CASTORE.java	    │             │   │       ├── DASTORE.java    │             │   │       ├── FASTORE.java    │             │   │       ├── IASTORE.java    │             │   │       ├── LASTORE.java	    │             │   │       └── SASTORE.java		    │             │   └── Factory       │             ├── rtda    │             │   ├── heap    │             │   │   ├── constantpool    │             │   │   ├── methodarea    │             │   │   │   ├── Class.java        │             │   │   │   ├── ClassMember.java      │             │   │   │   ├── Field.java        │             │   │   │   ├── Method.java     │             │   │   │   ├── MethodDescriptor.java     │             │   │   │   ├── MethodDescriptorParser.java     │             │   │   │   ├── MethodLookup.java 	    │             │   │   │   ├── Object.java       │             │   │   │   ├── Slots.java       │             │   │   │   └── StringPool.java	    │             │   │   └── ClassLoader.java      │             │   ├── Frame.java    │             │   ├── JvmStack.java    │             │   ├── LocalVars.java    │             │   ├── OperandStack.java    │             │   ├── Slot.java     │             │   └── Thread.java    │             ├── Cmd.java    │             ├── Interpret.java        │             └── Main.java    └── test         └── java             └── org.itstack.demo.test                 └── HelloWorld.java

代码片段

.

_Class.java

.
package org.itstack.demo.jvm._native.java;import org.itstack.demo.jvm._native.NativeMethod;import org.itstack.demo.jvm._native.Registry;import org.itstack.demo.jvm.rtda.Frame;import org.itstack.demo.jvm.rtda.LocalVars;import org.itstack.demo.jvm.rtda.OperandStack;import org.itstack.demo.jvm.rtda.heap.ClassLoader;import org.itstack.demo.jvm.rtda.heap.methodarea.Class;import org.itstack.demo.jvm.rtda.heap.methodarea.Object;import org.itstack.demo.jvm.rtda.heap.methodarea.StringPool;/** * http://www.itstack.org * create by fuzhengwei on 2019/4/30 */public class _Class {    private final String jlClass = "java/lang/Class";    public _Class() {        Registry.register(jlClass, "getPrimitiveClass", "(Ljava/lang/String;)Ljava/lang/Class;", new NativeMethod(this, "getPrimitiveClass"));        Registry.register(jlClass, "getName0", "()Ljava/lang/String;", new NativeMethod(this, "getName0"));        Registry.register(jlClass, "desiredAssertionStatus0", "(Ljava/lang/Class;)Z", new NativeMethod(this, "desiredAssertionStatus0"));        Registry.register(jlClass, "registerNatives", "()V", new NativeMethod(this, "registerNatives"));    }    public void registerNatives(Frame frame) {        // do nothing    }    public void getPrimitiveClass(Frame frame) {        Object nameObj = frame.localVars().getRef(0);        String name = StringPool.goString(nameObj);        ClassLoader loader = frame.method().clazz().loader();        Object jClass = loader.loadClass(name).jClass();        frame.operandStack().pushRef(jClass);    }    public void getName0(Frame frame) {        Object thiz = frame.localVars().getThis();        Class clazz = (Class) thiz.extra();        String name = "虚拟机本地方法getName0获取类名:" + clazz.javaName();        Object nameObj = StringPool.jString(clazz.loader(), name);        frame.operandStack().pushRef(nameObj);    }    public void desiredAssertionStatus0(Frame frame) {        frame.operandStack().pushBoolean(false);    }    public void isInterface(Frame frame) {        LocalVars vars = frame.localVars();        Object thiz = vars.getThis();        Class clazz = (Class) thiz.extra();        OperandStack stack = frame.operandStack();        stack.pushBoolean(clazz.isInterface());    }    public void isPrimitive(Frame frame) {        LocalVars vars = frame.localVars();        Object thiz = vars.getThis();        Class clazz = (Class) thiz.extra();        OperandStack stack = frame.operandStack();        stack.pushBoolean(clazz.IsPrimitive());    }}
.

_System.java

.
package org.itstack.demo.jvm._native.java;import org.itstack.demo.jvm._native.NativeMethod;import org.itstack.demo.jvm._native.Registry;import org.itstack.demo.jvm.rtda.Frame;import org.itstack.demo.jvm.rtda.LocalVars;import org.itstack.demo.jvm.rtda.heap.methodarea.Class;import org.itstack.demo.jvm.rtda.heap.methodarea.Object;/** * http://www.itstack.org * create by fuzhengwei on 2019/4/30 */public class _System {    private final String jlSystem = "java/lang/System";    public _System() {        Registry.register(jlSystem, "arraycopy", "()Ljava/lang/String;", new NativeMethod(this, "arraycopy"));        Registry.register(jlSystem,"registerNatives", "()V",new NativeMethod(this,"registerNatives"));    }    public void registerNatives(Frame frame) {        // do nothing    }        public void arraycopy(Frame frame) {        LocalVars vars = frame.localVars();        Object src = vars.getRef(0);        int srcPos = vars.getInt(1);        Object dest = vars.getRef(2);        int destPos = vars.getInt(4);        int length = vars.getInt(4);        if (null == src || dest == null) {            throw new NullPointerException();        }        if (!checkArrayCopy(src, dest)) {            throw new ArrayStoreException();        }        if (srcPos < 0 || destPos < 0 || length < 0 ||                srcPos + length > src.arrayLength() ||                destPos + length > dest.arrayLength()) {            throw new IndexOutOfBoundsException();        }        System.arraycopy(src, srcPos, dest, destPos, length);        //todo 待完善    }    public boolean checkArrayCopy(Object src, Object dest) {        Class srcClass = src.clazz();        Class destClass = dest.clazz();        if (!srcClass.isArray() || !destClass.isArray()) {            return false;        }        if (srcClass.componentClass().IsPrimitive() || destClass.componentClass().IsPrimitive()) {            return srcClass == destClass;        }        return true;    }}
.

NativeMethod.java

.
package org.itstack.demo.jvm._native;import org.itstack.demo.jvm.rtda.Frame;import java.lang.reflect.Method;/** * http://www.itstack.org * create by fuzhengwei on 2019/4/30 */public class NativeMethod {    private String methodName;    private Object obj;    public NativeMethod(Object obj, String methodName) {        this.methodName = methodName;        this.obj = obj;    }    public void invoke(Frame frame) {        try {            Method method = obj.getClass().getMethod(methodName, frame.getClass());            method.invoke(obj, frame);        } catch (Exception e) {            e.printStackTrace();        }    }}
.

Registry.java

.
package org.itstack.demo.jvm._native;import org.itstack.demo.jvm._native.java.*;import java.util.HashMap;import java.util.Map;/** * http://www.itstack.org * create by fuzhengwei on 2019/4/30 */public class Registry {    private static Map<String, NativeMethod> registry = new HashMap<>();    //初始化本地方法    public static void initNative() {        new _Class();        new _Double();        new _Float();        new _Object();        new _String();        new _System();    }    public static void register(String className, String methodName, String methodDescriptor, NativeMethod method) {        String key = className + "~" + methodName + "~" + methodDescriptor;        registry.put(key, method);    }    public static NativeMethod findNativeMethod(String className, String methodName, String methodDescriptor) {        String key = className + "~" + methodName + "~" + methodDescriptor;        return registry.get(key);    }}
.

INVOKE_NATIVE.java

.
package org.itstack.demo.jvm.instructions.reserved;import org.itstack.demo.jvm._native.NativeMethod;import org.itstack.demo.jvm._native.Registry;import org.itstack.demo.jvm.instructions.base.InstructionNoOperands;import org.itstack.demo.jvm.rtda.Frame;import org.itstack.demo.jvm.rtda.heap.methodarea.Method;/** * http://www.itstack.org * create by fuzhengwei on 2019/5/2 */public class INVOKE_NATIVE extends InstructionNoOperands {    @Override    public void execute(Frame frame) {        Method method = frame.method();        String className = method.clazz().name();        String methodName = method.name();        String methodDescriptor = method.descriptor();        NativeMethod nativeMethod = Registry.findNativeMethod(className, methodName, methodDescriptor);        if (null == nativeMethod) {            String methodInfo = className + "." + methodName + methodDescriptor;            throw new UnsatisfiedLinkError(methodInfo);        }        nativeMethod.invoke(frame);    }}
.

ClassLoader.java

.
package org.itstack.demo.jvm.rtda.heap;import org.itstack.demo.jvm.classfile.ClassFile;import org.itstack.demo.jvm.classpath.Classpath;import org.itstack.demo.jvm.rtda.heap.constantpool.AccessFlags;import org.itstack.demo.jvm.rtda.heap.methodarea.*;import org.itstack.demo.jvm.rtda.heap.constantpool.RunTimeConstantPool;import org.itstack.demo.jvm.rtda.heap.methodarea.Class;import org.itstack.demo.jvm.rtda.heap.methodarea.Object;import java.util.HashMap;import java.util.Map;/*class names:    - primitive types: boolean, byte, int ...    - primitive arrays: [Z, [B, [I ...    - non-array classes: java/lang/Object ...    - array classes: [Ljava/lang/Object; ...*/public class ClassLoader {    private Classpath classpath;    private Map<String, Class> classMap;    public ClassLoader(Classpath classpath) {        this.classpath = classpath;        this.classMap = new HashMap<>();        this.loadBasicClasses();        this.loadPrimitiveClasses();    }    private void loadBasicClasses() {        Class jlClassClass = this.loadClass("java/lang/Class");        for (Map.Entry<String, Class> entry : this.classMap.entrySet()) {            Class clazz = entry.getValue();            if (clazz.jClass == null) {                clazz.jClass = jlClassClass.newObject();                clazz.jClass.extra = clazz;            }        }    }    private void loadPrimitiveClasses() {        for (Map.Entry<String, String> entry : ClassNameHelper.primitiveTypes.entrySet()) {            loadPrimitiveClass(entry.getKey());        }    }    private void loadPrimitiveClass(String className) {        Class clazz = new Class(AccessFlags.ACC_PUBLIC,                className,                this,                true);        clazz.jClass = this.classMap.get("java/lang/Class").newObject();        clazz.jClass.extra = clazz;        this.classMap.put(className, clazz);    }    public Class loadClass(String className) {        Class clazz = classMap.get(className);        if (null != clazz) return clazz;        //'['数组标识        if (className.getBytes()[0] == '[') {            clazz = loadArrayClass(className);        } else {            clazz = loadNonArrayClass(className);        }        Class jlClazz = this.classMap.get("java/lang/Class");        if (null != jlClazz && null != clazz) {            clazz.jClass = jlClazz.newObject();            clazz.jClass.extra = clazz;        }        return clazz;    }    private Class loadArrayClass(String className) {        Class clazz = new Class(AccessFlags.ACC_PUBLIC,                className,                this,                true,                this.loadClass("java/lang/Object"),                new Class[]{                        this.loadClass("java/lang/Cloneable"),                        this.loadClass("java/io/Serializable")});        this.classMap.put(className, clazz);        return clazz;    }    private Class loadNonArrayClass(String className) {        try {            byte[] data = this.classpath.readClass(className);            if (null == data) {                throw new ClassNotFoundException(className);            }            Class clazz = defineClass(data);            link(clazz);            return clazz;        } catch (Exception e) {            e.printStackTrace();            return null;        }    }    private void link(Class clazz) {        verify(clazz);        prepare(clazz);    }    private void prepare(Class clazz) {        calcInstanceFieldSlotIds(clazz);        calcStaticFieldSlotIds(clazz);        allocAndInitStaticVars(clazz);    }    private void allocAndInitStaticVars(Class clazz) {        clazz.staticVars = new Slots(clazz.staticSlotCount);        for (Field field : clazz.fields) {            if (field.isStatic() && field.isFinal()) {                initStaticFinalVar(clazz, field);            }        }    }    private void initStaticFinalVar(Class clazz, Field field) {        Slots staticVars = clazz.staticVars;        RunTimeConstantPool constantPool = clazz.runTimeConstantPool;        int cpIdx = field.constValueIndex();        int slotId = field.slotId();        if (cpIdx > 0) {            switch (field.descriptor()) {                case "Z":                case "B":                case "C":                case "S":                case "I":                    java.lang.Object val = constantPool.getConstants(cpIdx);                    staticVars.setInt(slotId, (Integer) val);                    break;                case "J":                    staticVars.setLong(slotId, (Long) constantPool.getConstants(cpIdx));                    break;                case "F":                    staticVars.setFloat(slotId, (Float) constantPool.getConstants(cpIdx));                    break;                case "D":                    staticVars.setDouble(slotId, (Double) constantPool.getConstants(cpIdx));                    break;                case "Ljava/lang/String;":                    String goStr = (String) constantPool.getConstants(cpIdx);                    Object jStr = StringPool.jString(clazz.loader(), goStr);                    staticVars.setRef(slotId, jStr);                    break;            }        }    }    private void calcStaticFieldSlotIds(Class clazz) {        int slotId = 0;        for (Field field : clazz.fields) {            if (field.isStatic()) {                field.slotId = slotId;                slotId++;                if (field.isLongOrDouble()) {                    slotId++;                }            }        }        clazz.staticSlotCount = slotId;    }    private void calcInstanceFieldSlotIds(Class clazz) {        int slotId = 0;        if (clazz.superClass != null) {            slotId = clazz.superClass.instanceSlotCount;        }        for (Field field : clazz.fields) {            if (!field.isStatic()) {                field.slotId = slotId;                slotId++;                if (field.isLongOrDouble()) {                    slotId++;                }            }        }        clazz.instanceSlotCount = slotId;    }    private void verify(Class clazz) {        // 校验字节码,尚未实现    }    private Class defineClass(byte[] data) throws Exception {        Class clazz = parseClass(data);        clazz.loader = this;        resolveSuperClass(clazz);        resolveInterfaces(clazz);        this.classMap.put(clazz.name, clazz);        return clazz;    }    private void resolveInterfaces(Class clazz) throws Exception {        int interfaceCount = clazz.interfaceNames.length;        if (interfaceCount > 0) {            clazz.interfaces = new Class[interfaceCount];            for (int i = 0; i < interfaceCount; i++) {                clazz.interfaces[i] = clazz.loader.loadClass(clazz.interfaceNames[i]);            }        }    }    private void resolveSuperClass(Class clazz) throws Exception {        if (!clazz.name.equals("java/lang/Object")) {            clazz.superClass = clazz.loader.loadClass(clazz.superClassName);        }    }    private Class parseClass(byte[] data) {        ClassFile classFile = new ClassFile(data);        return new Class(classFile);    }}
.

HelloWorld.java

.
package org.itstack.demo.test;/** * -Xjre "C:/Program Files/Java/jdk1.8.0_161/jre" E:/itstack/git/istack-demo/itstack-demo-jvm/itstack-demo-jvm-09/target/test-classes/org/itstack/demo/test/HelloWorld -verbose true -args 你好,java版虚拟机v1.0,欢迎你的到来。 */public class HelloWorld {    public static void main(String[] args) {        System.out.println(byte.class.getName()); // byte        System.out.println(void.class.getName()); // void        System.out.println(boolean.class.getName()); // boolean        System.out.println(char.class.getName()); // char        System.out.println(short.class.getName()); // short        System.out.println(int.class.getName()); // int        System.out.println(long.class.getName()); // long        System.out.println(float.class.getName()); // float        System.out.println(double.class.getName()); // double        System.out.println(Object.class.getName()); // java.lang.Object        System.out.println(int[].class.getName()); // [I        System.out.println(int[][].class.getName()); // [[I        System.out.println(Object[].class.getName()); // [Ljava.lang.Object;        System.out.println(Object[][].class.getName()); // [[Ljava.lang.Object;    }}

测试结果

虚拟机本地方法getName0获取类名:byte虚拟机本地方法getName0获取类名:void虚拟机本地方法getName0获取类名:boolean虚拟机本地方法getName0获取类名:char虚拟机本地方法getName0获取类名:short虚拟机本地方法getName0获取类名:int虚拟机本地方法getName0获取类名:long虚拟机本地方法getName0获取类名:float虚拟机本地方法getName0获取类名:double虚拟机本地方法getName0获取类名:java.lang.Object虚拟机本地方法getName0获取类名:[I虚拟机本地方法getName0获取类名:[[I虚拟机本地方法getName0获取类名:[Ljava.lang.Object;虚拟机本地方法getName0获取类名:[[Ljava.lang.Object;

上一篇:用Java实现JVM第八章《数组和字符串》

下一篇:用Java实现JVM第十章《异常处理》

微信搜索「bugstack虫洞栈」公众号,关注后回复「用Java实现jvm源码」获取本文源码&更多原创专题案例!

.

.

广告 广告

评论区