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

案例介绍

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

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

环境准备

jdk 1.8.0

IntelliJ IDEA Community Edition 2018.3.1 x64

配置信息

调试配置

配置位置:Run/Debug Configurations -> program arguments

配置内容:-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 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 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 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 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;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值