// This method is being used by artQuickResolutionTrampoline, before it sets up // the passed parameters in a GC friendly way. Therefore we must never be // suspended while executing it.
ScopedAssertNoThreadSuspension sants(__FUNCTION__);
{
InlineInfo inline_info = inline_infos.back();
if (inline_info.EncodesArtMethod()) { return inline_info.GetArtMethod();
}
uint32_t method_index = code_info.GetMethodIndexOf(inline_info); if (inline_info.GetDexPc() == static_cast<uint32_t>(-1)) { // "charAt" special case. It is the only non-leaf method we inline across dex files.
ArtMethod* inlined_method = WellKnownClasses::java_lang_String_charAt;
DCHECK_EQ(inlined_method->GetDexMethodIndex(), method_index); return inlined_method;
}
}
ALWAYS_INLINE inline ObjPtr<mirror::Class> CheckClassInitializedForObjectAlloc(ObjPtr<mirror::Class> klass,
Thread* self, bool* slow_path)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_) { if (UNLIKELY(!klass->IsVisiblyInitialized())) {
StackHandleScope<1> hs(self);
Handle<mirror::Class> h_class(hs.NewHandle(klass)); // EnsureInitialized (the class initializer) might cause a GC. // may cause us to suspend meaning that another thread may try to // change the allocator while we are stuck in the entrypoints of // an old allocator. Also, the class initialization may fail. To // handle these cases we mark the slow path boolean as true so // that the caller knows to check the allocator type to see if it // has changed and to null-check the return value in case the // initialization fails.
*slow_path = true; if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
DCHECK(self->IsExceptionPending()); return nullptr; // Failure
} else {
DCHECK(!self->IsExceptionPending());
} return h_class.Get();
} return klass;
}
// Allocate an instance of klass. Throws InstantationError if klass is not instantiable, // or IllegalAccessError if klass is j.l.Class. Performs a clinit check too. template <bool kInstrumented>
ALWAYS_INLINE inline ObjPtr<mirror::Object> AllocObjectFromCode(ObjPtr<mirror::Class> klass,
Thread* self,
gc::AllocatorType allocator_type) { bool slow_path = false;
klass = CheckObjectAlloc(klass, self, &slow_path); if (UNLIKELY(slow_path)) { if (klass == nullptr) { return nullptr;
} // CheckObjectAlloc can cause thread suspension which means we may now be instrumented. return klass->Alloc</*kInstrumented=*/true>(
self,
Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
DCHECK(klass != nullptr); return klass->Alloc<kInstrumented>(self, allocator_type);
}
// Given the context of a calling Method and a resolved class, create an instance. template <bool kInstrumented>
ALWAYS_INLINE inline ObjPtr<mirror::Object> AllocObjectFromCodeResolved(ObjPtr<mirror::Class> klass,
Thread* self,
gc::AllocatorType allocator_type) {
DCHECK(klass != nullptr); bool slow_path = false;
klass = CheckClassInitializedForObjectAlloc(klass, self, &slow_path); if (UNLIKELY(slow_path)) { if (klass == nullptr) { return nullptr;
}
gc::Heap* heap = Runtime::Current()->GetHeap(); // Pass in kNoAddFinalizer since the object cannot be finalizable. // CheckClassInitializedForObjectAlloc can cause thread suspension which means we may now be // instrumented. return klass->Alloc</*kInstrumented=*/true, mirror::Class::AddFinalizer::kNoAddFinalizer>(
self, heap->GetCurrentAllocator());
} // Pass in kNoAddFinalizer since the object cannot be finalizable. return klass->Alloc<kInstrumented,
mirror::Class::AddFinalizer::kNoAddFinalizer>(self, allocator_type);
}
// Given the context of a calling Method and an initialized class, create an instance. template <bool kInstrumented>
ALWAYS_INLINE inline ObjPtr<mirror::Object> AllocObjectFromCodeInitialized(ObjPtr<mirror::Class> klass,
Thread* self,
gc::AllocatorType allocator_type) {
DCHECK(klass != nullptr); // Pass in kNoAddFinalizer since the object cannot be finalizable. return klass->Alloc<kInstrumented,
mirror::Class::AddFinalizer::kNoAddFinalizer>(self, allocator_type);
}
ALWAYS_INLINE inline ObjPtr<mirror::Class> CheckArrayAlloc(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method, bool* slow_path) { if (UNLIKELY(component_count < 0)) {
ThrowNegativeArraySizeException(component_count);
*slow_path = true; return nullptr; // Failure
}
ObjPtr<mirror::Class> klass = method->GetDexCache()->GetResolvedType(type_idx); if (UNLIKELY(klass == nullptr)) { // Not in dex cache so try to resolve
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
klass = class_linker->ResolveType(type_idx, method);
*slow_path = true; if (klass == nullptr) { // Error
DCHECK(Thread::Current()->IsExceptionPending()); return nullptr; // Failure
}
CHECK(klass->IsArrayClass()) << klass->PrettyClass();
} if (!method->SkipAccessChecks()) {
ObjPtr<mirror::Class> referrer = method->GetDeclaringClass(); if (UNLIKELY(!referrer->CanAccess(klass))) {
ThrowIllegalAccessErrorClass(referrer, klass);
*slow_path = true; return nullptr; // Failure
}
} return klass;
}
// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If // it cannot be resolved, throw an error. If it can, use it to create an array. // When verification/compiler hasn't been able to verify access, optionally perform an access // check. template <bool kInstrumented>
ALWAYS_INLINE inline ObjPtr<mirror::Array> AllocArrayFromCode(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
Thread* self,
gc::AllocatorType allocator_type) { bool slow_path = false;
ObjPtr<mirror::Class> klass = CheckArrayAlloc(type_idx, component_count, method, &slow_path); if (UNLIKELY(slow_path)) { if (klass == nullptr) { return nullptr;
}
gc::Heap* heap = Runtime::Current()->GetHeap(); // CheckArrayAlloc can cause thread suspension which means we may now be instrumented. return mirror::Array::Alloc</*kInstrumented=*/true>(self,
klass,
component_count,
klass->GetComponentSizeShift(),
heap->GetCurrentAllocator());
} return mirror::Array::Alloc<kInstrumented>(self,
klass,
component_count,
klass->GetComponentSizeShift(),
allocator_type);
}
template <bool kInstrumented>
ALWAYS_INLINE inline ObjPtr<mirror::Array> AllocArrayFromCodeResolved(ObjPtr<mirror::Class> klass,
int32_t component_count,
Thread* self,
gc::AllocatorType allocator_type) {
DCHECK(klass != nullptr); if (UNLIKELY(component_count < 0)) {
ThrowNegativeArraySizeException(component_count); return nullptr; // Failure
} // No need to retry a slow-path allocation as the above code won't cause a GC or thread // suspension. return mirror::Array::Alloc<kInstrumented>(self,
klass,
component_count,
klass->GetComponentSizeShift(),
allocator_type);
}
FLATTEN inline ArtField* ResolveFieldWithAccessChecks(Thread* self,
ClassLinker* class_linker,
uint16_t field_index,
ArtMethod* caller, bool is_static, bool is_put,
size_t resolve_field_type) // Resolve if not zero
REQUIRES_SHARED(Locks::mutator_lock_) { if (caller->SkipAccessChecks()) { return class_linker->ResolveField(field_index, caller, is_static);
}
staticinlinebool IsStringInit(const DexFile* dex_file, uint32_t method_idx)
REQUIRES_SHARED(Locks::mutator_lock_) { const dex::MethodId& method_id = dex_file->GetMethodId(method_idx); const std::string_view class_name = dex_file->GetTypeDescriptorView(method_id.class_idx_); const std::string_view method_name = dex_file->GetMethodNameView(method_id); // Instead of calling ResolveMethod() which has suspend point and can trigger // GC, look up the method symbolically. // Compare method's class name and method name against string init. // It's ok since it's not allowed to create your own java/lang/String. // TODO: verify that assumption. if (class_name == "Ljava/lang/String;" && method_name == "<init>") { returntrue;
} returnfalse;
}
// Try to find the method in thread-local cache.
size_t tls_value = 0u; if (!self->GetInterpreterCache()->Get(self, &inst, &tls_value)) { if (only_lookup_tls_cache) { return nullptr;
}
DCHECK(!self->IsExceptionPending()); // NterpGetMethod can suspend, so save this_object.
StackHandleScope<1> hs(self);
HandleWrapperObjPtr<mirror::Object> h_this(hs.NewHandleWrapper(this_object));
tls_value = NterpGetMethod(
self, caller, reinterpret_cast<const uint16_t*>(&inst), /* registers= */ nullptr); if (self->IsExceptionPending()) { return nullptr;
}
}
if (type != kStatic && UNLIKELY((*this_object) == nullptr)) { if (UNLIKELY(IsStringInit(inst, caller))) { // Hack for String init: // // We assume that the input of String.<init> in verified code is always // an uninitialized reference. If it is a null constant, it must have been // optimized out by the compiler and we arrive here after deoptimization. // Do not throw NullPointerException.
} else { // Maintain interpreter-like semantics where NullPointerException is thrown // after potential NoSuchMethodError from class linker. const uint32_t method_idx = inst.VRegB();
ThrowNullPointerExceptionForMethodAccess(method_idx, type); return nullptr;
}
}
template<bool access_check>
ALWAYS_INLINE ArtMethod* FindSuperMethodToCall(uint32_t method_idx,
ArtMethod* resolved_method,
ArtMethod* referrer,
Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) { // TODO This lookup is quite slow. // NB This is actually quite tricky to do any other way. We cannot use GetDeclaringClass since // that will actually not be what we want in some cases where there are miranda methods or // defaults. What we actually need is a GetContainingClass that says which classes virtuals // this method is coming from.
ClassLinker* linker = Runtime::Current()->GetClassLinker();
dex::TypeIndex type_idx = referrer->GetDexFile()->GetMethodId(method_idx).class_idx_;
ObjPtr<mirror::Class> referenced_class = linker->ResolveType(type_idx, referrer); if (UNLIKELY(referenced_class == nullptr)) {
DCHECK(self->IsExceptionPending()); return nullptr;
}
if (access_check) { if (!referenced_class->IsAssignableFrom(referrer->GetDeclaringClass())) {
ThrowNoSuchMethodError(kSuper,
resolved_method->GetDeclaringClass(),
resolved_method->GetName(),
resolved_method->GetSignature()); return nullptr;
}
}
if (referenced_class->IsInterface()) { if (!resolved_method->GetDeclaringClass()->IsInterface()) { // invoke-super from interface should not resolve to Object methods.
DCHECK(resolved_method->GetDeclaringClass()->IsObjectClass());
ThrowIncompatibleClassChangeError(
kSuper, resolved_method->GetInvokeType(), resolved_method, referrer); return nullptr;
} // TODO We can do better than this for a (compiled) fastpath.
ArtMethod* found_method = referenced_class->FindVirtualMethodForInterfaceSuper(
resolved_method, linker->GetImagePointerSize());
DCHECK(found_method != nullptr); return found_method;
}
inline ObjPtr<mirror::Object> GetGenericJniSynchronizationObject(Thread* self, ArtMethod* called)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(!called->IsCriticalNative());
DCHECK(!called->IsFastNative());
DCHECK(self->GetManagedStack()->GetTopQuickFrame() != nullptr);
DCHECK_EQ(*self->GetManagedStack()->GetTopQuickFrame(), called); // We do not need read barriers here. // On method entry, all reference arguments are to-space references and we mark the // declaring class of a static native method if needed. When visiting thread roots at // the start of a GC, we visit all these references to ensure they point to the to-space. if (called->IsStatic()) { // Static methods synchronize on the declaring class object. return called->GetDeclaringClass<kWithoutReadBarrier>();
} else { // Instance methods synchronize on the `this` object. // The `this` reference is stored in the first out vreg in the caller's frame.
uint8_t* sp = reinterpret_cast<uint8_t*>(self->GetManagedStack()->GetTopQuickFrame());
size_t frame_size = RuntimeCalleeSaveFrame::GetFrameSize(CalleeSaveType::kSaveRefsAndArgs);
StackReference<mirror::Object>* this_ref = reinterpret_cast<StackReference<mirror::Object>*>(
sp + frame_size + static_cast<size_t>(kRuntimePointerSize)); return this_ref->AsMirrorPtr();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.