java getaccessflags_Java类加载机制

1. 源文件

public class ClassLoadMechanism implements Serializable {

private static int STATE_NON_FINAL = 10;

private static final int STATIC_BASIC = 10;

private static final String STATIC_STR = "123";

private final int mLoading;

private final String mRef;

ClassLoadMechanism(int loading, String ref) {

this.mLoading = loading;

this.mRef = ref;

}

public void test() {

System.out.println("instance fun be called!");

}

public static void staticFun(int arg) {

System.out.println("static fun be called!");

}

}

2. 反编译源代码

javap -v -s -constants -p file:/classes/com/study/ClassLoadMechanism.class

2.1 反编译描述信息

Classfile /classes/com/yq/study/ClassLoadMechanism.class

Last modified Feb 27, 2021; size 1033 bytes

MD5 checksum ced3b2d1999f400f5d7aa04f536b72dc

Compiled from "ClassLoadMechanism.java"

2.2 类描述信息

public class com.yq.study.ClassLoadMechanism implements java.io.Serializable

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

2.3 常量池

Constant pool:

#1 = Methodref #10.#39 // java/lang/Object."":()V

#2 = Fieldref #9.#40 // com/yq/study/ClassLoadMechanism.mLoading:I

#3 = Fieldref #9.#41 // com/yq/study/ClassLoadMechanism.mRef:Ljava/lang/String;

#4 = Fieldref #42.#43 // java/lang/System.out:Ljava/io/PrintStream;

#5 = String #44 // instance fun be called!

#6 = Methodref #45.#46 // java/io/PrintStream.println:(Ljava/lang/String;)V

#7 = String #47 // static fun be called!

#8 = Fieldref #9.#48 // com/yq/study/ClassLoadMechanism.STATE_NON_FINAL:I

#9 = Class #49 // com/yq/study/ClassLoadMechanism

#10 = Class #50 // java/lang/Object

#11 = Class #51 // java/io/Serializable

#12 = Utf8 STATE_NON_FINAL

#13 = Utf8 I

#14 = Utf8 STATIC_BASIC

#15 = Utf8 ConstantValue

#16 = Integer 10

#17 = Utf8 STATIC_STR

#18 = Utf8 Ljava/lang/String;

#19 = String #52 // 123

#20 = Utf8 mLoading

#21 = Utf8 mRef

#22 = Utf8

#23 = Utf8 (ILjava/lang/String;)V

#24 = Utf8 Code

#25 = Utf8 LineNumberTable

#26 = Utf8 LocalVariableTable

#27 = Utf8 this

#28 = Utf8 Lcom/yq/study/ClassLoadMechanism;

#29 = Utf8 loading

#30 = Utf8 ref

#31 = Utf8 test

#32 = Utf8 ()V

#33 = Utf8 staticFun

#34 = Utf8 (I)V

#35 = Utf8 arg

#36 = Utf8

#37 = Utf8 SourceFile

#38 = Utf8 ClassLoadMechanism.java

#39 = NameAndType #22:#32 // "":()V

#40 = NameAndType #20:#13 // mLoading:I

#41 = NameAndType #21:#18 // mRef:Ljava/lang/String;

#42 = Class #53 // java/lang/System

#43 = NameAndType #54:#55 // out:Ljava/io/PrintStream;

#44 = Utf8 instance fun be called!

#45 = Class #56 // java/io/PrintStream

#46 = NameAndType #57:#58 // println:(Ljava/lang/String;)V

#47 = Utf8 static fun be called!

#48 = NameAndType #12:#13 // STATE_NON_FINAL:I

#49 = Utf8 com/yq/study/ClassLoadMechanism

#50 = Utf8 java/lang/Object

#51 = Utf8 java/io/Serializable

#52 = Utf8 123

#53 = Utf8 java/lang/System

#54 = Utf8 out

#55 = Utf8 Ljava/io/PrintStream;

#56 = Utf8 java/io/PrintStream

#57 = Utf8 println

#58 = Utf8 (Ljava/lang/String;)V

2.3 字段

private static int STATE_NON_FINAL;

descriptor: I

flags: ACC_PRIVATE, ACC_STATIC

private static final int STATIC_BASIC = 10;

descriptor: I

flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL

ConstantValue: int 10

private static final java.lang.String STATIC_STR = "123";

descriptor: Ljava/lang/String;

flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL

ConstantValue: String 123

private final int mLoading;

descriptor: I

flags: ACC_PRIVATE, ACC_FINAL

private final java.lang.String mRef;

descriptor: Ljava/lang/String;

flags: ACC_PRIVATE, ACC_FINAL

2.4 方法

com.yq.study.ClassLoadMechanism(int, java.lang.String);

descriptor: (ILjava/lang/String;)V

flags:

Code:

stack=2, locals=3, args_size=3

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: aload_0

5: iload_1

6: putfield #2 // Field mLoading:I

9: aload_0

10: aload_2

11: putfield #3 // Field mRef:Ljava/lang/String;

14: return

LineNumberTable:

line 16: 0

line 17: 4

line 18: 9

line 19: 14

LocalVariableTable:

Start Length Slot Name Signature

0 15 0 this Lcom/yq/study/ClassLoadMechanism;

0 15 1 loading I

0 15 2 ref Ljava/lang/String;

public void test();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc #5 // String instance fun be called!

5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

8: return

LineNumberTable:

line 22: 0

line 23: 8

LocalVariableTable:

Start Length Slot Name Signature

0 9 0 this Lcom/yq/study/ClassLoadMechanism;

public static void staticFun(int);

descriptor: (I)V

flags: ACC_PUBLIC, ACC_STATIC

Code:

stack=2, locals=1, args_size=1

0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc #7 // String static fun be called!

5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

8: return

LineNumberTable:

line 26: 0

line 27: 8

LocalVariableTable:

Start Length Slot Name Signature

0 9 0 arg I

static {};

descriptor: ()V

flags: ACC_STATIC

Code:

stack=1, locals=0, args_size=0

0: bipush 10

2: putstatic #8 // Field STATE_NON_FINAL:I

5: return

LineNumberTable:

line 9: 0

3. 虚拟机加载Class字节码面向对象设计

3.1 类封装

// C++ mirror of java.lang.Class

class MANAGED Class final : public Object {

private:

// Defining class loader, or null for the "bootstrap" system loader.

HeapReference class_loader_;

// DexCache of resolved constant pool entries

HeapReference dex_cache_;

// The interface table (iftable_) contains pairs of a interface class and an array of the

// interface methods.

HeapReference iftable_;

// Descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName

HeapReference name_;

// The superclass, or null if this is java.lang.Object or a primitive type.

HeapReference super_class_;

// Virtual method table (vtable)

HeapReference vtable_;

// instance fields

// ArtFields are allocated as a length prefixed ArtField array, and not an array of pointers to

// ArtFields.

uint64_t ifields_;

// Pointer to an ArtMethod length-prefixed array.

// where they are logically defined. This includes all private, static, final and virtual methods

uint64_t methods_;

// Static fields length-prefixed array.

uint64_t sfields_;

// Access flags; low 16 bits are defined by VM spec.

uint32_t access_flags_;

// Class flags to help speed up visiting object references.

uint32_t class_flags_;

// Total size of the Class instance; used when allocating storage on gc heap.

// See also object_size_.

uint32_t class_size_;

// Tid used to check for recursive invocation.

pid_t clinit_thread_id_;

static_assert(sizeof(pid_t) == sizeof(int32_t), "java.lang.Class.clinitThreadId size check");

// ClassDef index in dex file, -1 if no class definition such as an array.

// TODO: really 16bits

int32_t dex_class_def_idx_;

// Type index in dex file.

// TODO: really 16bits

int32_t dex_type_idx_;

// Number of instance fields that are object refs.

uint32_t num_reference_instance_fields_;

// Number of static fields that are object refs,

uint32_t num_reference_static_fields_;

// Total object size; used when allocating storage on gc heap.

// (For interfaces and abstract classes this will be zero.)

// See also class_size_.

uint32_t object_size_;

// Aligned object size for allocation fast path. The value is max uint32_t if the object is

// uninitialized or finalizable. Not currently used for variable sized objects.

uint32_t object_size_alloc_fast_path_;

// The lower 16 bits contains a Primitive::Type value. The upper 16

// bits contains the size shift of the primitive type.

uint32_t primitive_type_;

// Bitmap of offsets of ifields.

uint32_t reference_instance_offsets_;

// See the real definition in subtype_check_bits_and_status.h

// typeof(status_) is actually SubtypeCheckBitsAndStatus.

uint32_t status_;

// The offset of the first virtual method that is copied from an interface. This includes miranda,

// default, and default-conflict methods. Having a hard limit of ((2 << 16) - 1) for methods

// defined on a single class is well established in Java so we will use only uint16_t's here.

uint16_t copied_methods_offset_;

// The offset of the first declared virtual methods in the methods_ array.

uint16_t virtual_methods_offset_;

};

3.2 字段的封装

class ArtField final {

private:

GcRoot<:class> declaring_class_;

uint32_t access_flags_ = 0;

// Dex cache index of field id

uint32_t field_dex_idx_ = 0;

// Offset of field within an instance or in the Class' static fields

uint32_t offset_ = 0;

};

3.3 方法的封装

class ArtMethod final {

protected:

// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".

// The class we are a part of.

GcRoot<:class> declaring_class_;

// Access flags; low 16 bits are defined by spec.

// Getting and setting this flag needs to be atomic when concurrency is

// possible, e.g. after this method's class is linked. Such as when setting

// verifier flags and single-implementation flag.

std::atomic<:uint32_t> access_flags_;

/* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */

// Offset to the CodeItem.

uint32_t dex_code_item_offset_;

// Index into method_ids of the dex file associated with this method.

uint32_t dex_method_index_;

/* End of dex file fields. */

// Entry within a dispatch table for this method. For static/direct methods the index is into

// the declaringClass.directMethods, for virtual methods the vtable and for interface methods the

// ifTable.

uint16_t method_index_;

union {

// Non-abstract methods: The hotness we measure for this method. Not atomic,

// as we allow missing increments: if the method is hot, we will see it eventually.

uint16_t hotness_count_;

// Abstract methods: IMT index (bitwise negated) or zero if it was not cached.

// The negation is needed to distinguish zero index and missing cached entry.

uint16_t imt_index_;

};

// Fake padding field gets inserted here.

// Must be the last fields in the method.

struct PtrSizedFields {

// Depending on the method type, the data is

// - native method: pointer to the JNI function registered to this method

// or a function to resolve the JNI function,

// - conflict method: ImtConflictTable,

// - abstract/interface method: the single-implementation if any,

// - proxy method: the original interface method or constructor,

// - other methods: the profiling data.

void* data_;

// Method dispatch from quick compiled code invokes this pointer which may cause bridging into

// the interpreter.

void* entry_point_from_quick_compiled_code_;

} ptr_sized_fields_;

4. 虚拟机加载字节码

4.1 从Classpath里加载系统类

// Finds the class in the boot class loader.

// If the class is found the method returns the resolved class. Otherwise it returns null.

ObjPtr<:class> ClassLinker::FindClassInBootClassLoaderClassPath(Thread* self,

const char* descriptor,

size_t hash) {

ObjPtr<:class> result = nullptr;

ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);

if (pair.second != nullptr) {

ObjPtr<:class> klass = LookupClass(self, descriptor, hash, nullptr);

if (klass != nullptr) {

result = EnsureResolved(self, descriptor, klass);

} else {

result = DefineClass(self,

descriptor,

hash,

ScopedNullHandle<:classloader>(),

*pair.first,

*pair.second);

}

if (result == nullptr) {

CHECK(self->IsExceptionPending()) << descriptor;

FilterDexFileCaughtExceptions(self, this);

}

}

return result;

}

4.2 从Dex里加载

ObjPtr<:class> ClassLinker::FindClassInBaseDexClassLoaderClassPath(

ScopedObjectAccessAlreadyRunnable& soa,

const char* descriptor,

size_t hash,

Handle<:classloader> class_loader) {

DCHECK(IsPathOrDexClassLoader(soa, class_loader) ||

IsInMemoryDexClassLoader(soa, class_loader) ||

IsDelegateLastClassLoader(soa, class_loader))

<< "Unexpected class loader for descriptor " << descriptor;

ObjPtr<:class> ret;

auto define_class = [&](const DexFile* cp_dex_file) REQUIRES_SHARED(Locks::mutator_lock_) {

const dex::ClassDef* dex_class_def = OatDexFile::FindClassDef(*cp_dex_file, descriptor, hash);

if (dex_class_def != nullptr) {

ObjPtr<:class> klass = DefineClass(soa.Self(),

descriptor,

hash,

class_loader,

*cp_dex_file,

*dex_class_def);

if (klass == nullptr) {

CHECK(soa.Self()->IsExceptionPending()) << descriptor;

FilterDexFileCaughtExceptions(soa.Self(), this);

// TODO: Is it really right to break here, and not check the other dex files?

} else {

DCHECK(!soa.Self()->IsExceptionPending());

}

ret = klass;

return false; // Found a Class (or error == nullptr), stop visit.

}

return true; // Continue with the next DexFile.

};

VisitClassLoaderDexFiles(soa, class_loader, define_class);

return ret;

}

4.3 DefineClass方法

SetupClass

LoadClass

LoadSuperAndInterfaces

LinkClass

ObjPtr<:class> ClassLinker::DefineClass(Thread* self,

const char* descriptor,

size_t hash,

Handle<:classloader> class_loader,

const DexFile& dex_file,

const dex::ClassDef& dex_class_def) {

ScopedDefiningClass sdc(self);

StackHandleScope<3> hs(self);

auto klass = hs.NewHandle<:class>(nullptr);

// Load the class from the dex file.

if (UNLIKELY(!init_done_)) {

// finish up init of hand crafted class_roots_

if (strcmp(descriptor, "Ljava/lang/Object;") == 0) {

klass.Assign(GetClassRoot<:object>(this));

} else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) {

klass.Assign(GetClassRoot<:class>(this));

} else if (strcmp(descriptor, "Ljava/lang/String;") == 0) {

klass.Assign(GetClassRoot<:string>(this));

} else if (strcmp(descriptor, "Ljava/lang/ref/Reference;") == 0) {

klass.Assign(GetClassRoot<:reference>(this));

} else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) {

klass.Assign(GetClassRoot<:dexcache>(this));

} else if (strcmp(descriptor, "Ldalvik/system/ClassExt;") == 0) {

klass.Assign(GetClassRoot<:classext>(this));

}

}

// For AOT-compilation of an app, we may use a shortened boot class path that excludes

// some runtime modules. Prevent definition of classes in app class loader that could clash

// with these modules as these classes could be resolved differently during execution.

if (class_loader != nullptr &&

Runtime::Current()->IsAotCompiler() &&

IsUpdatableBootClassPathDescriptor(descriptor)) {

ObjPtr<:throwable> pre_allocated =

Runtime::Current()->GetPreAllocatedNoClassDefFoundError();

self->SetException(pre_allocated);

return sdc.Finish(nullptr);

}

// This is to prevent the calls to ClassLoad and ClassPrepare which can cause java/user-supplied

// code to be executed. We put it up here so we can avoid all the allocations associated with

// creating the class. This can happen with (eg) jit threads.

if (!self->CanLoadClasses()) {

// Make sure we don't try to load anything, potentially causing an infinite loop.

ObjPtr<:throwable> pre_allocated =

Runtime::Current()->GetPreAllocatedNoClassDefFoundError();

self->SetException(pre_allocated);

return sdc.Finish(nullptr);

}

if (klass == nullptr) {

// Allocate a class with the status of not ready.

// Interface object should get the right size here. Regular class will

// figure out the right size later and be replaced with one of the right

// size when the class becomes resolved.

if (CanAllocClass()) {

klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));

} else {

return sdc.Finish(nullptr);

}

}

if (UNLIKELY(klass == nullptr)) {

self->AssertPendingOOMException();

return sdc.Finish(nullptr);

}

// Get the real dex file. This will return the input if there aren't any callbacks or they do

// nothing.

DexFile const* new_dex_file = nullptr;

dex::ClassDef const* new_class_def = nullptr;

// TODO We should ideally figure out some way to move this after we get a lock on the klass so it

// will only be called once.

Runtime::Current()->GetRuntimeCallbacks()->ClassPreDefine(descriptor,

klass,

class_loader,

dex_file,

dex_class_def,

&new_dex_file,

&new_class_def);

// Check to see if an exception happened during runtime callbacks. Return if so.

if (self->IsExceptionPending()) {

return sdc.Finish(nullptr);

}

ObjPtr<:dexcache> dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get());

if (dex_cache == nullptr) {

self->AssertPendingException();

return sdc.Finish(nullptr);

}

// Note: 设置class.dex_cache属性(Resolve后ArtField/ArtMethod会保存到这里)

klass->SetDexCache(dex_cache);

// Note: SetupClass

SetupClass(*new_dex_file, *new_class_def, klass, class_loader.Get());

// Mark the string class by setting its access flag.

if (UNLIKELY(!init_done_)) {

if (strcmp(descriptor, "Ljava/lang/String;") == 0) {

klass->SetStringClass();

}

}

ObjectLock<:class> lock(self, klass);

klass->SetClinitThreadId(self->GetTid());

// Make sure we have a valid empty iftable even if there are errors.

klass->SetIfTable(GetClassRoot<:object>(this)->GetIfTable());

// Add the newly loaded class to the loaded classes table.

ObjPtr<:class> existing = InsertClass(descriptor, klass.Get(), hash);

if (existing != nullptr) {

// Note: We failed to insert because we raced with another thread. Calling EnsureResolved may cause

// this thread to block.

return sdc.Finish(EnsureResolved(self, descriptor, existing));

}

// Load the fields and other things after we are inserted in the table. This is so that we don't

// end up allocating unfree-able linear alloc resources and then lose the race condition. The

// other reason is that the field roots are only visited from the class table. So we need to be

// inserted before we allocate / fill in these fields.

// Note: LoadClass

LoadClass(self, *new_dex_file, *new_class_def, klass);

if (self->IsExceptionPending()) {

VLOG(class_linker) << self->GetException()->Dump();

// An exception occured during load, set status to erroneous while holding klass' lock in case

// notification is necessary.

if (!klass->IsErroneous()) {

mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);

}

return sdc.Finish(nullptr);

}

// Finish loading (if necessary) by finding parents

CHECK(!klass->IsLoaded());

// Note: LoadSuperAndInterfaces

if (!LoadSuperAndInterfaces(klass, *new_dex_file)) {

// Loading failed.

if (!klass->IsErroneous()) {

mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);

}

return sdc.Finish(nullptr);

}

CHECK(klass->IsLoaded());

// At this point the class is loaded. Publish a ClassLoad event.

// Note: this may be a temporary class. It is a listener's responsibility to handle this.

Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(klass);

// Link the class (if necessary)

CHECK(!klass->IsResolved());

// TODO: Use fast jobjects?

auto interfaces = hs.NewHandle<:objectarray>>(nullptr);

MutableHandle<:class> h_new_class = hs.NewHandle<:class>(nullptr);

// Note: LinkClass

if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) {

// Linking failed.

if (!klass->IsErroneous()) {

mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);

}

return sdc.Finish(nullptr);

}

self->AssertNoPendingException();

CHECK(h_new_class != nullptr) << descriptor;

CHECK(h_new_class->IsResolved() && !h_new_class->IsErroneousResolved()) << descriptor;

// Instrumentation may have updated entrypoints for all methods of all

// classes. However it could not update methods of this class while we

// were loading it. Now the class is resolved, we can update entrypoints

// as required by instrumentation.

if (Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()) {

// We must be in the kRunnable state to prevent instrumentation from

// suspending all threads to update entrypoints while we are doing it

// for this class.

DCHECK_EQ(self->GetState(), kRunnable);

Runtime::Current()->GetInstrumentation()->InstallStubsForClass(h_new_class.Get());

}

/*

* We send CLASS_PREPARE events to the debugger from here. The

* definition of "preparation" is creating the static fields for a

* class and initializing them to the standard default values, but not

* executing any code (that comes later, during "initialization").

*

* We did the static preparation in LinkClass.

*

* The class has been prepared and resolved but possibly not yet verified

* at this point.

*/

Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(klass, h_new_class);

// Notify native debugger of the new class and its layout.

jit::Jit::NewTypeLoadedIfUsingJit(h_new_class.Get());

return sdc.Finish(h_new_class);

}

4.3.1 LoadClass

访问者模式读取Class字节码

ArtField/ArtMethod分配内存并与Class的field/method关联

LinkCode

void ClassLinker::LoadClass(Thread* self,

const DexFile& dex_file,

const dex::ClassDef& dex_class_def,

Handle<:class> klass) {

ClassAccessor accessor(dex_file,

dex_class_def,

/* parse_hiddenapi_class_data= */ klass->IsBootStrapClassLoaded());

if (!accessor.HasClassData()) {

return;

}

Runtime* const runtime = Runtime::Current();

{

// Note: We cannot have thread suspension until the field and method arrays are setup or else

// Class::VisitFieldRoots may miss some fields or methods.

ScopedAssertNoThreadSuspension nts(__FUNCTION__);

// Load static fields.

// We allow duplicate definitions of the same field in a class_data_item

// but ignore the repeated indexes here, b/21868015.

LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader());

LengthPrefixedArray* sfields = AllocArtFieldArray(self,

allocator,

accessor.NumStaticFields());

LengthPrefixedArray* ifields = AllocArtFieldArray(self,

allocator,

accessor.NumInstanceFields());

size_t num_sfields = 0u;

size_t num_ifields = 0u;

uint32_t last_static_field_idx = 0u;

uint32_t last_instance_field_idx = 0u;

// Methods

bool has_oat_class = false;

const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler())

? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class)

: OatFile::OatClass::Invalid();

const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr;

klass->SetMethodsPtr(

AllocArtMethodArray(self, allocator, accessor.NumMethods()),

accessor.NumDirectMethods(),

accessor.NumVirtualMethods());

size_t class_def_method_index = 0;

uint32_t last_dex_method_index = dex::kDexNoIndex;

size_t last_class_def_method_index = 0;

// Use the visitor since the ranged based loops are bit slower from seeking. Seeking to the

// methods needs to decode all of the fields.

// Note: 访问类的所有的字段跟方法

accessor.VisitFieldsAndMethods([&](

const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {

uint32_t field_idx = field.GetIndex();

DCHECK_GE(field_idx, last_static_field_idx); // Ordering enforced by DexFileVerifier.

if (num_sfields == 0 || LIKELY(field_idx > last_static_field_idx)) {

// Note: 加载静态字段

LoadField(field, klass, &sfields->At(num_sfields));

++num_sfields;

last_static_field_idx = field_idx;

}

}, [&](const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {

uint32_t field_idx = field.GetIndex();

DCHECK_GE(field_idx, last_instance_field_idx); // Ordering enforced by DexFileVerifier.

if (num_ifields == 0 || LIKELY(field_idx > last_instance_field_idx)) {

// Note: 加载实例字段

LoadField(field, klass, &ifields->At(num_ifields));

++num_ifields;

last_instance_field_idx = field_idx;

}

}, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {

ArtMethod* art_method = klass->GetDirectMethodUnchecked(class_def_method_index,

image_pointer_size_);

LoadMethod(dex_file, method, klass, art_method);

LinkCode(this, art_method, oat_class_ptr, class_def_method_index);

uint32_t it_method_index = method.GetIndex();

if (last_dex_method_index == it_method_index) {

// duplicate case

art_method->SetMethodIndex(last_class_def_method_index);

} else {

art_method->SetMethodIndex(class_def_method_index);

last_dex_method_index = it_method_index;

last_class_def_method_index = class_def_method_index;

}

++class_def_method_index;

}, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {

ArtMethod* art_method = klass->GetVirtualMethodUnchecked(

class_def_method_index - accessor.NumDirectMethods(),

image_pointer_size_);

LoadMethod(dex_file, method, klass, art_method);

LinkCode(this, art_method, oat_class_ptr, class_def_method_index);

++class_def_method_index;

});

if (UNLIKELY(num_ifields + num_sfields != accessor.NumFields())) {

LOG(WARNING) << "Duplicate fields in class " << klass->PrettyDescriptor()

<< " (unique static fields: " << num_sfields << "/" << accessor.NumStaticFields()

<< ", unique instance fields: " << num_ifields << "/" << accessor.NumInstanceFields()

<< ")";

// NOTE: Not shrinking the over-allocated sfields/ifields, just setting size.

if (sfields != nullptr) {

sfields->SetSize(num_sfields);

}

if (ifields != nullptr) {

ifields->SetSize(num_ifields);

}

}

// Set the field arrays.

klass->SetSFieldsPtr(sfields);

DCHECK_EQ(klass->NumStaticFields(), num_sfields);

klass->SetIFieldsPtr(ifields);

DCHECK_EQ(klass->NumInstanceFields(), num_ifields);

}

// Ensure that the card is marked so that remembered sets pick up native roots.

WriteBarrier::ForEveryFieldWrite(klass.Get());

self->AllowThreadSuspension();

}

4.3.1.1 LoadField

设置该字段所属类

设置字段符号引用、访问权限

void ClassLinker::LoadField(const ClassAccessor::Field& field,

Handle<:class> klass,

ArtField* dst) {

const uint32_t field_idx = field.GetIndex();

dst->SetDexFieldIndex(field_idx);

dst->SetDeclaringClass(klass.Get());

// Get access flags from the DexFile and set hiddenapi runtime access flags.

dst->SetAccessFlags(field.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(field));

}

4.3.1.2 LoadMethod

设置方法所属的类

设置方法的访问权限、符号引用(method_idx)、

如果是finalize方法则给class设置SetFinalizable()

void ClassLinker::LoadMethod(const DexFile& dex_file,

const ClassAccessor::Method& method,

Handle<:class> klass,

ArtMethod* dst) {

const uint32_t dex_method_idx = method.GetIndex();

const dex::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);

const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);

ScopedAssertNoThreadSuspension ants("LoadMethod");

dst->SetDexMethodIndex(dex_method_idx);

dst->SetDeclaringClass(klass.Get());

dst->SetCodeItemOffset(method.GetCodeItemOffset());

// Get access flags from the DexFile and set hiddenapi runtime access flags.

uint32_t access_flags = method.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(method);

if (UNLIKELY(strcmp("finalize", method_name) == 0)) {

// Set finalizable flag on declaring class.

if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) {

// Void return type.

if (klass->GetClassLoader() != nullptr) { // All non-boot finalizer methods are flagged.

klass->SetFinalizable();

} else {

std::string temp;

const char* klass_descriptor = klass->GetDescriptor(&temp);

// The Enum class declares a "final" finalize() method to prevent subclasses from

// introducing a finalizer. We don't want to set the finalizable flag for Enum or its

// subclasses, so we exclude it here.

// We also want to avoid setting the flag on Object, where we know that finalize() is

// empty.

if (strcmp(klass_descriptor, "Ljava/lang/Object;") != 0 &&

strcmp(klass_descriptor, "Ljava/lang/Enum;") != 0) {

klass->SetFinalizable();

}

}

}

} else if (method_name[0] == '

// Fix broken access flags for initializers. Bug 11157540.

bool is_init = (strcmp("", method_name) == 0);

bool is_clinit = !is_init && (strcmp("", method_name) == 0);

if (UNLIKELY(!is_init && !is_clinit)) {

LOG(WARNING) << "Unexpected '

} else {

if (UNLIKELY((access_flags & kAccConstructor) == 0)) {

LOG(WARNING) << method_name << " didn't have expected constructor access flag in class "

<< klass->PrettyDescriptor() << " in dex file " << dex_file.GetLocation();

access_flags |= kAccConstructor;

}

}

}

if (UNLIKELY((access_flags & kAccNative) != 0u)) {

// Check if the native method is annotated with @FastNative or @CriticalNative.

access_flags |= annotations::GetNativeMethodAnnotationAccessFlags(

dex_file, dst->GetClassDef(), dex_method_idx);

}

dst->SetAccessFlags(access_flags);

// Must be done after SetAccessFlags since IsAbstract depends on it.

if (klass->IsInterface() && dst->IsAbstract()) {

dst->CalculateAndSetImtIndex();

}

}

4.3.1.3 LinkCode

ArtMethod设置quick_code(函数的入口地址)

static void LinkCode(ClassLinker* class_linker,

ArtMethod* method,

const OatFile::OatClass* oat_class,

uint32_t class_def_method_index) REQUIRES_SHARED(Locks::mutator_lock_) {

ScopedAssertNoThreadSuspension sants(__FUNCTION__);

Runtime* const runtime = Runtime::Current();

if (runtime->IsAotCompiler()) {

// The following code only applies to a non-compiler runtime.

return;

}

// Method shouldn't have already been linked.

DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);

if (!method->IsInvokable()) {

EnsureThrowsInvocationError(class_linker, method);

return;

}

const void* quick_code = nullptr;

if (oat_class != nullptr) {

// Every kind of method should at least get an invoke stub from the oat_method.

// non-abstract methods also get their code pointers.

const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index);

quick_code = oat_method.GetQuickCode();

}

bool enter_interpreter = class_linker->ShouldUseInterpreterEntrypoint(method, quick_code);

// Note: this mimics the logic in image_writer.cc that installs the resolution

// stub only if we have compiled code and the method needs a class initialization

// check.

if (quick_code == nullptr) {

method->SetEntryPointFromQuickCompiledCode(

method->IsNative() ? GetQuickGenericJniStub() : GetQuickToInterpreterBridge());

} else if (enter_interpreter) {

method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());

} else if (NeedsClinitCheckBeforeCall(method)) {

DCHECK(!method->GetDeclaringClass()->IsVisiblyInitialized()); // Actually ClassStatus::Idx.

// If we do have code but the method needs a class initialization check before calling

// that code, install the resolution stub that will perform the check.

// It will be replaced by the proper entry point by ClassLinker::FixupStaticTrampolines

// after initializing class (see ClassLinker::InitializeClass method).

method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());

} else {

method->SetEntryPointFromQuickCompiledCode(quick_code);

}

if (method->IsNative()) {

// Unregistering restores the dlsym lookup stub.

method->UnregisterNative();

if (enter_interpreter || quick_code == nullptr) {

// We have a native method here without code. Then it should have the generic JNI

// trampoline as entrypoint.

// TODO: this doesn't handle all the cases where trampolines may be installed.

DCHECK(class_linker->IsQuickGenericJniStub(method->GetEntryPointFromQuickCompiledCode()));

}

}

}

4.3.2 LinkClass

LinkSuperClass

LinkMethods

LinkInstanceFields

LinkStaticFields

bool ClassLinker::LinkClass(Thread* self,

const char* descriptor,

Handle<:class> klass,

Handle<:objectarray>> interfaces,

MutableHandle<:class>* h_new_class_out) {

CHECK_EQ(ClassStatus::kLoaded, klass->GetStatus());

if (!LinkSuperClass(klass)) {

return false;

}

ArtMethod* imt_data[ImTable::kSize];

// If there are any new conflicts compared to super class.

bool new_conflict = false;

std::fill_n(imt_data, arraysize(imt_data), Runtime::Current()->GetImtUnimplementedMethod());

if (!LinkMethods(self, klass, interfaces, &new_conflict, imt_data)) {

return false;

}

if (!LinkInstanceFields(self, klass)) {

return false;

}

size_t class_size;

if (!LinkStaticFields(self, klass, &class_size)) {

return false;

}

CreateReferenceInstanceOffsets(klass);

CHECK_EQ(ClassStatus::kLoaded, klass->GetStatus());

ImTable* imt = nullptr;

if (klass->ShouldHaveImt()) {

// If there are any new conflicts compared to the super class we can not make a copy. There

// can be cases where both will have a conflict method at the same slot without having the same

// set of conflicts. In this case, we can not share the IMT since the conflict table slow path

// will possibly create a table that is incorrect for either of the classes.

// Same IMT with new_conflict does not happen very often.

if (!new_conflict) {

ImTable* super_imt = FindSuperImt(klass.Get(), image_pointer_size_);

if (super_imt != nullptr) {

bool imt_equals = true;

for (size_t i = 0; i < ImTable::kSize && imt_equals; ++i) {

imt_equals = imt_equals && (super_imt->Get(i, image_pointer_size_) == imt_data[i]);

}

if (imt_equals) {

imt = super_imt;

}

}

}

if (imt == nullptr) {

LinearAlloc* allocator = GetAllocatorForClassLoader(klass->GetClassLoader());

imt = reinterpret_cast(

allocator->Alloc(self, ImTable::SizeInBytes(image_pointer_size_)));

if (imt == nullptr) {

return false;

}

imt->Populate(imt_data, image_pointer_size_);

}

}

if (!klass->IsTemp() || (!init_done_ && klass->GetClassSize() == class_size)) {

// We don't need to retire this class as it has no embedded tables or it was created the

// correct size during class linker initialization.

CHECK_EQ(klass->GetClassSize(), class_size) << klass->PrettyDescriptor();

if (klass->ShouldHaveEmbeddedVTable()) {

klass->PopulateEmbeddedVTable(image_pointer_size_);

}

if (klass->ShouldHaveImt()) {

klass->SetImt(imt, image_pointer_size_);

}

// Update CHA info based on whether we override methods.

// Have to do this before setting the class as resolved which allows

// instantiation of klass.

if (LIKELY(descriptor != nullptr) && cha_ != nullptr) {

cha_->UpdateAfterLoadingOf(klass);

}

// This will notify waiters on klass that saw the not yet resolved

// class in the class_table_ during EnsureResolved.

mirror::Class::SetStatus(klass, ClassStatus::kResolved, self);

h_new_class_out->Assign(klass.Get());

} else {

CHECK(!klass->IsResolved());

// Retire the temporary class and create the correctly sized resolved class.

StackHandleScope<1> hs(self);

Handle<:class> h_new_class =

hs.NewHandle(mirror::Class::CopyOf(klass, self, class_size, imt, image_pointer_size_));

// Set arrays to null since we don't want to have multiple classes with the same ArtField or

// ArtMethod array pointers. If this occurs, it causes bugs in remembered sets since the GC

// may not see any references to the target space and clean the card for a class if another

// class had the same array pointer.

klass->SetMethodsPtrUnchecked(nullptr, 0, 0);

klass->SetSFieldsPtrUnchecked(nullptr);

klass->SetIFieldsPtrUnchecked(nullptr);

if (UNLIKELY(h_new_class == nullptr)) {

self->AssertPendingOOMException();

mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);

return false;

}

CHECK_EQ(h_new_class->GetClassSize(), class_size);

ObjectLock<:class> lock(self, h_new_class);

FixupTemporaryDeclaringClass(klass.Get(), h_new_class.Get());

if (LIKELY(descriptor != nullptr)) {

WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);

const ObjPtr<:classloader> class_loader = h_new_class.Get()->GetClassLoader();

ClassTable* const table = InsertClassTableForClassLoader(class_loader);

const ObjPtr<:class> existing =

table->UpdateClass(descriptor, h_new_class.Get(), ComputeModifiedUtf8Hash(descriptor));

if (class_loader != nullptr) {

// We updated the class in the class table, perform the write barrier so that the GC knows

// about the change.

WriteBarrier::ForEveryFieldWrite(class_loader);

}

CHECK_EQ(existing, klass.Get());

if (log_new_roots_) {

new_class_roots_.push_back(GcRoot<:class>(h_new_class.Get()));

}

}

// Update CHA info based on whether we override methods.

// Have to do this before setting the class as resolved which allows

// instantiation of klass.

if (LIKELY(descriptor != nullptr) && cha_ != nullptr) {

cha_->UpdateAfterLoadingOf(h_new_class);

}

// This will notify waiters on temp class that saw the not yet resolved class in the

// class_table_ during EnsureResolved.

mirror::Class::SetStatus(klass, ClassStatus::kRetired, self);

CHECK_EQ(h_new_class->GetStatus(), ClassStatus::kResolving);

// This will notify waiters on new_class that saw the not yet resolved

// class in the class_table_ during EnsureResolved.

mirror::Class::SetStatus(h_new_class, ClassStatus::kResolved, self);

// Return the new class.

h_new_class_out->Assign(h_new_class.Get());

}

return true;

}

4.3.2.1 LinkSuperClass

父类语法校验(Object基类不可以有父类、父类访问权限、是否final等)

bool ClassLinker::LinkSuperClass(Handle<:class> klass) {

CHECK(!klass->IsPrimitive());

ObjPtr<:class> super = klass->GetSuperClass();

ObjPtr<:class> object_class = GetClassRoot<:object>(this);

if (klass.Get() == object_class) {

if (super != nullptr) {

ThrowClassFormatError(klass.Get(), "java.lang.Object must not have a superclass");

return false;

}

return true;

}

if (super == nullptr) {

ThrowLinkageError(klass.Get(), "No superclass defined for class %s",

klass->PrettyDescriptor().c_str());

return false;

}

// Verify

if (klass->IsInterface() && super != object_class) {

ThrowClassFormatError(klass.Get(), "Interfaces must have java.lang.Object as superclass");

return false;

}

if (super->IsFinal()) {

ThrowVerifyError(klass.Get(),

"Superclass %s of %s is declared final",

super->PrettyDescriptor().c_str(),

klass->PrettyDescriptor().c_str());

return false;

}

if (super->IsInterface()) {

ThrowIncompatibleClassChangeError(klass.Get(),

"Superclass %s of %s is an interface",

super->PrettyDescriptor().c_str(),

klass->PrettyDescriptor().c_str());

return false;

}

if (!klass->CanAccess(super)) {

ThrowIllegalAccessError(klass.Get(), "Superclass %s is inaccessible to class %s",

super->PrettyDescriptor().c_str(),

klass->PrettyDescriptor().c_str());

return false;

}

// Inherit kAccClassIsFinalizable from the superclass in case this

// class doesn't override finalize.

if (super->IsFinalizable()) {

klass->SetFinalizable();

}

// Inherit class loader flag form super class.

if (super->IsClassLoaderClass()) {

klass->SetClassLoaderClass();

}

// Inherit reference flags (if any) from the superclass.

uint32_t reference_flags = (super->GetClassFlags() & mirror::kClassFlagReference);

if (reference_flags != 0) {

CHECK_EQ(klass->GetClassFlags(), 0u);

klass->SetClassFlags(klass->GetClassFlags() | reference_flags);

}

// Disallow custom direct subclasses of java.lang.ref.Reference.

if (init_done_ && super == GetClassRoot<:reference>(this)) {

ThrowLinkageError(klass.Get(),

"Class %s attempts to subclass java.lang.ref.Reference, which is not allowed",

klass->PrettyDescriptor().c_str());

return false;

}

if (kIsDebugBuild) {

// Ensure super classes are fully resolved prior to resolving fields..

while (super != nullptr) {

CHECK(super->IsResolved());

super = super->GetSuperClass();

}

}

return true;

}

4.3.2.2 LinkMethods

SetupInterfaceLookupTable

LinkVirtualMethods (设置vtable)

LinkInterfaceMethods

bool ClassLinker::LinkMethods(Thread* self,

Handle<:class> klass,

Handle<:objectarray>> interfaces,

bool* out_new_conflict,

ArtMethod** out_imt) {

self->AllowThreadSuspension();

// A map from vtable indexes to the method they need to be updated to point to. Used because we

// need to have default methods be in the virtuals array of each class but we don't set that up

// until LinkInterfaceMethods.

std::unordered_map default_translations;

// Link virtual methods then interface methods.

// We set up the interface lookup table first because we need it to determine if we need to update

// any vtable entries with new default method implementations.

return SetupInterfaceLookupTable(self, klass, interfaces)

&& LinkVirtualMethods(self, klass, /*out*/ &default_translations)

&& LinkInterfaceMethods(self, klass, default_translations, out_new_conflict, out_imt);

}

4.3.2.3 LinkField

计算Static/Instance字段的MemberOffset

bool ClassLinker::LinkFields(Thread* self,

Handle<:class> klass,

bool is_static,

size_t* class_size) {

self->AllowThreadSuspension();

const size_t num_fields = is_static ? klass->NumStaticFields() : klass->NumInstanceFields();

LengthPrefixedArray* const fields = is_static ? klass->GetSFieldsPtr() :

klass->GetIFieldsPtr();

// Initialize field_offset

MemberOffset field_offset(0);

if (is_static) {

field_offset = klass->GetFirstReferenceStaticFieldOffsetDuringLinking(image_pointer_size_);

} else {

ObjPtr<:class> super_class = klass->GetSuperClass();

if (super_class != nullptr) {

CHECK(super_class->IsResolved())

<< klass->PrettyClass() << " " << super_class->PrettyClass();

field_offset = MemberOffset(super_class->GetObjectSize());

}

}

CHECK_EQ(num_fields == 0, fields == nullptr) << klass->PrettyClass();

// we want a relatively stable order so that adding new fields

// minimizes disruption of C++ version such as Class and Method.

//

// The overall sort order order is:

// 1) All object reference fields, sorted alphabetically.

// 2) All java long (64-bit) integer fields, sorted alphabetically.

// 3) All java double (64-bit) floating point fields, sorted alphabetically.

// 4) All java int (32-bit) integer fields, sorted alphabetically.

// 5) All java float (32-bit) floating point fields, sorted alphabetically.

// 6) All java char (16-bit) integer fields, sorted alphabetically.

// 7) All java short (16-bit) integer fields, sorted alphabetically.

// 8) All java boolean (8-bit) integer fields, sorted alphabetically.

// 9) All java byte (8-bit) integer fields, sorted alphabetically.

//

// Once the fields are sorted in this order we will attempt to fill any gaps that might be present

// in the memory layout of the structure. See ShuffleForward for how this is done.

std::deque grouped_and_sorted_fields;

const char* old_no_suspend_cause = self->StartAssertNoThreadSuspension(

"Naked ArtField references in deque");

for (size_t i = 0; i < num_fields; i++) {

grouped_and_sorted_fields.push_back(&fields->At(i));

}

std::sort(grouped_and_sorted_fields.begin(), grouped_and_sorted_fields.end(),

LinkFieldsComparator());

// References should be at the front.

size_t current_field = 0;

size_t num_reference_fields = 0;

FieldGaps gaps;

for (; current_field < num_fields; current_field++) {

ArtField* field = grouped_and_sorted_fields.front();

Primitive::Type type = field->GetTypeAsPrimitiveType();

bool isPrimitive = type != Primitive::kPrimNot;

if (isPrimitive) {

break; // past last reference, move on to the next phase

}

if (UNLIKELY(!IsAligned)>(

field_offset.Uint32Value()))) {

MemberOffset old_offset = field_offset;

field_offset = MemberOffset(RoundUp(field_offset.Uint32Value(), 4));

AddFieldGap(old_offset.Uint32Value(), field_offset.Uint32Value(), &gaps);

}

DCHECK_ALIGNED(field_offset.Uint32Value(), sizeof(mirror::HeapReference<:object>));

grouped_and_sorted_fields.pop_front();

num_reference_fields++;

field->SetOffset(field_offset);

field_offset = MemberOffset(field_offset.Uint32Value() +

sizeof(mirror::HeapReference<:object>));

}

// Gaps are stored as a max heap which means that we must shuffle from largest to smallest

// otherwise we could end up with suboptimal gap fills.

ShuffleForward<8>(&current_field, &field_offset, &grouped_and_sorted_fields, &gaps);

ShuffleForward<4>(&current_field, &field_offset, &grouped_and_sorted_fields, &gaps);

ShuffleForward<2>(&current_field, &field_offset, &grouped_and_sorted_fields, &gaps);

ShuffleForward<1>(&current_field, &field_offset, &grouped_and_sorted_fields, &gaps);

CHECK(grouped_and_sorted_fields.empty()) << "Missed " << grouped_and_sorted_fields.size() <<

" fields.";

self->EndAssertNoThreadSuspension(old_no_suspend_cause);

// We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it.

if (!is_static && klass->DescriptorEquals("Ljava/lang/ref/Reference;")) {

// We know there are no non-reference fields in the Reference classes, and we know

// that 'referent' is alphabetically last, so this is easy...

CHECK_EQ(num_reference_fields, num_fields) << klass->PrettyClass();

CHECK_STREQ(fields->At(num_fields - 1).GetName(), "referent")

<< klass->PrettyClass();

--num_reference_fields;

}

size_t size = field_offset.Uint32Value();

// Update klass

if (is_static) {

klass->SetNumReferenceStaticFields(num_reference_fields);

*class_size = size;

} else {

klass->SetNumReferenceInstanceFields(num_reference_fields);

ObjPtr<:class> super_class = klass->GetSuperClass();

if (num_reference_fields == 0 || super_class == nullptr) {

// object has one reference field, klass, but we ignore it since we always visit the class.

// super_class is null iff the class is java.lang.Object.

if (super_class == nullptr ||

(super_class->GetClassFlags() & mirror::kClassFlagNoReferenceFields) != 0) {

klass->SetClassFlags(klass->GetClassFlags() | mirror::kClassFlagNoReferenceFields);

}

}

if (kIsDebugBuild) {

DCHECK_EQ(super_class == nullptr, klass->DescriptorEquals("Ljava/lang/Object;"));

size_t total_reference_instance_fields = 0;

ObjPtr<:class> cur_super = klass.Get();

while (cur_super != nullptr) {

total_reference_instance_fields += cur_super->NumReferenceInstanceFieldsDuringLinking();

cur_super = cur_super->GetSuperClass();

}

if (super_class == nullptr) {

CHECK_EQ(total_reference_instance_fields, 1u) << klass->PrettyDescriptor();

} else {

// Check that there is at least num_reference_fields other than Object.class.

CHECK_GE(total_reference_instance_fields, 1u + num_reference_fields)

<< klass->PrettyClass();

}

}

if (!klass->IsVariableSize()) {

std::string temp;

DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor(&temp);

size_t previous_size = klass->GetObjectSize();

if (previous_size != 0) {

// Make sure that we didn't originally have an incorrect size.

CHECK_EQ(previous_size, size) << klass->GetDescriptor(&temp);

}

klass->SetObjectSize(size);

}

}

if (kIsDebugBuild) {

// Make sure that the fields array is ordered by name but all reference

// offsets are at the beginning as far as alignment allows.

MemberOffset start_ref_offset = is_static

? klass->GetFirstReferenceStaticFieldOffsetDuringLinking(image_pointer_size_)

: klass->GetFirstReferenceInstanceFieldOffset();

MemberOffset end_ref_offset(start_ref_offset.Uint32Value() +

num_reference_fields *

sizeof(mirror::HeapReference<:object>));

MemberOffset current_ref_offset = start_ref_offset;

for (size_t i = 0; i < num_fields; i++) {

ArtField* field = &fields->At(i);

VLOG(class_linker) << "LinkFields: " << (is_static ? "static" : "instance")

<< " class=" << klass->PrettyClass() << " field=" << field->PrettyField()

<< " offset=" << field->GetOffsetDuringLinking();

if (i != 0) {

ArtField* const prev_field = &fields->At(i - 1);

// NOTE: The field names can be the same. This is not possible in the Java language

// but it's valid Java/dex bytecode and for example proguard can generate such bytecode.

DCHECK_LE(strcmp(prev_field->GetName(), field->GetName()), 0);

}

Primitive::Type type = field->GetTypeAsPrimitiveType();

bool is_primitive = type != Primitive::kPrimNot;

if (klass->DescriptorEquals("Ljava/lang/ref/Reference;") &&

strcmp("referent", field->GetName()) == 0) {

is_primitive = true; // We lied above, so we have to expect a lie here.

}

MemberOffset offset = field->GetOffsetDuringLinking();

if (is_primitive) {

if (offset.Uint32Value() < end_ref_offset.Uint32Value()) {

// Shuffled before references.

size_t type_size = Primitive::ComponentSize(type);

CHECK_LT(type_size, sizeof(mirror::HeapReference<:object>));

CHECK_LT(offset.Uint32Value(), start_ref_offset.Uint32Value());

CHECK_LE(offset.Uint32Value() + type_size, start_ref_offset.Uint32Value());

CHECK(!IsAligned)>(offset.Uint32Value()));

}

} else {

CHECK_EQ(current_ref_offset.Uint32Value(), offset.Uint32Value());

current_ref_offset = MemberOffset(current_ref_offset.Uint32Value() +

sizeof(mirror::HeapReference<:object>));

}

}

CHECK_EQ(current_ref_offset.Uint32Value(), end_ref_offset.Uint32Value());

}

return true;

}

4 解析Resolve

符号引用转成直接引用的过程

ResolveType(Class)

ResolveArtField

ResolveArtMethod

4.1 ResolveType

type_idx转为Class

inline ObjPtr<:class> ClassLinker::ResolveType(dex::TypeIndex type_idx,

ObjPtr<:class> referrer) {

if (kObjPtrPoisoning) {

StackHandleScope<1> hs(Thread::Current());

HandleWrapperObjPtr<:class> referrer_wrapper = hs.NewHandleWrapper(&referrer);

Thread::Current()->PoisonObjectPointers();

}

DCHECK(!Thread::Current()->IsExceptionPending());

// We do not need the read barrier for getting the DexCache for the initial resolved type

// lookup as both from-space and to-space copies point to the same native resolved types array.

ObjPtr<:class> resolved_type =

referrer->GetDexCache()->GetResolvedType(type_idx);

if (resolved_type == nullptr) {

resolved_type = DoResolveType(type_idx, referrer);

}

return resolved_type;

}

4.2 ResolveMethod

template <:resolvemode kresolvemode>

inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,

uint32_t method_idx,

ArtMethod* referrer,

InvokeType type) {

DCHECK(referrer != nullptr);

// Note: The referrer can be a Proxy constructor. In that case, we need to do the

// lookup in the context of the original method from where it steals the code.

// However, we delay the GetInterfaceMethodIfProxy() until needed.

DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor());

Thread::PoisonObjectPointersIfDebug();

// We do not need the read barrier for getting the DexCache for the initial resolved method

// lookup as both from-space and to-space copies point to the same native resolved methods array.

ArtMethod* resolved_method = referrer->GetDexCache()->GetResolvedMethod(

method_idx, image_pointer_size_);

DCHECK(resolved_method == nullptr || !resolved_method->IsRuntimeMethod());

if (UNLIKELY(resolved_method == nullptr)) {

referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);

ObjPtr<:class> declaring_class = referrer->GetDeclaringClass();

StackHandleScope<2> hs(self);

Handle<:dexcache> h_dex_cache(hs.NewHandle(referrer->GetDexCache()));

Handle<:classloader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));

resolved_method = ResolveMethod(method_idx,

h_dex_cache,

h_class_loader,

referrer,

type);

} else if (kResolveMode == ResolveMode::kCheckICCEAndIAE) {

referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_);

// Check if the invoke type matches the class type.

ObjPtr<:dexcache> dex_cache = referrer->GetDexCache();

ObjPtr<:classloader> class_loader = referrer->GetClassLoader();

if (CheckInvokeClassMismatch* kThrow= */ true>(dex_cache, type, method_idx, class_loader)) {

DCHECK(Thread::Current()->IsExceptionPending());

return nullptr;

}

// Check access.

ObjPtr<:class> referring_class = referrer->GetDeclaringClass();

if (!referring_class->CheckResolvedMethodAccess(resolved_method->GetDeclaringClass(),

resolved_method,

dex_cache,

method_idx,

type)) {

DCHECK(Thread::Current()->IsExceptionPending());

return nullptr;

}

// Check if the invoke type matches the method type.

if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {

ThrowIncompatibleClassChangeError(type,

resolved_method->GetInvokeType(),

resolved_method,

referrer);

return nullptr;

}

}

// Note: We cannot check here to see whether we added the method to the cache. It

// might be an erroneous class, which results in it being hidden from us.

return resolved_method;

}

4.3 ResolvedField

inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,

ArtMethod* referrer,

bool is_static) {

Thread::PoisonObjectPointersIfDebug();

// We do not need the read barrier for getting the DexCache for the initial resolved field

// lookup as both from-space and to-space copies point to the same native resolved fields array.

ArtField* resolved_field = referrer->GetDexCache()->GetResolvedField(

field_idx, image_pointer_size_);

if (UNLIKELY(resolved_field == nullptr)) {

StackHandleScope<2> hs(Thread::Current());

ObjPtr<:class> referring_class = referrer->GetDeclaringClass();

Handle<:dexcache> dex_cache(hs.NewHandle(referrer->GetDexCache()));

Handle<:classloader> class_loader(hs.NewHandle(referring_class->GetClassLoader()));

resolved_field = ResolveField(field_idx, dex_cache, class_loader, is_static);

// Note: We cannot check here to see whether we added the field to the cache. The type

// might be an erroneous class, which results in it being hidden from us.

}

return resolved_field;

}

5. 类初始化(ClassLinker::InitializeClass)

(clinit)ArtMethod::Invoke

bool ClassLinker::InitializeClass(Thread* self,

Handle<:class> klass,

bool can_init_statics,

bool can_init_parents) {

// 去掉大部分的代码逻辑

if (!self->IsExceptionPending()) {

ArtMethod* clinit = klass->FindClassInitializer(image_pointer_size_);

if (clinit != nullptr) {

CHECK(can_init_statics);

JValue result;

clinit->Invoke(self, nullptr, 0, &result, "V");

}

}

...

return success;

}

5.1 ArtMethod::Invoke

void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,

const char* shorty) {

if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {

ThrowStackOverflowError(self);

return;

}

if (kIsDebugBuild) {

self->AssertThreadSuspensionIsAllowable();

CHECK_EQ(kRunnable, self->GetState());

CHECK_STREQ(GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(), shorty);

}

// Push a transition back into managed code onto the linked list in thread.

ManagedStack fragment;

self->PushManagedStackFragment(&fragment);

Runtime* runtime = Runtime::Current();

// Call the invoke stub, passing everything as arguments.

// If the runtime is not yet started or it is required by the debugger, then perform the

// Invocation by the interpreter, explicitly forcing interpretation over JIT to prevent

// cycling around the various JIT/Interpreter methods that handle method invocation.

if (UNLIKELY(!runtime->IsStarted() ||

(self->IsForceInterpreter() && !IsNative() && !IsProxyMethod() && IsInvokable()))) {

if (IsStatic()) {

art::interpreter::EnterInterpreterFromInvoke(

self, this, nullptr, args, result, /*stay_in_interpreter=*/ true);

} else {

mirror::Object* receiver =

reinterpret_cast*>(&args[0])->AsMirrorPtr();

art::interpreter::EnterInterpreterFromInvoke(

self, this, receiver, args + 1, result, /*stay_in_interpreter=*/ true);

}

} else {

DCHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);

constexpr bool kLogInvocationStartAndReturn = false;

bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr;

if (LIKELY(have_quick_code)) {

if (kLogInvocationStartAndReturn) {

LOG(INFO) << StringPrintf(

"Invoking '%s' quick code=%p static=%d", PrettyMethod().c_str(),

GetEntryPointFromQuickCompiledCode(), static_cast(IsStatic() ? 1 : 0));

}

// Ensure that we won't be accidentally calling quick compiled code when -Xint.

if (kIsDebugBuild && runtime->GetInstrumentation()->IsForcedInterpretOnly()) {

CHECK(!runtime->UseJitCompilation());

const void* oat_quick_code =

(IsNative() || !IsInvokable() || IsProxyMethod() || IsObsolete())

? nullptr

: GetOatMethodQuickCode(runtime->GetClassLinker()->GetImagePointerSize());

CHECK(oat_quick_code == nullptr || oat_quick_code != GetEntryPointFromQuickCompiledCode())

<< "Don't call compiled code when -Xint " << PrettyMethod();

}

if (!IsStatic()) {

(*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);

} else {

(*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty);

}

}

// Pop transition.

self->PopManagedStackFragment(fragment);

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值