我们写的java代码通过javac程序编译成class文件,然后由java程序解释执行class文件字节码指令。java.c执行程序入口main主方法,第一步创建JVM、第二步加载class文件及解析内容、第三步执行方法。创建JVM前面章节讲过,就是校验启动参数、计算线程栈大小堆大小、创建主线程等准备JVM环境;加载和解析class文件也有,就是类加载器加载class文件,解析里面的字段方法常量池封装成Klass对象。执行方法就是字节码指令的执行,组成执行环境的核心部分就是运行时数据区:Java栈、 JAVA堆、元空间(JDK8以下是永久代上面的实现方法区)、本地方法栈、PC寄存器(程序计数器)。
进程基本单位是线程,java程序运行就是java线程的执行。从计算器角度看就是操作系统调度执行java线程,送PC寄存器地址上的指令到CPU执行,以及在内存分配空间缓存数据。其中内存分配相关的是线程执行在栈上面创建栈帧执行方法和在堆上面创建对象,方法执行完栈帧销毁内存释放,而堆上面内存通过GC释放。
java线程
运行main方法就会创建一个主线程,操作系统调度执行main线程。显式new Thread()创建Java线程也是一样,交由操作系统调度。
java中启动一个线程,操作系统也创建一个线程,两个关联起来,所以java线程实际是操作系统的线程。
只不过java线程状态有自己一套语法语义调度规则,和操作系统线程有点区别。创建一个java线程,也创建线程独享几个部分:PC寄存器、本地方法栈、Java线程栈。
java 方法调用
一个方法被调用就会在java线程栈上创建栈帧,栈帧里面有局部变量表,操作数栈、方法出口、动态链接等,根据字节码指令操作局部变量表、操作数栈。PC寄存器则指向下一条待执行指令的地址,可以是本地指针或方法区中相对应于该方法起始指令的偏移量。本地方法栈则是保存native方法进入区域的地址。PC寄存器、本地方法栈、Java线程栈共同保障了方法正常执行。
常用的class字节码指令比如,load指令是将局部变量表转载到操作数栈中,aload表示引用类型,java基本类型int是 iload float是fload等等。store指令是将栈顶值保存到局部变量表中,同样astore表示引用类型,java基本类型int是istore float是fstore等等。方法调用指令是invokespecial、invokevirtual等。方法返回指令是ireturn、areturn等。
class字节码指令解释参考https://www.cnblogs.com/longjee/p/8675771.html
方法调用JVM源码
main方法调用是上面java.c的CallStaticVoidMethod方法调用,以上的代码都是在jdk中,而CallStaticVoidMethod方法就调到了JVM代码。hotspot的src/share/vm/prims/jni.cpp中jni_CallStaticVoidMethod方法
jni_CallStaticVoidMethod再调jni_invoke_static方法
static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) {
methodHandle method(THREAD, Method::resolve_jmethod_id(method_id));
// Create object to hold arguments for the JavaCall, and associate it with
// the jni parser
ResourceMark rm(THREAD);
int number_of_parameters = method->size_of_parameters();
JavaCallArguments java_args(number_of_parameters);
args->set_java_argument_object(&java_args);
assert(method->is_static(), "method should be static");
// Fill out JavaCallArguments object
args->iterate( Fingerprinter(method).fingerprint() );
// Initialize result type
result->set_type(args->get_ret_type());
// Invoke the method. Result is returned as oop.
JavaCalls::call(result, method, &java_args, CHECK);
// Convert result
if (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY) {
result->set_jobject(JNIHandles::make_local(env, (oop) result->get_jobject()));
}
}
获取方法、参数然后调JavaCalls::call()
//hostspot /src/share/vm/runtime/javaCalls.cpp
void JavaCalls::call(JavaValue* result, methodHandle method, JavaCallArguments* args, TRAPS) {
// Check if we need to wrap a potential OS exception handler around thread
// This is used for e.g. Win32 structured exception handlers
assert(THREAD->is_Java_thread(), "only JavaThreads can make JavaCalls");
// Need to wrap each and everytime, since there might be native code down the
// stack that has installed its own exception handlers
os::os_exception_wrapper(call_helper, result, &method, args, THREAD);
}
void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArguments* args, TRAPS) {
methodHandle method = *m;
JavaThread* thread = (JavaThread*)THREAD;
assert(thread->is_Java_thread(), "must be called by a java thread");
assert(method.not_null(), "must have a method to call");
assert(!SafepointSynchronize::is_at_safepoint(), "call to Java code during VM operation");
assert(!thread->handle_area()->no_handle_mark_active(), "cannot call out to Java here");
CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();)
// Verify the arguments
if (CheckJNICalls) {
args->verify(method, result->get_type(), thread);
}
else debug_only(args->verify(method, result->get_type(), thread));
// Ignore call if method is empty
if (method->is_empty_method()) {
assert(result->get_type() == T_VOID, "an empty method must return a void value");
return;
}
#ifdef ASSERT
{ InstanceKlass* holder = method->method_holder();
// A klass might not be initialized since JavaCall's might be used during the executing of
// the <clinit>. For example, a Thread.start might start executing on an object that is
// not fully initialized! (bad Java programming style)
assert(holder->is_linked(), "rewritting must have taken place");
}
#endif
assert(!thread->is_Compiler_thread(), "cannot compile from the compiler");
if (CompilationPolicy::must_be_compiled(method)) {
CompileBroker::compile_method(method, InvocationEntryBci,
CompilationPolicy::policy()->initial_compile_level(),
methodHandle(), 0, "must_be_compiled", CHECK);
}
// Since the call stub sets up like the interpreter we call the from_interpreted_entry
// so we can go compiled via a i2c. Otherwise initial entry method will always
// run interpreted.
address entry_point = method->from_interpreted_entry();
if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) {
entry_point = method->interpreter_entry();
}
// Figure out if the result value is an oop or not (Note: This is a different value
// than result_type. result_type will be T_INT of oops. (it is about size)
BasicType result_type = runtime_type_from(result);
bool oop_result_flag = (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY);
// NOTE: if we move the computation of the result_val_address inside
// the call to call_stub, the optimizer produces wrong code.
intptr_t* result_val_address = (intptr_t*)(result->get_value_addr());
// Find receiver
Handle receiver = (!method->is_static()) ? args->receiver() : Handle();
// When we reenter Java, we need to reenable the yellow zone which
// might already be disabled when we are in VM.
if (thread->stack_yellow_zone_disabled()) {
thread->reguard_stack();
}
// Check that there are shadow pages available before changing thread state
// to Java
if (!os::stack_shadow_pages_available(THREAD, method)) {
// Throw stack overflow exception with preinitialized exception.
Exceptions::throw_stack_overflow_exception(THREAD, __FILE__, __LINE__, method);
return;
} else {
// Touch pages checked if the OS needs them to be touched to be mapped.
os::bang_stack_shadow_pages();
}
// do call
{ JavaCallWrapper link(method, receiver, result, CHECK);
{ HandleMark hm(thread); // HandleMark used by HandleMarkCleaner
StubRoutines::call_stub()(
(address)&link,
// (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
result_val_address, // see NOTE above (compiler problem)
result_type,
method(),
entry_point,
args->parameters(),
args->size_of_parameters(),
CHECK
);
result = link.result(); // circumvent MS C++ 5.0 compiler bug (result is clobbered across call)
// Preserve oop return value across possible gc points
if (oop_result_flag) {
thread->set_vm_result((oop) result->get_jobject());
}
}
} // Exit JavaCallWrapper (can block - potential return oop must be preserved)
// Check if a thread stop or suspend should be executed
// The following assert was not realistic. Thread.stop can set that bit at any moment.
//assert(!thread->has_special_runtime_exit_condition(), "no async. exceptions should be installed");
// Restore possible oop return
if (oop_result_flag) {
result->set_jobject((jobject)thread->vm_result());
thread->set_vm_result(NULL);
}
}
核心调用是 StubRoutines::call_stub()。通过指针调用目标函数,这个函数指针指向什么地方呢。这个在前面提到的创建JVM时其中一步init_globals方法,init.cpp中init_globals其中一步stubRoutines_init1();这个就是生成目标函数地址。这是和CPU架构有关的,因为为了加快执行速度直接操作寄存器,而32位与64位CPU的寄存器不一样。以X86-32为例,见subGenerator_x86_32.cpp,用汇编执行java方法。
address generate_call_stub(address& return_address) {
StubCodeMark mark(this, "StubRoutines", "call_stub");
address start = __ pc();
// stub code parameters / addresses
assert(frame::entry_frame_call_wrapper_offset == 2, "adjust this code");
bool sse_save = false;
const Address rsp_after_call(rbp, -4 * wordSize); // same as in generate_catch_exception()!
const int locals_count_in_bytes (4*wordSize);
const Address mxcsr_save (rbp, -4 * wordSize);
const Address saved_rbx (rbp, -3 * wordSize);
const Address saved_rsi (rbp, -2 * wordSize);
const Address saved_rdi (rbp, -1 * wordSize);
const Address result (rbp, 3 * wordSize);
const Address result_type (rbp, 4 * wordSize);
const Address method (rbp, 5 * wordSize);
const Address entry_point (rbp, 6 * wordSize);
const Address parameters (rbp, 7 * wordSize);
const Address parameter_size(rbp, 8 * wordSize);
const Address thread (rbp, 9 * wordSize); // same as in generate_catch_exception()!
sse_save = UseSSE > 0;
// stub code
__ enter();
__ movptr(rcx, parameter_size); // parameter counter
__ shlptr(rcx, Interpreter::logStackElementSize); // convert parameter count to bytes
__ addptr(rcx, locals_count_in_bytes); // reserve space for register saves
__ subptr(rsp, rcx);
__ andptr(rsp, -(StackAlignmentInBytes)); // Align stack
// save rdi, rsi, & rbx, according to C calling conventions
__ movptr(saved_rdi, rdi);
__ movptr(saved_rsi, rsi);
__ movptr(saved_rbx, rbx);
// save and initialize %mxcsr
if (sse_save) {
Label skip_ldmx;
__ stmxcsr(mxcsr_save);
__ movl(rax, mxcsr_save);
__ andl(rax, MXCSR_MASK); // Only check control and mask bits
ExternalAddress mxcsr_std(StubRoutines::addr_mxcsr_std());
__ cmp32(rax, mxcsr_std);
__ jcc(Assembler::equal, skip_ldmx);
__ ldmxcsr(mxcsr_std);
__ bind(skip_ldmx);
}
// make sure the control word is correct.
__ fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std()));
#ifdef ASSERT
// make sure we have no pending exceptions
{ Label L;
__ movptr(rcx, thread);
__ cmpptr(Address(rcx, Thread::pending_exception_offset()), (int32_t)NULL_WORD);
__ jcc(Assembler::equal, L);
__ stop("StubRoutines::call_stub: entered with pending exception");
__ bind(L);
}
#endif
// pass parameters if any
BLOCK_COMMENT("pass parameters if any");
Label parameters_done;
__ movl(rcx, parameter_size); // parameter counter
__ testl(rcx, rcx);
__ jcc(Assembler::zero, parameters_done);
// parameter passing loop
Label loop;
// Copy Java parameters in reverse order (receiver last)
// Note that the argument order is inverted in the process
// source is rdx[rcx: N-1..0]
// dest is rsp[rbx: 0..N-1]
__ movptr(rdx, parameters); // parameter pointer
__ xorptr(rbx, rbx);
__ BIND(loop);
// get parameter
__ movptr(rax, Address(rdx, rcx, Interpreter::stackElementScale(), -wordSize));
__ movptr(Address(rsp, rbx, Interpreter::stackElementScale(),
Interpreter::expr_offset_in_bytes(0)), rax); // store parameter
__ increment(rbx);
__ decrement(rcx);
__ jcc(Assembler::notZero, loop);
// call Java function
__ BIND(parameters_done);
__ movptr(rbx, method); // get Method*
__ movptr(rax, entry_point); // get entry_point
__ mov(rsi, rsp); // set sender sp
BLOCK_COMMENT("call Java function");
__ call(rax);
BLOCK_COMMENT("call_stub_return_address:");
return_address = __ pc();
#ifdef COMPILER2
{
Label L_skip;
if (UseSSE >= 2) {
__ verify_FPU(0, "call_stub_return");
} else {
for (int i = 1; i < 8; i++) {
__ ffree(i);
}
// UseSSE <= 1 so double result should be left on TOS
__ movl(rsi, result_type);
__ cmpl(rsi, T_DOUBLE);
__ jcc(Assembler::equal, L_skip);
if (UseSSE == 0) {
// UseSSE == 0 so float result should be left on TOS
__ cmpl(rsi, T_FLOAT);
__ jcc(Assembler::equal, L_skip);
}
__ ffree(0);
}
__ BIND(L_skip);
}
#endif // COMPILER2
// store result depending on type
// (everything that is not T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT)
__ movptr(rdi, result);
Label is_long, is_float, is_double, exit;
__ movl(rsi, result_type);
__ cmpl(rsi, T_LONG);
__ jcc(Assembler::equal, is_long);
__ cmpl(rsi, T_FLOAT);
__ jcc(Assembler::equal, is_float);
__ cmpl(rsi, T_DOUBLE);
__ jcc(Assembler::equal, is_double);
// handle T_INT case
__ movl(Address(rdi, 0), rax);
__ BIND(exit);
// check that FPU stack is empty
__ verify_FPU(0, "generate_call_stub");
// pop parameters
__ lea(rsp, rsp_after_call);
// restore %mxcsr
if (sse_save) {
__ ldmxcsr(mxcsr_save);
}
// restore rdi, rsi and rbx,
__ movptr(rbx, saved_rbx);
__ movptr(rsi, saved_rsi);
__ movptr(rdi, saved_rdi);
__ addptr(rsp, 4*wordSize);
// return
__ pop(rbp);
__ ret(0);
// handle return types different from T_INT
__ BIND(is_long);
__ movl(Address(rdi, 0 * wordSize), rax);
__ movl(Address(rdi, 1 * wordSize), rdx);
__ jmp(exit);
__ BIND(is_float);
// interpreter uses xmm0 for return values
if (UseSSE >= 1) {
__ movflt(Address(rdi, 0), xmm0);
} else {
__ fstp_s(Address(rdi, 0));
}
__ jmp(exit);
__ BIND(is_double);
// interpreter uses xmm0 for return values
if (UseSSE >= 2) {
__ movdbl(Address(rdi, 0), xmm0);
} else {
__ fstp_d(Address(rdi, 0));
}
__ jmp(exit);
return start;
}
java字节码执行
java代码经过javac.exe编译成class字节码,字节码进过java.exe解释执行,这个过程就是把java字节码中的指令逐步执行,实现由汇编和C++混合,与上面通过调用目标函数执行java方法不同,这里用的是字节码模板,也是创建JVM时初始化的,init.cpp中init_globals()方法一步interpreter_init()。
//hotspot src/share/vm/interpreter/interpreter.cpp
void interpreter_init() {
Interpreter::initialize();
...
}
//hotspot src/share/vm/interpreter/templateInterpreter.cpp
void TemplateInterpreter::initialize() {
if (_code != NULL) return;
// assertions
assert((int)Bytecodes::number_of_codes <= (int)DispatchTable::length,
"dispatch table too small");
AbstractInterpreter::initialize();
TemplateTable::initialize();
...
}
初始化了java指令模板
//hotspot /src/share/vm/interpreter/templateTable.cpp
void TemplateTable::initialize() {
if (_is_initialized) return;
// Initialize table
TraceTime timer("TemplateTable initialization", TraceStartupTime);
_bs = Universe::heap()->barrier_set();
// For better readability
const char _ = ' ';
const int ____ = 0;
const int ubcp = 1 << Template::uses_bcp_bit;
const int disp = 1 << Template::does_dispatch_bit;
const int clvm = 1 << Template::calls_vm_bit;
const int iswd = 1 << Template::wide_bit;
// interpr. templates
// Java spec bytecodes ubcp|disp|clvm|iswd in out generator argument
def(Bytecodes::_nop , ____|____|____|____, vtos, vtos, nop , _ );
def(Bytecodes::_aconst_null , ____|____|____|____, vtos, atos, aconst_null , _ );
def(Bytecodes::_iconst_m1 , ____|____|____|____, vtos, itos, iconst , -1 );
def(Bytecodes::_iconst_0 , ____|____|____|____, vtos, itos, iconst , 0 );
def(Bytecodes::_iconst_1 , ____|____|____|____, vtos, itos, iconst , 1 );
def(Bytecodes::_iconst_2 , ____|____|____|____, vtos, itos, iconst , 2 );
def(Bytecodes::_iconst_3 , ____|____|____|____, vtos, itos, iconst , 3 );
def(Bytecodes::_iconst_4 , ____|____|____|____, vtos, itos, iconst , 4 );
def(Bytecodes::_iconst_5 , ____|____|____|____, vtos, itos, iconst , 5 );
def(Bytecodes::_lconst_0 , ____|____|____|____, vtos, ltos, lconst , 0 );
def(Bytecodes::_lconst_1 , ____|____|____|____, vtos, ltos, lconst , 1 );
def(Bytecodes::_fconst_0 , ____|____|____|____, vtos, ftos, fconst , 0 );
def(Bytecodes::_fconst_1 , ____|____|____|____, vtos, ftos, fconst , 1 );
def(Bytecodes::_fconst_2 , ____|____|____|____, vtos, ftos, fconst , 2 );
def(Bytecodes::_dconst_0 , ____|____|____|____, vtos, dtos, dconst , 0 );
def(Bytecodes::_dconst_1 , ____|____|____|____, vtos, dtos, dconst , 1 );
def(Bytecodes::_bipush , ubcp|____|____|____, vtos, itos, bipush , _ );
def(Bytecodes::_sipush , ubcp|____|____|____, vtos, itos, sipush , _ );
def(Bytecodes::_ldc , ubcp|____|clvm|____, vtos, vtos, ldc , false );
def(Bytecodes::_ldc_w , ubcp|____|clvm|____, vtos, vtos, ldc , true );
def(Bytecodes::_ldc2_w , ubcp|____|____|____, vtos, vtos, ldc2_w , _ );
def(Bytecodes::_iload , ubcp|____|clvm|____, vtos, itos, iload , _ );
def(Bytecodes::_lload , ubcp|____|____|____, vtos, ltos, lload , _ );
def(Bytecodes::_fload , ubcp|____|____|____, vtos, ftos, fload , _ );
def(Bytecodes::_dload , ubcp|____|____|____, vtos, dtos, dload , _ );
def(Bytecodes::_aload , ubcp|____|clvm|____, vtos, atos, aload , _ );
def(Bytecodes::_iload_0 , ____|____|____|____, vtos, itos, iload , 0 );
def(Bytecodes::_iload_1 , ____|____|____|____, vtos, itos, iload , 1 );
def(Bytecodes::_iload_2 , ____|____|____|____, vtos, itos, iload , 2 );
def(Bytecodes::_iload_3 , ____|____|____|____, vtos, itos, iload , 3 );
def(Bytecodes::_lload_0 , ____|____|____|____, vtos, ltos, lload , 0 );
def(Bytecodes::_lload_1 , ____|____|____|____, vtos, ltos, lload , 1 );
def(Bytecodes::_lload_2 , ____|____|____|____, vtos, ltos, lload , 2 );
def(Bytecodes::_lload_3 , ____|____|____|____, vtos, ltos, lload , 3 );
def(Bytecodes::_fload_0 , ____|____|____|____, vtos, ftos, fload , 0 );
def(Bytecodes::_fload_1 , ____|____|____|____, vtos, ftos, fload , 1 );
def(Bytecodes::_fload_2 , ____|____|____|____, vtos, ftos, fload , 2 );
def(Bytecodes::_fload_3 , ____|____|____|____, vtos, ftos, fload , 3 );
def(Bytecodes::_dload_0 , ____|____|____|____, vtos, dtos, dload , 0 );
def(Bytecodes::_dload_1 , ____|____|____|____, vtos, dtos, dload , 1 );
def(Bytecodes::_dload_2 , ____|____|____|____, vtos, dtos, dload , 2 );
def(Bytecodes::_dload_3 , ____|____|____|____, vtos, dtos, dload , 3 );
def(Bytecodes::_aload_0 , ubcp|____|clvm|____, vtos, atos, aload_0 , _ );
def(Bytecodes::_aload_1 , ____|____|____|____, vtos, atos, aload , 1 );
def(Bytecodes::_aload_2 , ____|____|____|____, vtos, atos, aload , 2 );
def(Bytecodes::_aload_3 , ____|____|____|____, vtos, atos, aload , 3 );
def(Bytecodes::_iaload , ____|____|____|____, itos, itos, iaload , _ );
def(Bytecodes::_laload , ____|____|____|____, itos, ltos, laload , _ );
def(Bytecodes::_faload , ____|____|____|____, itos, ftos, faload , _ );
def(Bytecodes::_daload , ____|____|____|____, itos, dtos, daload , _ );
def(Bytecodes::_aaload , ____|____|____|____, itos, atos, aaload , _ );
def(Bytecodes::_baload , ____|____|____|____, itos, itos, baload , _ );
def(Bytecodes::_caload , ____|____|____|____, itos, itos, caload , _ );
def(Bytecodes::_saload , ____|____|____|____, itos, itos, saload , _ );
def(Bytecodes::_istore , ubcp|____|clvm|____, itos, vtos, istore , _ );
def(Bytecodes::_lstore , ubcp|____|____|____, ltos, vtos, lstore , _ );
def(Bytecodes::_fstore , ubcp|____|____|____, ftos, vtos, fstore , _ );
def(Bytecodes::_dstore , ubcp|____|____|____, dtos, vtos, dstore , _ );
def(Bytecodes::_astore , ubcp|____|clvm|____, vtos, vtos, astore , _ );
def(Bytecodes::_istore_0 , ____|____|____|____, itos, vtos, istore , 0 );
def(Bytecodes::_istore_1 , ____|____|____|____, itos, vtos, istore , 1 );
def(Bytecodes::_istore_2 , ____|____|____|____, itos, vtos, istore , 2 );
def(Bytecodes::_istore_3 , ____|____|____|____, itos, vtos, istore , 3 );
def(Bytecodes::_lstore_0 , ____|____|____|____, ltos, vtos, lstore , 0 );
def(Bytecodes::_lstore_1 , ____|____|____|____, ltos, vtos, lstore , 1 );
def(Bytecodes::_lstore_2 , ____|____|____|____, ltos, vtos, lstore , 2 );
def(Bytecodes::_lstore_3 , ____|____|____|____, ltos, vtos, lstore , 3 );
def(Bytecodes::_fstore_0 , ____|____|____|____, ftos, vtos, fstore , 0 );
def(Bytecodes::_fstore_1 , ____|____|____|____, ftos, vtos, fstore , 1 );
def(Bytecodes::_fstore_2 , ____|____|____|____, ftos, vtos, fstore , 2 );
def(Bytecodes::_fstore_3 , ____|____|____|____, ftos, vtos, fstore , 3 );
def(Bytecodes::_dstore_0 , ____|____|____|____, dtos, vtos, dstore , 0 );
def(Bytecodes::_dstore_1 , ____|____|____|____, dtos, vtos, dstore , 1 );
def(Bytecodes::_dstore_2 , ____|____|____|____, dtos, vtos, dstore , 2 );
def(Bytecodes::_dstore_3 , ____|____|____|____, dtos, vtos, dstore , 3 );
def(Bytecodes::_astore_0 , ____|____|____|____, vtos, vtos, astore , 0 );
def(Bytecodes::_astore_1 , ____|____|____|____, vtos, vtos, astore , 1 );
def(Bytecodes::_astore_2 , ____|____|____|____, vtos, vtos, astore , 2 );
def(Bytecodes::_astore_3 , ____|____|____|____, vtos, vtos, astore , 3 );
def(Bytecodes::_iastore , ____|____|____|____, itos, vtos, iastore , _ );
def(Bytecodes::_lastore , ____|____|____|____, ltos, vtos, lastore , _ );
def(Bytecodes::_fastore , ____|____|____|____, ftos, vtos, fastore , _ );
def(Bytecodes::_dastore , ____|____|____|____, dtos, vtos, dastore , _ );
def(Bytecodes::_aastore , ____|____|clvm|____, vtos, vtos, aastore , _ );
def(Bytecodes::_bastore , ____|____|____|____, itos, vtos, bastore , _ );
def(Bytecodes::_castore , ____|____|____|____, itos, vtos, castore , _ );
def(Bytecodes::_sastore , ____|____|____|____, itos, vtos, sastore , _ );
def(Bytecodes::_pop , ____|____|____|____, vtos, vtos, pop , _ );
def(Bytecodes::_pop2 , ____|____|____|____, vtos, vtos, pop2 , _ );
def(Bytecodes::_dup , ____|____|____|____, vtos, vtos, dup , _ );
def(Bytecodes::_dup_x1 , ____|____|____|____, vtos, vtos, dup_x1 , _ );
def(Bytecodes::_dup_x2 , ____|____|____|____, vtos, vtos, dup_x2 , _ );
def(Bytecodes::_dup2 , ____|____|____|____, vtos, vtos, dup2 , _ );
def(Bytecodes::_dup2_x1 , ____|____|____|____, vtos, vtos, dup2_x1 , _ );
def(Bytecodes::_dup2_x2 , ____|____|____|____, vtos, vtos, dup2_x2 , _ );
def(Bytecodes::_swap , ____|____|____|____, vtos, vtos, swap , _ );
def(Bytecodes::_iadd , ____|____|____|____, itos, itos, iop2 , add );
def(Bytecodes::_ladd , ____|____|____|____, ltos, ltos, lop2 , add );
def(Bytecodes::_fadd , ____|____|____|____, ftos, ftos, fop2 , add );
def(Bytecodes::_dadd , ____|____|____|____, dtos, dtos, dop2 , add );
def(Bytecodes::_isub , ____|____|____|____, itos, itos, iop2 , sub );
def(Bytecodes::_lsub , ____|____|____|____, ltos, ltos, lop2 , sub );
def(Bytecodes::_fsub , ____|____|____|____, ftos, ftos, fop2 , sub );
def(Bytecodes::_dsub , ____|____|____|____, dtos, dtos, dop2 , sub );
def(Bytecodes::_imul , ____|____|____|____, itos, itos, iop2 , mul );
def(Bytecodes::_lmul , ____|____|____|____, ltos, ltos, lmul , _ );
def(Bytecodes::_fmul , ____|____|____|____, ftos, ftos, fop2 , mul );
def(Bytecodes::_dmul , ____|____|____|____, dtos, dtos, dop2 , mul );
def(Bytecodes::_idiv , ____|____|____|____, itos, itos, idiv , _ );
def(Bytecodes::_ldiv , ____|____|____|____, ltos, ltos, ldiv , _ );
def(Bytecodes::_fdiv , ____|____|____|____, ftos, ftos, fop2 , div );
def(Bytecodes::_ddiv , ____|____|____|____, dtos, dtos, dop2 , div );
def(Bytecodes::_irem , ____|____|____|____, itos, itos, irem , _ );
def(Bytecodes::_lrem , ____|____|____|____, ltos, ltos, lrem , _ );
def(Bytecodes::_frem , ____|____|____|____, ftos, ftos, fop2 , rem );
def(Bytecodes::_drem , ____|____|____|____, dtos, dtos, dop2 , rem );
def(Bytecodes::_ineg , ____|____|____|____, itos, itos, ineg , _ );
def(Bytecodes::_lneg , ____|____|____|____, ltos, ltos, lneg , _ );
def(Bytecodes::_fneg , ____|____|____|____, ftos, ftos, fneg , _ );
def(Bytecodes::_dneg , ____|____|____|____, dtos, dtos, dneg , _ );
def(Bytecodes::_ishl , ____|____|____|____, itos, itos, iop2 , shl );
def(Bytecodes::_lshl , ____|____|____|____, itos, ltos, lshl , _ );
def(Bytecodes::_ishr , ____|____|____|____, itos, itos, iop2 , shr );
def(Bytecodes::_lshr , ____|____|____|____, itos, ltos, lshr , _ );
def(Bytecodes::_iushr , ____|____|____|____, itos, itos, iop2 , ushr );
def(Bytecodes::_lushr , ____|____|____|____, itos, ltos, lushr , _ );
def(Bytecodes::_iand , ____|____|____|____, itos, itos, iop2 , _and );
def(Bytecodes::_land , ____|____|____|____, ltos, ltos, lop2 , _and );
def(Bytecodes::_ior , ____|____|____|____, itos, itos, iop2 , _or );
def(Bytecodes::_lor , ____|____|____|____, ltos, ltos, lop2 , _or );
def(Bytecodes::_ixor , ____|____|____|____, itos, itos, iop2 , _xor );
def(Bytecodes::_lxor , ____|____|____|____, ltos, ltos, lop2 , _xor );
def(Bytecodes::_iinc , ubcp|____|clvm|____, vtos, vtos, iinc , _ );
def(Bytecodes::_i2l , ____|____|____|____, itos, ltos, convert , _ );
def(Bytecodes::_i2f , ____|____|____|____, itos, ftos, convert , _ );
def(Bytecodes::_i2d , ____|____|____|____, itos, dtos, convert , _ );
def(Bytecodes::_l2i , ____|____|____|____, ltos, itos, convert , _ );
def(Bytecodes::_l2f , ____|____|____|____, ltos, ftos, convert , _ );
def(Bytecodes::_l2d , ____|____|____|____, ltos, dtos, convert , _ );
def(Bytecodes::_f2i , ____|____|____|____, ftos, itos, convert , _ );
def(Bytecodes::_f2l , ____|____|____|____, ftos, ltos, convert , _ );
def(Bytecodes::_f2d , ____|____|____|____, ftos, dtos, convert , _ );
def(Bytecodes::_d2i , ____|____|____|____, dtos, itos, convert , _ );
def(Bytecodes::_d2l , ____|____|____|____, dtos, ltos, convert , _ );
def(Bytecodes::_d2f , ____|____|____|____, dtos, ftos, convert , _ );
def(Bytecodes::_i2b , ____|____|____|____, itos, itos, convert , _ );
def(Bytecodes::_i2c , ____|____|____|____, itos, itos, convert , _ );
def(Bytecodes::_i2s , ____|____|____|____, itos, itos, convert , _ );
def(Bytecodes::_lcmp , ____|____|____|____, ltos, itos, lcmp , _ );
def(Bytecodes::_fcmpl , ____|____|____|____, ftos, itos, float_cmp , -1 );
def(Bytecodes::_fcmpg , ____|____|____|____, ftos, itos, float_cmp , 1 );
def(Bytecodes::_dcmpl , ____|____|____|____, dtos, itos, double_cmp , -1 );
def(Bytecodes::_dcmpg , ____|____|____|____, dtos, itos, double_cmp , 1 );
def(Bytecodes::_ifeq , ubcp|____|clvm|____, itos, vtos, if_0cmp , equal );
def(Bytecodes::_ifne , ubcp|____|clvm|____, itos, vtos, if_0cmp , not_equal );
def(Bytecodes::_iflt , ubcp|____|clvm|____, itos, vtos, if_0cmp , less );
def(Bytecodes::_ifge , ubcp|____|clvm|____, itos, vtos, if_0cmp , greater_equal);
def(Bytecodes::_ifgt , ubcp|____|clvm|____, itos, vtos, if_0cmp , greater );
def(Bytecodes::_ifle , ubcp|____|clvm|____, itos, vtos, if_0cmp , less_equal );
def(Bytecodes::_if_icmpeq , ubcp|____|clvm|____, itos, vtos, if_icmp , equal );
def(Bytecodes::_if_icmpne , ubcp|____|clvm|____, itos, vtos, if_icmp , not_equal );
def(Bytecodes::_if_icmplt , ubcp|____|clvm|____, itos, vtos, if_icmp , less );
def(Bytecodes::_if_icmpge , ubcp|____|clvm|____, itos, vtos, if_icmp , greater_equal);
def(Bytecodes::_if_icmpgt , ubcp|____|clvm|____, itos, vtos, if_icmp , greater );
def(Bytecodes::_if_icmple , ubcp|____|clvm|____, itos, vtos, if_icmp , less_equal );
def(Bytecodes::_if_acmpeq , ubcp|____|clvm|____, atos, vtos, if_acmp , equal );
def(Bytecodes::_if_acmpne , ubcp|____|clvm|____, atos, vtos, if_acmp , not_equal );
def(Bytecodes::_goto , ubcp|disp|clvm|____, vtos, vtos, _goto , _ );
def(Bytecodes::_jsr , ubcp|disp|____|____, vtos, vtos, jsr , _ ); // result is not an oop, so do not transition to atos
def(Bytecodes::_ret , ubcp|disp|____|____, vtos, vtos, ret , _ );
def(Bytecodes::_tableswitch , ubcp|disp|____|____, itos, vtos, tableswitch , _ );
def(Bytecodes::_lookupswitch , ubcp|disp|____|____, itos, itos, lookupswitch , _ );
def(Bytecodes::_ireturn , ____|disp|clvm|____, itos, itos, _return , itos );
def(Bytecodes::_lreturn , ____|disp|clvm|____, ltos, ltos, _return , ltos );
def(Bytecodes::_freturn , ____|disp|clvm|____, ftos, ftos, _return , ftos );
def(Bytecodes::_dreturn , ____|disp|clvm|____, dtos, dtos, _return , dtos );
def(Bytecodes::_areturn , ____|disp|clvm|____, atos, atos, _return , atos );
def(Bytecodes::_return , ____|disp|clvm|____, vtos, vtos, _return , vtos );
def(Bytecodes::_getstatic , ubcp|____|clvm|____, vtos, vtos, getstatic , f1_byte );
def(Bytecodes::_putstatic , ubcp|____|clvm|____, vtos, vtos, putstatic , f2_byte );
def(Bytecodes::_getfield , ubcp|____|clvm|____, vtos, vtos, getfield , f1_byte );
def(Bytecodes::_putfield , ubcp|____|clvm|____, vtos, vtos, putfield , f2_byte );
def(Bytecodes::_invokevirtual , ubcp|disp|clvm|____, vtos, vtos, invokevirtual , f2_byte );
def(Bytecodes::_invokespecial , ubcp|disp|clvm|____, vtos, vtos, invokespecial , f1_byte );
def(Bytecodes::_invokestatic , ubcp|disp|clvm|____, vtos, vtos, invokestatic , f1_byte );
def(Bytecodes::_invokeinterface , ubcp|disp|clvm|____, vtos, vtos, invokeinterface , f1_byte );
def(Bytecodes::_invokedynamic , ubcp|disp|clvm|____, vtos, vtos, invokedynamic , f1_byte );
def(Bytecodes::_new , ubcp|____|clvm|____, vtos, atos, _new , _ );
def(Bytecodes::_newarray , ubcp|____|clvm|____, itos, atos, newarray , _ );
def(Bytecodes::_anewarray , ubcp|____|clvm|____, itos, atos, anewarray , _ );
def(Bytecodes::_arraylength , ____|____|____|____, atos, itos, arraylength , _ );
def(Bytecodes::_athrow , ____|disp|____|____, atos, vtos, athrow , _ );
def(Bytecodes::_checkcast , ubcp|____|clvm|____, atos, atos, checkcast , _ );
def(Bytecodes::_instanceof , ubcp|____|clvm|____, atos, itos, instanceof , _ );
def(Bytecodes::_monitorenter , ____|disp|clvm|____, atos, vtos, monitorenter , _ );
def(Bytecodes::_monitorexit , ____|____|clvm|____, atos, vtos, monitorexit , _ );
def(Bytecodes::_wide , ubcp|disp|____|____, vtos, vtos, wide , _ );
def(Bytecodes::_multianewarray , ubcp|____|clvm|____, vtos, atos, multianewarray , _ );
def(Bytecodes::_ifnull , ubcp|____|clvm|____, atos, vtos, if_nullcmp , equal );
def(Bytecodes::_ifnonnull , ubcp|____|clvm|____, atos, vtos, if_nullcmp , not_equal );
def(Bytecodes::_goto_w , ubcp|____|clvm|____, vtos, vtos, goto_w , _ );
def(Bytecodes::_jsr_w , ubcp|____|____|____, vtos, vtos, jsr_w , _ );
// wide Java spec bytecodes
def(Bytecodes::_iload , ubcp|____|____|iswd, vtos, itos, wide_iload , _ );
def(Bytecodes::_lload , ubcp|____|____|iswd, vtos, ltos, wide_lload , _ );
def(Bytecodes::_fload , ubcp|____|____|iswd, vtos, ftos, wide_fload , _ );
def(Bytecodes::_dload , ubcp|____|____|iswd, vtos, dtos, wide_dload , _ );
def(Bytecodes::_aload , ubcp|____|____|iswd, vtos, atos, wide_aload , _ );
def(Bytecodes::_istore , ubcp|____|____|iswd, vtos, vtos, wide_istore , _ );
def(Bytecodes::_lstore , ubcp|____|____|iswd, vtos, vtos, wide_lstore , _ );
def(Bytecodes::_fstore , ubcp|____|____|iswd, vtos, vtos, wide_fstore , _ );
def(Bytecodes::_dstore , ubcp|____|____|iswd, vtos, vtos, wide_dstore , _ );
def(Bytecodes::_astore , ubcp|____|____|iswd, vtos, vtos, wide_astore , _ );
def(Bytecodes::_iinc , ubcp|____|____|iswd, vtos, vtos, wide_iinc , _ );
def(Bytecodes::_ret , ubcp|disp|____|iswd, vtos, vtos, wide_ret , _ );
def(Bytecodes::_breakpoint , ubcp|disp|clvm|____, vtos, vtos, _breakpoint , _ );
// JVM bytecodes
def(Bytecodes::_fast_agetfield , ubcp|____|____|____, atos, atos, fast_accessfield , atos );
def(Bytecodes::_fast_bgetfield , ubcp|____|____|____, atos, itos, fast_accessfield , itos );
def(Bytecodes::_fast_cgetfield , ubcp|____|____|____, atos, itos, fast_accessfield , itos );
def(Bytecodes::_fast_dgetfield , ubcp|____|____|____, atos, dtos, fast_accessfield , dtos );
def(Bytecodes::_fast_fgetfield , ubcp|____|____|____, atos, ftos, fast_accessfield , ftos );
def(Bytecodes::_fast_igetfield , ubcp|____|____|____, atos, itos, fast_accessfield , itos );
def(Bytecodes::_fast_lgetfield , ubcp|____|____|____, atos, ltos, fast_accessfield , ltos );
def(Bytecodes::_fast_sgetfield , ubcp|____|____|____, atos, itos, fast_accessfield , itos );
def(Bytecodes::_fast_aputfield , ubcp|____|____|____, atos, vtos, fast_storefield , atos );
def(Bytecodes::_fast_bputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
def(Bytecodes::_fast_cputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
def(Bytecodes::_fast_dputfield , ubcp|____|____|____, dtos, vtos, fast_storefield , dtos );
def(Bytecodes::_fast_fputfield , ubcp|____|____|____, ftos, vtos, fast_storefield , ftos );
def(Bytecodes::_fast_iputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
def(Bytecodes::_fast_lputfield , ubcp|____|____|____, ltos, vtos, fast_storefield , ltos );
def(Bytecodes::_fast_sputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
def(Bytecodes::_fast_aload_0 , ____|____|____|____, vtos, atos, aload , 0 );
def(Bytecodes::_fast_iaccess_0 , ubcp|____|____|____, vtos, itos, fast_xaccess , itos );
def(Bytecodes::_fast_aaccess_0 , ubcp|____|____|____, vtos, atos, fast_xaccess , atos );
def(Bytecodes::_fast_faccess_0 , ubcp|____|____|____, vtos, ftos, fast_xaccess , ftos );
def(Bytecodes::_fast_iload , ubcp|____|____|____, vtos, itos, fast_iload , _ );
def(Bytecodes::_fast_iload2 , ubcp|____|____|____, vtos, itos, fast_iload2 , _ );
def(Bytecodes::_fast_icaload , ubcp|____|____|____, vtos, itos, fast_icaload , _ );
def(Bytecodes::_fast_invokevfinal , ubcp|disp|clvm|____, vtos, vtos, fast_invokevfinal , f2_byte );
def(Bytecodes::_fast_linearswitch , ubcp|disp|____|____, itos, vtos, fast_linearswitch , _ );
def(Bytecodes::_fast_binaryswitch , ubcp|disp|____|____, itos, vtos, fast_binaryswitch , _ );
def(Bytecodes::_fast_aldc , ubcp|____|clvm|____, vtos, atos, fast_aldc , false );
def(Bytecodes::_fast_aldc_w , ubcp|____|clvm|____, vtos, atos, fast_aldc , true );
def(Bytecodes::_return_register_finalizer , ____|disp|clvm|____, vtos, vtos, _return , vtos );
def(Bytecodes::_invokehandle , ubcp|disp|clvm|____, vtos, vtos, invokehandle , f1_byte );
def(Bytecodes::_shouldnotreachhere , ____|____|____|____, vtos, vtos, shouldnotreachhere , _ );
// platform specific bytecodes
pd_initialize();
_is_initialized = true;
}
我们看一个比较熟悉的java指令new,以x86_64为例
//hotspot src/cpu/x86/vm/templateTable_x86_64.cpp
void TemplateTable::_new() {
transition(vtos, atos);
__ get_unsigned_2_byte_index_at_bcp(rdx, 1);
Label slow_case;
Label done;
Label initialize_header;
Label initialize_object; // including clearing the fields
Label allocate_shared;
__ get_cpool_and_tags(rsi, rax);
// Make sure the class we're about to instantiate has been resolved.
// This is done before loading InstanceKlass to be consistent with the order
// how Constant Pool is updated (see ConstantPool::klass_at_put)
const int tags_offset = Array<u1>::base_offset_in_bytes();
__ cmpb(Address(rax, rdx, Address::times_1, tags_offset),
JVM_CONSTANT_Class);
__ jcc(Assembler::notEqual, slow_case);
// get InstanceKlass
__ movptr(rsi, Address(rsi, rdx,
Address::times_8, sizeof(ConstantPool)));
// make sure klass is initialized & doesn't have finalizer
// make sure klass is fully initialized
__ cmpb(Address(rsi,
InstanceKlass::init_state_offset()),
InstanceKlass::fully_initialized);
__ jcc(Assembler::notEqual, slow_case);
// get instance_size in InstanceKlass (scaled to a count of bytes)
__ movl(rdx,
Address(rsi,
Klass::layout_helper_offset()));
// test to see if it has a finalizer or is malformed in some way
__ testl(rdx, Klass::_lh_instance_slow_path_bit);
__ jcc(Assembler::notZero, slow_case);
// Allocate the instance
// 1) Try to allocate in the TLAB
// 2) if fail and the object is large allocate in the shared Eden
// 3) if the above fails (or is not applicable), go to a slow case
// (creates a new TLAB, etc.)
const bool allow_shared_alloc =
Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode;
if (UseTLAB) {
__ movptr(rax, Address(r15_thread, in_bytes(JavaThread::tlab_top_offset())));
__ lea(rbx, Address(rax, rdx, Address::times_1));
__ cmpptr(rbx, Address(r15_thread, in_bytes(JavaThread::tlab_end_offset())));
__ jcc(Assembler::above, allow_shared_alloc ? allocate_shared : slow_case);
__ movptr(Address(r15_thread, in_bytes(JavaThread::tlab_top_offset())), rbx);
if (ZeroTLAB) {
// the fields have been already cleared
__ jmp(initialize_header);
} else {
// initialize both the header and fields
__ jmp(initialize_object);
}
}
// Allocation in the shared Eden, if allowed.
//
// rdx: instance size in bytes
if (allow_shared_alloc) {
__ bind(allocate_shared);
ExternalAddress top((address)Universe::heap()->top_addr());
ExternalAddress end((address)Universe::heap()->end_addr());
const Register RtopAddr = rscratch1;
const Register RendAddr = rscratch2;
__ lea(RtopAddr, top);
__ lea(RendAddr, end);
__ movptr(rax, Address(RtopAddr, 0));
// For retries rax gets set by cmpxchgq
Label retry;
__ bind(retry);
__ lea(rbx, Address(rax, rdx, Address::times_1));
__ cmpptr(rbx, Address(RendAddr, 0));
__ jcc(Assembler::above, slow_case);
// Compare rax with the top addr, and if still equal, store the new
// top addr in rbx at the address of the top addr pointer. Sets ZF if was
// equal, and clears it otherwise. Use lock prefix for atomicity on MPs.
//
// rax: object begin
// rbx: object end
// rdx: instance size in bytes
if (os::is_MP()) {
__ lock();
}
__ cmpxchgptr(rbx, Address(RtopAddr, 0));
// if someone beat us on the allocation, try again, otherwise continue
__ jcc(Assembler::notEqual, retry);
__ incr_allocated_bytes(r15_thread, rdx, 0);
}
if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) {
// The object is initialized before the header. If the object size is
// zero, go directly to the header initialization.
__ bind(initialize_object);
__ decrementl(rdx, sizeof(oopDesc));
__ jcc(Assembler::zero, initialize_header);
// Initialize object fields
__ xorl(rcx, rcx); // use zero reg to clear memory (shorter code)
__ shrl(rdx, LogBytesPerLong); // divide by oopSize to simplify the loop
{
Label loop;
__ bind(loop);
__ movq(Address(rax, rdx, Address::times_8,
sizeof(oopDesc) - oopSize),
rcx);
__ decrementl(rdx);
__ jcc(Assembler::notZero, loop);
}
// initialize object header only.
__ bind(initialize_header);
if (UseBiasedLocking) {
__ movptr(rscratch1, Address(rsi, Klass::prototype_header_offset()));
__ movptr(Address(rax, oopDesc::mark_offset_in_bytes()), rscratch1);
} else {
__ movptr(Address(rax, oopDesc::mark_offset_in_bytes()),
(intptr_t) markOopDesc::prototype()); // header (address 0x1)
}
__ xorl(rcx, rcx); // use zero reg to clear memory (shorter code)
__ store_klass_gap(rax, rcx); // zero klass gap for compressed oops
__ store_klass(rax, rsi); // store klass last
{
SkipIfEqual skip(_masm, &DTraceAllocProbes, false);
// Trigger dtrace event for fastpath
__ push(atos); // save the return value
__ call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), rax);
__ pop(atos); // restore the return value
}
__ jmp(done);
}
// slow case
__ bind(slow_case);
__ get_constant_pool(c_rarg1);
__ get_unsigned_2_byte_index_at_bcp(c_rarg2, 1);
call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), c_rarg1, c_rarg2);
__ verify_oop(rax);
// continue
__ bind(done);
}
整过过程是判断是否快速创建对象(TLAB上分配内存),还是慢速分配(heap上分配,其实这里也判断是否支持快速分配),call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), c_rarg1, c_rarg2); 这里调用C++代码InterpreterRuntime.cpp分配内存,与前面都是一样最终调Universe::heap().mem_allocate()分配内存。
总结
我们的java代码的运行原理,也就是java解释执行javac编译后的字节码中的指令,用了汇编直接操作CPU寄存器以及调C++实现其他功能如分配内存等。而方法的执行也差不多,多了借助java线程栈。