##有请志愿者OtherClass.java
public class OtherClass {private static int CONSTANT_O=9876;public int o=1234;public void dddd(){String dddd = "dddd";System.out.println(dddd+CONSTANT_O);}}
类字节码
Classfile /home/yym/debug-java/OtherClass.classLast modified Oct. 28, 2024; size 973 bytesMD5 checksum 807f1e8fc3640c40a826bc5905a9ae6aCompiled from "OtherClass.java"
public class OtherClassminor version: 0major version: 55flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #8 // OtherClasssuper_class: #9 // java/lang/Objectinterfaces: 0, fields: 2, methods: 3, attributes: 3
Constant pool:#1 = Methodref #9.#21 // java/lang/Object."<init>":()V#2 = Fieldref #8.#22 // OtherClass.o:I#3 = String #17 // dddd#4 = Fieldref #23.#24 // java/lang/System.out:Ljava/io/PrintStream;#5 = Fieldref #8.#25 // OtherClass.CONSTANT_O:I#6 = InvokeDynamic #0:#29 // #0:makeConcatWithConstants:(Ljava/lang/String;I)Ljava/lang/String;#7 = Methodref #30.#31 // java/io/PrintStream.println:(Ljava/lang/String;)V#8 = Class #32 // OtherClass#9 = Class #33 // java/lang/Object#10 = Utf8 CONSTANT_O#11 = Utf8 I#12 = Utf8 o#13 = Utf8 <init>#14 = Utf8 ()V#15 = Utf8 Code#16 = Utf8 LineNumberTable#17 = Utf8 dddd#18 = Utf8 <clinit>#19 = Utf8 SourceFile#20 = Utf8 OtherClass.java#21 = NameAndType #13:#14 // "<init>":()V#22 = NameAndType #12:#11 // o:I#23 = Class #34 // java/lang/System#24 = NameAndType #35:#36 // out:Ljava/io/PrintStream;#25 = NameAndType #10:#11 // CONSTANT_O:I#26 = Utf8 BootstrapMethods#27 = MethodHandle 6:#37 // REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#28 = String #38 // \u0001\u0001#29 = NameAndType #39:#40 // makeConcatWithConstants:(Ljava/lang/String;I)Ljava/lang/String;#30 = Class #41 // java/io/PrintStream#31 = NameAndType #42:#43 // println:(Ljava/lang/String;)V#32 = Utf8 OtherClass#33 = Utf8 java/lang/Object#34 = Utf8 java/lang/System#35 = Utf8 out#36 = Utf8 Ljava/io/PrintStream;#37 = Methodref #44.#45 // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#38 = Utf8 \u0001\u0001#39 = Utf8 makeConcatWithConstants#40 = Utf8 (Ljava/lang/String;I)Ljava/lang/String;#41 = Utf8 java/io/PrintStream#42 = Utf8 println#43 = Utf8 (Ljava/lang/String;)V#44 = Class #46 // java/lang/invoke/StringConcatFactory#45 = NameAndType #39:#50 // makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#46 = Utf8 java/lang/invoke/StringConcatFactory#47 = Class #52 // java/lang/invoke/MethodHandles$Lookup#48 = Utf8 Lookup#49 = Utf8 InnerClasses#50 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#51 = Class #53 // java/lang/invoke/MethodHandles#52 = Utf8 java/lang/invoke/MethodHandles$Lookup#53 = Utf8 java/lang/invoke/MethodHandles
{public int o;descriptor: Iflags: (0x0001) ACC_PUBLICpublic OtherClass();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: sipush 12348: putfield #2 // Field o:I11: returnLineNumberTable:line 1: 0line 4: 4public void dddd();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=3, locals=2, args_size=10: ldc #3 // String dddd2: astore_13: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;6: aload_17: getstatic #5 // Field CONSTANT_O:I10: invokedynamic #6, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;I)Ljava/lang/String;15: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V18: returnLineNumberTable:line 8: 0line 9: 3line 10: 18static {};descriptor: ()Vflags: (0x0008) ACC_STATICCode:stack=1, locals=0, args_size=00: sipush 98763: putstatic #5 // Field CONSTANT_O:I6: returnLineNumberTable:line 3: 0
}
SourceFile: "OtherClass.java"
InnerClasses:public static final #48= #47 of #51; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:0: #27 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;Method arguments:#28 \u0001\u0001
##类静态变量初始化
// Make sure klass is initialized
klass->initialize(CHECK);
JRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* current, ConstantPool* pool, int index))Klass* k = pool->klass_at(index, CHECK);InstanceKlass* klass = InstanceKlass::cast(k);// Make sure we are not instantiating an abstract klassklass->check_valid_for_instantiation(true, CHECK);// Make sure klass is initializedklass->initialize(CHECK);// At this point the class may not be fully initialized// because of recursive initialization. If it is fully// initialized & has_finalized is not set, we rewrite// it into its fast version (Note: no locking is needed// here since this is an atomic byte write and can be// done more than once).//// Note: In case of classes with has_finalized we don't// rewrite since that saves us an extra check in// the fast version which then would call the// slow version anyway (and do a call back into// Java).// If we have a breakpoint, then we don't rewrite// because the _breakpoint bytecode would be lost.oop obj = klass->allocate_instance(CHECK);// std::cout << "@@@@yym%%%%obj address " << klass->name()->as_C_string() << obj << "----begin" << std::endl;current->set_vm_result(obj);
JRT_END
##void InstanceKlass::initialize_impl(TRAPS) 方法步骤8初始化静态
// Step 8{DTRACE_CLASSINIT_PROBE_WAIT(clinit, -1, wait);if (class_initializer() != NULL) {// Timer includes any side effects of class initialization (resolution,// etc), but not recursive entry into call_class_initializer().PerfClassTraceTime timer(ClassLoader::perf_class_init_time(),ClassLoader::perf_class_init_selftime(),ClassLoader::perf_classes_inited(),jt->get_thread_stat()->perf_recursion_counts_addr(),jt->get_thread_stat()->perf_timers_addr(),PerfClassTraceTime::CLASS_CLINIT);call_class_initializer(THREAD);} else {// The elapsed time is so small it's not worth counting.if (UsePerfData) {ClassLoader::perf_classes_inited()->inc();}call_class_initializer(THREAD);}}
##JavaCalls::call执行clinit 字节码,初始化静态变量
##clinit 方法
Method* InstanceKlass::class_initializer() const {Method* clinit = find_method(vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());if (clinit != NULL && clinit->has_valid_initializer_flags()) {return clinit;}return NULL;
}
##JavaCalls::call执行clinit 字节码
void InstanceKlass::call_class_initializer(TRAPS) {if (ReplayCompiles &&(ReplaySuppressInitializers == 1 ||(ReplaySuppressInitializers >= 2 && class_loader() != NULL))) {// Hide the existence of the initializer for the purpose of replaying the compilereturn;}methodHandle h_method(THREAD, class_initializer());assert(!is_initialized(), "we cannot initialize twice");LogTarget(Info, class, init) lt;if (lt.is_enabled()) {ResourceMark rm(THREAD);LogStream ls(lt);ls.print("%d Initializing ", call_class_initializer_counter++);name()->print_value_on(&ls);ls.print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", p2i(this));}if (h_method() != NULL) {JavaCallArguments args; // No argumentsJavaValue result(T_VOID);JavaCalls::call(&result, h_method, &args, CHECK); // Static call (no args)}
}
##执行putstatic字节码
// Fields
//void InterpreterRuntime::resolve_get_put(JavaThread* current, Bytecodes::Code bytecode) {// resolve fieldfieldDescriptor info;LastFrameAccessor last_frame(current);constantPoolHandle pool(current, last_frame.method()->constants());methodHandle m(current, last_frame.method());bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_nofast_putfield ||bytecode == Bytecodes::_putstatic);bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);{JvmtiHideSingleStepping jhss(current);JavaThread* THREAD = current; // For exception macros.LinkResolver::resolve_field_access(info, pool, last_frame.get_index_u2_cpcache(bytecode),m, bytecode, CHECK);} // end JvmtiHideSingleStepping// check if link resolution caused cpCache to be updatedConstantPoolCacheEntry* cp_cache_entry = last_frame.cache_entry();if (cp_cache_entry->is_resolved(bytecode)) return;// compute auxiliary field attributesTosState state = as_TosState(info.field_type());// Resolution of put instructions on final fields is delayed. That is required so that// exceptions are thrown at the correct place (when the instruction is actually invoked).// If we do not resolve an instruction in the current pass, leaving the put_code// set to zero will cause the next put instruction to the same field to reresolve.// Resolution of put instructions to final instance fields with invalid updates (i.e.,// to final instance fields with updates originating from a method different than <init>)// is inhibited. A putfield instruction targeting an instance final field must throw// an IllegalAccessError if the instruction is not in an instance// initializer method <init>. If resolution were not inhibited, a putfield// in an initializer method could be resolved in the initializer. Subsequent// putfield instructions to the same field would then use cached information.// As a result, those instructions would not pass through the VM. That is,// checks in resolve_field_access() would not be executed for those instructions// and the required IllegalAccessError would not be thrown.//// Also, we need to delay resolving getstatic and putstatic instructions until the// class is initialized. This is required so that access to the static// field will call the initialization function every time until the class// is completely initialized ala. in 2.17.5 in JVM Specification.InstanceKlass* klass = info.field_holder();bool uninitialized_static = is_static && !klass->is_initialized();bool has_initialized_final_update = info.field_holder()->major_version() >= 53 &&info.has_initialized_final_update();assert(!(has_initialized_final_update && !info.access_flags().is_final()), "Fields with initialized final updates must be final");Bytecodes::Code get_code = (Bytecodes::Code)0;Bytecodes::Code put_code = (Bytecodes::Code)0;if (!uninitialized_static) {get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield);if ((is_put && !has_initialized_final_update) || !info.access_flags().is_final()) {put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);}}// std::cout << "@@@@yym%%%%field" << info.name()->as_C_string() << ":offset:" << info.offset() << std::endl;cp_cache_entry->set_field(get_code,put_code,info.field_holder(),info.index(),info.offset(),state,info.access_flags().is_final(),info.access_flags().is_volatile());
}
##设置字段 cp_cache_entry->set_field
void ConstantPoolCacheEntry::set_field(Bytecodes::Code get_code,Bytecodes::Code put_code,Klass* field_holder,int field_index,int field_offset,TosState field_type,bool is_final,bool is_volatile) {set_f1(field_holder);set_f2(field_offset);assert((field_index & field_index_mask) == field_index,"field index does not fit in low flag bits");set_field_flags(field_type,((is_volatile ? 1 : 0) << is_volatile_shift) |((is_final ? 1 : 0) << is_final_shift),field_index);set_bytecode_1(get_code);set_bytecode_2(put_code);NOT_PRODUCT(verify(tty));
}