mirror of
https://github.com/FranzHaidnor/haidnorJVM.git
synced 2026-03-13 21:43:42 +08:00
add INVOKEINTERFACE
This commit is contained in:
@@ -88,22 +88,24 @@ public class JavaExecutionEngine {
|
||||
|
||||
log.debug("{}├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌", blank);
|
||||
|
||||
// 执行方法中的字节码指令 tip:(int i, 相当于程序计数器, 记录当前执行到的字节码指令的”行号“)
|
||||
for (int i = 0; i < frame.getCodeLength(); ) {
|
||||
Instruction instruction = instructionMap.get(i);
|
||||
// 执行方法中的字节码指令 tip:(int pc, 相当于程序计数器, 记录当前执行到的字节码指令的”行号“)
|
||||
for (int pc = 0; pc < frame.getCodeLength(); ) {
|
||||
Instruction instruction = instructionMap.get(pc);
|
||||
log.debug("{}│ {}", blank, instruction);
|
||||
try {
|
||||
instruction.execute(frame);
|
||||
if (instruction instanceof RETURN || instruction instanceof ARETURN || instruction instanceof DRETURN || instruction instanceof FRETURN || instruction instanceof IRETURN) {
|
||||
break;
|
||||
}
|
||||
i += instruction.offSet();
|
||||
} catch (Exception exception) {
|
||||
pc += instruction.offSet();
|
||||
}
|
||||
// catch instruction.execute() Exception
|
||||
catch (Exception exception) {
|
||||
Integer handlerPC = null;
|
||||
|
||||
CodeException[] exceptionTable = frame.getMethod().getCode().getExceptionTable();
|
||||
for (CodeException codeException : exceptionTable) {
|
||||
if (codeException.getStartPC() <= i & i <= codeException.getEndPC()) {
|
||||
if (codeException.getStartPC() <= pc & pc <= codeException.getEndPC()) {
|
||||
int catchType = codeException.getCatchType();
|
||||
// 0, if the handler catches any exception, otherwise it points to the exception class which is to be caught.
|
||||
if (catchType == 0) {
|
||||
@@ -121,7 +123,7 @@ public class JavaExecutionEngine {
|
||||
}
|
||||
}
|
||||
if (handlerPC != null) {
|
||||
i = handlerPC;
|
||||
pc = handlerPC;
|
||||
} else {
|
||||
log.debug("{}└──────────────────[{}] No Exception Handler Return!", blank, stackSize);
|
||||
throw exception;
|
||||
|
||||
@@ -577,7 +577,7 @@ public abstract class InstructionFactory {
|
||||
return new INVOKESTATIC(codeStream);
|
||||
}
|
||||
case Const.INVOKEINTERFACE -> {
|
||||
throw new Error("Not support JavaVM opcode INVOKEINTERFACE");
|
||||
return new INVOKEINTERFACE(codeStream);
|
||||
}
|
||||
case Const.INVOKEDYNAMIC -> {
|
||||
throw new Error("Not support JavaVM opcode INVOKEDYNAMIC");
|
||||
@@ -604,10 +604,10 @@ public abstract class InstructionFactory {
|
||||
return new INSTANCEOF(codeStream);
|
||||
}
|
||||
case Const.MONITORENTER -> {
|
||||
throw new Error("Not support JavaVM opcode MONITORENTER");
|
||||
return new MONITORENTER(codeStream);
|
||||
}
|
||||
case Const.MONITOREXIT -> {
|
||||
throw new Error("Not support JavaVM opcode MONITOREXIT");
|
||||
return new MONITOREXIT(codeStream);
|
||||
}
|
||||
case Const.WIDE -> {
|
||||
throw new Error("Not support JavaVM opcode WIDE");
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
package haidnor.jvm.instruction.references;
|
||||
|
||||
import haidnor.jvm.classloader.ClassLoader;
|
||||
import haidnor.jvm.core.JavaExecutionEngine;
|
||||
import haidnor.jvm.instruction.Instruction;
|
||||
import haidnor.jvm.rtda.Instance;
|
||||
import haidnor.jvm.rtda.Klass;
|
||||
import haidnor.jvm.rtda.KlassMethod;
|
||||
import haidnor.jvm.rtda.Metaspace;
|
||||
import haidnor.jvm.runtime.Frame;
|
||||
import haidnor.jvm.runtime.StackValue;
|
||||
import haidnor.jvm.util.CodeStream;
|
||||
import haidnor.jvm.util.ConstantPoolUtil;
|
||||
import haidnor.jvm.util.SignatureUtil;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.bcel.Const;
|
||||
import org.apache.bcel.classfile.ConstantInterfaceMethodref;
|
||||
import org.apache.bcel.classfile.ConstantPool;
|
||||
import org.apache.bcel.classfile.JavaClass;
|
||||
import org.apache.bcel.classfile.Utility;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 调用对象实例方法,根据对象的实际类型进行分派(虚方法分派),支持多态
|
||||
*/
|
||||
public class INVOKEINTERFACE extends Instruction {
|
||||
|
||||
private final int constantMethodrefIndex;
|
||||
|
||||
public final int count;
|
||||
|
||||
public final int zero;
|
||||
|
||||
public INVOKEINTERFACE(CodeStream codeStream) {
|
||||
super(codeStream);
|
||||
this.constantMethodrefIndex = codeStream.readUnsignedShort(this);
|
||||
this.count = codeStream.readUnsignedByte(this);
|
||||
this.zero = codeStream.readUnsignedByte(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void execute(Frame frame) {
|
||||
ConstantPool constantPool = frame.getConstantPool();
|
||||
ConstantPoolUtil constantPoolUtil = frame.getConstantPoolUtil();
|
||||
|
||||
ConstantInterfaceMethodref interfaceMethodref = constantPool.getConstant(constantMethodrefIndex);
|
||||
|
||||
int classIndex = interfaceMethodref.getClassIndex();
|
||||
String interfaceName = constantPoolUtil.getConstantClassClassName(classIndex);
|
||||
|
||||
int nameAndTypeIndex = interfaceMethodref.getNameAndTypeIndex();
|
||||
String methodName = constantPoolUtil.constantNameAndType_name(nameAndTypeIndex);
|
||||
String methodSignature = constantPoolUtil.constantNameAndType_signature(nameAndTypeIndex);
|
||||
|
||||
// 系统类反射 自定义类另外处理
|
||||
if (interfaceName.startsWith("java/")) {
|
||||
// 解析方法签名得到方法的返回类型
|
||||
String returnType = Utility.methodSignatureReturnType(methodSignature, false);
|
||||
// 执行方法的参数列表
|
||||
Class<?>[] parameterTypeArr = SignatureUtil.getParameterTypes(methodSignature);
|
||||
// 执行方法的参数值
|
||||
Object[] args = frame.popStacksValue(parameterTypeArr.length);
|
||||
// 将特定的参数转换为基本类型
|
||||
for (int i = 0; i < parameterTypeArr.length; i++) {
|
||||
Class<?> clazz = parameterTypeArr[i];
|
||||
if (clazz.getName().equals("boolean")) { // boolean 存储方式为 int 类型
|
||||
int booleanFlag = (int) args[i];
|
||||
args[i] = booleanFlag == 1;
|
||||
} else if (clazz.getName().equals("char")) { // char 存储方式为
|
||||
int charInt = (int) args[i];
|
||||
char c = (char) charInt;
|
||||
args[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
StackValue stackValue = frame.pop();
|
||||
Object obj = stackValue.getValue();
|
||||
Method method = obj.getClass().getMethod(methodName, parameterTypeArr);
|
||||
method.setAccessible(true);
|
||||
Object value = method.invoke(obj, args);
|
||||
if (!Objects.equals(Const.getTypeName(Const.T_VOID), returnType)) { // void 调用的方法无返回值
|
||||
frame.push(new StackValue(Const.T_OBJECT, value));
|
||||
}
|
||||
}
|
||||
// 调用自定义类的方法
|
||||
else {
|
||||
Klass interfaceKlass = Metaspace.getJavaClass(Utility.compactClassName(interfaceName));
|
||||
if (interfaceKlass == null) {
|
||||
ClassLoader classLoader = frame.getMetaClass().getClassLoader();
|
||||
classLoader.loadClass(interfaceName);
|
||||
}
|
||||
|
||||
StackValue stackValue = frame.peek();
|
||||
Instance instance = (Instance) stackValue.getValue();
|
||||
Klass klass = instance.klass;
|
||||
|
||||
// 按照继承关系从下往上找实现的方法 (实现多态)
|
||||
org.apache.bcel.classfile.Method method = getMethod(klass.getJavaClass(), methodSignature, methodName);
|
||||
// 从接口找方法 JDK8. interface default()
|
||||
if (method == null) {
|
||||
method = getMethodFromInterface(klass.getJavaClass(), methodSignature, methodName);
|
||||
}
|
||||
if (method == null) {
|
||||
throw new AbstractMethodError();
|
||||
}
|
||||
KlassMethod klassMethod = new KlassMethod(klass, method);
|
||||
JavaExecutionEngine.callMethod(frame, klassMethod);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归查找方法, 如果子类没有实现方法则向父类查找
|
||||
*/
|
||||
private static org.apache.bcel.classfile.Method getMethod(JavaClass javaClass, String methodSignature, String methodName) throws ClassNotFoundException {
|
||||
org.apache.bcel.classfile.Method m = null;
|
||||
for (org.apache.bcel.classfile.Method method : javaClass.getMethods()) {
|
||||
if (method.getSignature().equals(methodSignature) && method.getName().equals(methodName)) {
|
||||
m = method;
|
||||
}
|
||||
}
|
||||
if (m != null) {
|
||||
return m;
|
||||
}
|
||||
if (javaClass.getSuperClass() == null) {
|
||||
return null;
|
||||
}
|
||||
return getMethod(javaClass.getSuperClass(), methodSignature, methodName);
|
||||
}
|
||||
|
||||
private static org.apache.bcel.classfile.Method getMethodFromInterface(JavaClass javaClass, String methodSignature, String methodName) throws ClassNotFoundException {
|
||||
JavaClass[] interfaces = javaClass.getInterfaces();
|
||||
for (JavaClass anInterface : interfaces) {
|
||||
for (org.apache.bcel.classfile.Method method : anInterface.getMethods()) {
|
||||
if (method.getSignature().equals(methodSignature) && method.getName().equals(methodName)) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package haidnor.jvm.instruction.references;
|
||||
|
||||
import haidnor.jvm.instruction.Instruction;
|
||||
import haidnor.jvm.runtime.Frame;
|
||||
import haidnor.jvm.util.CodeStream;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
public class MONITORENTER extends Instruction {
|
||||
|
||||
public MONITORENTER(CodeStream codeStream) {
|
||||
super(codeStream);
|
||||
throw new UnsupportedOperationException("MONITORENTER");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void execute(Frame frame) {
|
||||
throw new UnsupportedOperationException("MONITORENTER");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package haidnor.jvm.instruction.references;
|
||||
|
||||
import haidnor.jvm.instruction.Instruction;
|
||||
import haidnor.jvm.runtime.Frame;
|
||||
import haidnor.jvm.util.CodeStream;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
public class MONITOREXIT extends Instruction {
|
||||
|
||||
public MONITOREXIT(CodeStream codeStream) {
|
||||
super(codeStream);
|
||||
throw new UnsupportedOperationException("MONITOREXIT");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void execute(Frame frame) {
|
||||
throw new UnsupportedOperationException("MONITOREXIT");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,6 +46,7 @@ public class ConstantPoolUtil {
|
||||
ConstantUtf8 constantUtf8 = cp.getConstant(constantClass.getNameIndex());
|
||||
return constantUtf8.getBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取长类名, 例如 java/lang/String
|
||||
*/
|
||||
@@ -132,4 +133,24 @@ public class ConstantPoolUtil {
|
||||
return constNameAndType.getSignature(cp);
|
||||
}
|
||||
|
||||
// ConstantNameAndType -----------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* ConstantNameAndType
|
||||
*/
|
||||
public ConstantNameAndType constantNameAndType(int constantNameAndTypeIndex) {
|
||||
return cp.getConstant(constantNameAndTypeIndex);
|
||||
}
|
||||
|
||||
public String constantNameAndType_name(int constantNameAndTypeIndex) {
|
||||
ConstantNameAndType constantNameAndType = constantNameAndType(constantNameAndTypeIndex);
|
||||
return constantNameAndType.getName(cp);
|
||||
}
|
||||
|
||||
public String constantNameAndType_signature(int constantNameAndTypeIndex) {
|
||||
ConstantNameAndType constantNameAndType = constantNameAndType(constantNameAndTypeIndex);
|
||||
return constantNameAndType.getSignature(cp);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import haidnor.jvm.test.instruction.Array;
|
||||
import haidnor.jvm.test.instruction.DO_WHILE;
|
||||
import haidnor.jvm.test.instruction.math.ISUB;
|
||||
import haidnor.jvm.test.instruction.math.LSUB;
|
||||
import haidnor.jvm.test.instruction.references.INVOKEINTERFACE;
|
||||
import haidnor.jvm.test.instruction.references.NEW;
|
||||
import haidnor.jvm.util.JavaClassUtil;
|
||||
import haidnor.jvm.util.JvmThreadHolder;
|
||||
@@ -75,6 +74,11 @@ public class TestJVM {
|
||||
runMainClass(Demo7.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_8() throws Exception {
|
||||
runMainClass(Demo8.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_NEW() throws Exception {
|
||||
runMainClass(NEW.class);
|
||||
@@ -100,11 +104,6 @@ public class TestJVM {
|
||||
runMainClass(Array.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_INVOKEINTERFACE() throws Exception {
|
||||
runMainClass(INVOKEINTERFACE.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_() throws Exception {
|
||||
String jarFilePath = "D:\\project_java\\JvmDemo\\target\\JvmDemo-1.0-SNAPSHOT.jar";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package haidnor.jvm.test.clazz;
|
||||
|
||||
public class Human {
|
||||
public class Human implements Organism {
|
||||
|
||||
public static final String HUMAN_NAME = "123";
|
||||
|
||||
|
||||
12
src/test/java/haidnor/jvm/test/clazz/Organism.java
Normal file
12
src/test/java/haidnor/jvm/test/clazz/Organism.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package haidnor.jvm.test.clazz;
|
||||
|
||||
/**
|
||||
* 生物
|
||||
*/
|
||||
public interface Organism {
|
||||
|
||||
default void die() {
|
||||
System.out.println("Organism die");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,6 @@
|
||||
package haidnor.jvm.test.clazz;
|
||||
|
||||
public class Student extends Human {
|
||||
|
||||
public static String school = "Hello World!";
|
||||
|
||||
static {
|
||||
System.out.println(HUMAN_NAME);
|
||||
System.out.println("student 类被加载了");
|
||||
}
|
||||
public class Student implements Organism {
|
||||
|
||||
public void method1() {
|
||||
System.out.println("method1");
|
||||
|
||||
17
src/test/java/haidnor/jvm/test/demo/Demo8.java
Normal file
17
src/test/java/haidnor/jvm/test/demo/Demo8.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package haidnor.jvm.test.demo;
|
||||
|
||||
|
||||
import haidnor.jvm.test.clazz.Human;
|
||||
import haidnor.jvm.test.clazz.Organism;
|
||||
import haidnor.jvm.test.clazz.Student;
|
||||
|
||||
public class Demo8 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Human organism1 = new Human();
|
||||
Organism organism = new Student();
|
||||
organism.die();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package haidnor.jvm.test.instruction.references;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
public class INVOKEINTERFACE {
|
||||
|
||||
public static void main(String[] args) {
|
||||
HashSet<Integer> set = new HashSet<>();
|
||||
set.add(1);
|
||||
int size = set.size();
|
||||
System.out.println(size);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user