kvm解释器-003

本文继续介绍kvm中解释执行的步骤.接上文,目前栈中的情况如图所示:

在这里插入图片描述

初始化Thread

此处初始化的步骤和上文中介绍的一样,也是调用runClinit方法.首先设置初始化线程为CurrentThread,然后由于其父类Object此时的状态为CLASS_READY,因此就不需要初始化父类了.此处的代码如下:

if ((thisClass->clazz.accessFlags & ACC_INTERFACE) == 0) {
    INSTANCE_CLASS superClass = thisClass->superClass;
    if (superClass && superClass->status != CLASS_READY) {
        topStack = 4;
        initializeClass(superClass);
        return;
    }
}

同样由于thread没有方法,因此会直接修改状态为CLASS_READY,然后进行弹栈操作.则此时栈的情况如图所示:

在这里插入图片描述

初始化String,System,OutOfMemoryError

对于String, System而言,其初始化过程和 Thread一致.而对于OutOfMemoryError而言,其继承结构如下:

在这里插入图片描述
因此对于OutOfMemoryError,会首先将状态改为4,然后尝试初始化VirtualMachineError,同样的VirtualMachineError将状态改为4,然后初始化Error,然后初始化Throwable.对于Throwable而言,其父类为Object已经为CLASS_READY,因此在runClinit方法中,直接将状态改为CLASS_READY,然后弹栈.接下来是Error,将状态改为CLASS_READY,然后弹栈.然后是VirtualMachineError,将状态改为CLASS_READY,然后弹栈.最终将OutOfMemoryError状态改为CLASS_READY,然后弹栈.则此时的栈的情况如图所示:

在这里插入图片描述

其实对于System而言,由于其内部有个静态字段.如下:

public final static PrintStream out = getOutput();

private static PrintStream getOutput() {
    return new PrintStream(new com.sun.cldc.io.ConsoleOutputStream());
}

因此,javac会生成一个方法.进行out字段的初始化.不过这里我就不展开了.

初始化主类

由于我们的主类代码如下:

public class KVMTest{
	
   public static void main(String[] args){
   	
      System.out.println("success");	
   } 

	
}

因此在runClinit方法中,直接将状态改为CLASS_READY,然后弹栈(父类Object的状态已经是CLASS_READY).则此时的栈的情况如下:

在这里插入图片描述

调用主类方法

此处同样,对应的字节码是CUSTOMCODE,其最终调用的是initInitialThreadBehaviorFromThread.此处的代码如下:

static void
initInitialThreadBehaviorFromThread(FRAME_HANDLE exceptionFrameH) {
    INSTANCE_CLASS thisClass;
    METHOD thisMethod;
    // 1. 如果有异常,则直接return
    if (exceptionFrameH != NULL) {
        /* We have no interest in dealing with exceptions. */
        return;
    }
    thisClass = secondStackAsType(INSTANCE_CLASS);// 获得主类名称

    // 2. 获得main方法
    thisMethod = getSpecialMethod(thisClass, mainNameAndType);
    if (thisMethod == NULL) {// 如果main方法不存在,则终止执行
        AlertUser(KVM_MSG_CLASS_DOES_NOT_HAVE_MAIN_FUNCTION);
        stopThread();
    } else if ((thisMethod->accessFlags & ACC_PUBLIC) == 0) {// 如果main方法的修饰符不是public,则终止执行
        AlertUser(KVM_MSG_MAIN_FUNCTION_MUST_BE_PUBLIC);
        stopThread();
    } else {
        START_TEMPORARY_ROOTS
	      /*
	       * ARRAY arguments = (
        arguments = (*(ARRAY *)((GlobalState.gs_sp))),
        TemporaryRoots[TemporaryRootsLength++].cellp = (cell *)&arguments,
        arguments)
	       */
            DECLARE_TEMPORARY_ROOT(ARRAY, arguments, topStackAsType(ARRAY));
            /* Reinitialize the thread for the new method 3. 由于此处是最后一个栈帧,则需要做一些初始化工作*/
            setSP((CurrentThread->stack->cells - 1) + thisMethod->argCount); // 复用参数
            setFP(NULL);
            setIP(KILLTHREAD);
            pushFrame(thisMethod);
            ((ARRAY *)getLP())[0] = arguments;
        END_TEMPORARY_ROOTS
		// 4. 对同步的处理
        if (thisMethod->accessFlags & ACC_SYNCHRONIZED) {
            getFP()->syncObject = (OBJECT)thisClass;
            monitorEnter((OBJECT)thisClass);
        } else {
            getFP()->syncObject = NULL;
        }
    }
}

这里比较重要的是第3步.由于当前是最后一个栈帧,因此将sp设置为(CurrentThread->stack->cells - 1) + thisMethod->argCount.(为何这样设置,是因为就相当于隐式弹栈一样)。此时的情况如图所示

在这里插入图片描述

在pushFrame后,栈的情况为:

在这里插入图片描述
在经过 ((ARRAY *)getLP())[0] = arguments的处理,则最终栈的情况为:
在这里插入图片描述

关于main方法的执行,下文介绍.

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值