前言

本文结合 zero 解释器窥探 字节码 new 的实现逻辑,相关概念可以参考之前的文章

opcode new

参考之前的文章,可以在 bytecodeInterpreter.cpp 文件中找到字节码 new 对应的 case 语句块:

CASE(_new): {
    u2 index = Bytes::get_Java_u2(pc+1);
    ConstantPool* constants = istate->method()->constants();
    if (!constants->tag_at(index).is_unresolved_klass()) {
        ...
        return
    }
    // Slow case allocation
    CALL_VM(InterpreterRuntime::_new(THREAD, METHOD->constants(), index),
            handle_exception);
    // Must prevent reordering of stores for object initialization
    // with stores that publish the new object.
    OrderAccess::storestore();
    SET_STACK_OBJECT(THREAD->vm_result(), 0);
    THREAD->set_vm_result(NULL);
    UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1);
}

可以看到大致有两条执行路径

  • fast case allocation,要创建对象的类已经加载

  • slow case allocation,要创建对象的类未加载

我们先来看看类未加载的情况

slow case allocation

slow case allocation 会调用 InterpreterRuntime::_new 方法,调用的时候传入了三个参数:

  • THREAD,线程

  • METHOD->constants,方法对应的常量池

  • index,要创建的类在常量池中的索引

常量池是 JVM 里面很重要的一个概念,重要的事情说三遍:ConstantPool! ConstantPool! ConstantPool!

InterpreterRuntime::_new

代码很简洁,似乎没有看到加载 Klass 相关的代码,凭借多年撸代码的经验,加载 Klass 的代码应该是在 pool-> klass_at 函数里面

// interpreterRuntime.cpp

IRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* thread, ConstantPool* pool,   
    int index))
  Klass* k_oop = pool->klass_at(index, CHECK);
  instanceKlassHandle klass (THREAD, k_oop);

  // Make sure we are not instantiating an abstract klass
  klass->check_valid_for_instantiation(true, CHECK);

  // Make sure klass is initialized
  klass->initialize(CHECK);

  oop obj = klass->allocate_instance(CHECK);
  thread->set_vm_result(obj);
IRT_END

接下来的代码分析可能会比较冗长和乏味,如果只想大概了解一下 字节码 new 的实现,到这就够了~

ConstantPool::klass_at_impl

总结


xingpingz
122 声望64 粉丝

博学,审问,慎思,明辨,力行