diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/arch/arm/quick_entrypoints_arm.S | 4 | ||||
-rw-r--r-- | runtime/arch/arm64/quick_entrypoints_arm64.S | 4 | ||||
-rw-r--r-- | runtime/arch/mips/quick_entrypoints_mips.S | 7 | ||||
-rw-r--r-- | runtime/arch/mips64/quick_entrypoints_mips64.S | 6 | ||||
-rw-r--r-- | runtime/arch/x86/quick_entrypoints_x86.S | 5 | ||||
-rw-r--r-- | runtime/arch/x86_64/quick_entrypoints_x86_64.S | 5 | ||||
-rw-r--r-- | runtime/base/arena_allocator.cc | 1 | ||||
-rw-r--r-- | runtime/base/arena_allocator.h | 1 | ||||
-rw-r--r-- | runtime/class_linker.cc | 8 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_throw_entrypoints.cc | 18 | ||||
-rw-r--r-- | runtime/subtype_check.h | 21 |
11 files changed, 76 insertions, 4 deletions
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index 737d2a86a1..1671a243c9 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -794,6 +794,9 @@ END art_quick_unlock_object_no_inline .extern artInstanceOfFromCode .extern artThrowClassCastExceptionForObject ENTRY art_quick_check_instance_of + // Type check using the bit string passes null as the target class. In that case just throw. + cbz r1, .Lthrow_class_cast_exception_for_bitstring_check + push {r0-r2, lr} @ save arguments, padding (r2) and link register .cfi_adjust_cfa_offset 16 .cfi_rel_offset r0, 0 @@ -812,6 +815,7 @@ ENTRY art_quick_check_instance_of .cfi_restore r2 .cfi_restore lr +.Lthrow_class_cast_exception_for_bitstring_check: SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r2 @ save all registers as basis for long jump context mov r2, r9 @ pass Thread::Current bl artThrowClassCastExceptionForObject @ (Object*, Class*, Thread*) diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S index b0e7b0a964..06141184f6 100644 --- a/runtime/arch/arm64/quick_entrypoints_arm64.S +++ b/runtime/arch/arm64/quick_entrypoints_arm64.S @@ -1333,6 +1333,9 @@ END art_quick_unlock_object_no_inline .extern artInstanceOfFromCode .extern artThrowClassCastExceptionForObject ENTRY art_quick_check_instance_of + // Type check using the bit string passes null as the target class. In that case just throw. + cbz x1, .Lthrow_class_cast_exception_for_bitstring_check + // Store arguments and link register // Stack needs to be 16B aligned on calls. SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 32 @@ -1358,6 +1361,7 @@ ENTRY art_quick_check_instance_of // Restore RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 32 +.Lthrow_class_cast_exception_for_bitstring_check: SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context mov x2, xSELF // pass Thread::Current bl artThrowClassCastExceptionForObject // (Object*, Class*, Thread*) diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S index b2f7e10f52..d8fe480719 100644 --- a/runtime/arch/mips/quick_entrypoints_mips.S +++ b/runtime/arch/mips/quick_entrypoints_mips.S @@ -1423,6 +1423,10 @@ END art_quick_unlock_object_no_inline .extern artInstanceOfFromCode .extern artThrowClassCastExceptionForObject ENTRY art_quick_check_instance_of + // Type check using the bit string passes null as the target class. In that case just throw. + beqz $a1, .Lthrow_class_cast_exception_for_bitstring_check + nop + addiu $sp, $sp, -32 .cfi_adjust_cfa_offset 32 sw $gp, 16($sp) @@ -1441,12 +1445,15 @@ ENTRY art_quick_check_instance_of jalr $zero, $ra addiu $sp, $sp, 32 .cfi_adjust_cfa_offset -32 + .Lthrow_class_cast_exception: lw $t9, 8($sp) lw $a1, 4($sp) lw $a0, 0($sp) addiu $sp, $sp, 32 .cfi_adjust_cfa_offset -32 + +.Lthrow_class_cast_exception_for_bitstring_check: SETUP_SAVE_ALL_CALLEE_SAVES_FRAME la $t9, artThrowClassCastExceptionForObject jalr $zero, $t9 # artThrowClassCastException (Object*, Class*, Thread*) diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S index 63f4f6cb8c..a5edc1fc2d 100644 --- a/runtime/arch/mips64/quick_entrypoints_mips64.S +++ b/runtime/arch/mips64/quick_entrypoints_mips64.S @@ -1364,6 +1364,9 @@ END art_quick_unlock_object_no_inline .extern artInstanceOfFromCode .extern artThrowClassCastExceptionForObject ENTRY art_quick_check_instance_of + // Type check using the bit string passes null as the target class. In that case just throw. + beqzc $a1, .Lthrow_class_cast_exception_for_bitstring_check + daddiu $sp, $sp, -32 .cfi_adjust_cfa_offset 32 sd $ra, 24($sp) @@ -1379,12 +1382,15 @@ ENTRY art_quick_check_instance_of jalr $zero, $ra daddiu $sp, $sp, 32 .cfi_adjust_cfa_offset -32 + .Lthrow_class_cast_exception: ld $t9, 16($sp) ld $a1, 8($sp) ld $a0, 0($sp) daddiu $sp, $sp, 32 .cfi_adjust_cfa_offset -32 + +.Lthrow_class_cast_exception_for_bitstring_check: SETUP_GP SETUP_SAVE_ALL_CALLEE_SAVES_FRAME dla $t9, artThrowClassCastExceptionForObject diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index 5a28120b30..d64e2fd99f 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -1431,6 +1431,10 @@ DEFINE_FUNCTION art_quick_instance_of END_FUNCTION art_quick_instance_of DEFINE_FUNCTION art_quick_check_instance_of + // Type check using the bit string passes null as the target class. In that case just throw. + testl %ecx, %ecx + jz .Lthrow_class_cast_exception_for_bitstring_check + PUSH eax // alignment padding PUSH ecx // pass arg2 - checked class PUSH eax // pass arg1 - obj @@ -1448,6 +1452,7 @@ DEFINE_FUNCTION art_quick_check_instance_of addl LITERAL(4), %esp CFI_ADJUST_CFA_OFFSET(-4) +.Lthrow_class_cast_exception_for_bitstring_check: SETUP_SAVE_ALL_CALLEE_SAVES_FRAME ebx, ebx // save all registers as basis for long jump context // Outgoing argument set up PUSH eax // alignment padding diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S index 781ade99ce..81ad7806dd 100644 --- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S +++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S @@ -1402,6 +1402,10 @@ DEFINE_FUNCTION art_quick_unlock_object_no_inline END_FUNCTION art_quick_unlock_object_no_inline DEFINE_FUNCTION art_quick_check_instance_of + // Type check using the bit string passes null as the target class. In that case just throw. + testl %esi, %esi + jz .Lthrow_class_cast_exception_for_bitstring_check + // We could check the super classes here but that is usually already checked in the caller. PUSH rdi // Save args for exc PUSH rsi @@ -1425,6 +1429,7 @@ DEFINE_FUNCTION art_quick_check_instance_of POP rsi // Pop arguments POP rdi +.Lthrow_class_cast_exception_for_bitstring_check: SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context mov %gs:THREAD_SELF_OFFSET, %rdx // pass Thread::Current() call SYMBOL(artThrowClassCastExceptionForObject) // (Object* src, Class* dest, Thread*) diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc index cc413c5ab9..6b66173627 100644 --- a/runtime/base/arena_allocator.cc +++ b/runtime/base/arena_allocator.cc @@ -56,6 +56,7 @@ const char* const ArenaAllocatorStatsImpl<kCount>::kAllocNames[] = { "CtorFenceIns ", "InvokeInputs ", "PhiInputs ", + "TypeCheckIns ", "LoopInfo ", "LIBackEdges ", "TryCatchInf ", diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h index 9e03658aef..d720e977dd 100644 --- a/runtime/base/arena_allocator.h +++ b/runtime/base/arena_allocator.h @@ -62,6 +62,7 @@ enum ArenaAllocKind { kArenaAllocConstructorFenceInputs, kArenaAllocInvokeInputs, kArenaAllocPhiInputs, + kArenaAllocTypeCheckInputs, kArenaAllocLoopInfo, kArenaAllocLoopInfoBackEdges, kArenaAllocTryCatchInfo, diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index b61fb4afe9..fb4690235d 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4483,6 +4483,14 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(temp_klass, klass); + // SubtypeCheckInfo::Initialized must happen-before any new-instance for that type. + // See also ClassLinker::EnsureInitialized(). + { + MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_); + SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(klass.Get()); + // TODO: Avoid taking subtype_check_lock_ if SubtypeCheck for j.l.r.Proxy is already assigned. + } + { // Lock on klass is released. Lock new class object. ObjectLock<mirror::Class> initialization_lock(self, klass); diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc index 565b4edcc3..4b26beece3 100644 --- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc @@ -15,8 +15,11 @@ */ #include "callee_save_frame.h" +#include "dex/code_item_accessors-inl.h" +#include "dex/dex_instruction-inl.h" #include "common_throws.h" #include "mirror/object-inl.h" +#include "nth_caller_visitor.h" #include "thread.h" #include "well_known_classes.h" @@ -111,6 +114,21 @@ extern "C" NO_RETURN void artThrowClassCastException(mirror::Class* dest_type, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { ScopedQuickEntrypointChecks sqec(self); + if (dest_type == nullptr) { + // Find the target class for check cast using the bitstring check (dest_type == null). + NthCallerVisitor visitor(self, 0u); + visitor.WalkStack(); + DCHECK(visitor.caller != nullptr); + uint32_t dex_pc = visitor.GetDexPc(); + CodeItemDataAccessor accessor(visitor.caller); + const Instruction& check_cast = accessor.InstructionAt(dex_pc); + DCHECK_EQ(check_cast.Opcode(), Instruction::CHECK_CAST); + dex::TypeIndex type_index(check_cast.VRegB_21c()); + ClassLinker* linker = Runtime::Current()->GetClassLinker(); + dest_type = linker->LookupResolvedType(type_index, visitor.caller).Ptr(); + CHECK(dest_type != nullptr) << "Target class should have been previously resolved: " + << visitor.caller->GetDexFile()->PrettyType(type_index); + } DCHECK(!dest_type->IsAssignableFrom(src_type)); ThrowClassCastException(dest_type, src_type); self->QuickDeliverException(); diff --git a/runtime/subtype_check.h b/runtime/subtype_check.h index 54d2f00106..03a6d9caee 100644 --- a/runtime/subtype_check.h +++ b/runtime/subtype_check.h @@ -283,6 +283,17 @@ struct SubtypeCheck { return SubtypeCheckInfo::kUninitialized; } + // Retrieve the state of this class's SubtypeCheckInfo. + // + // Cost: O(Depth(Class)). + // + // Returns: The precise SubtypeCheckInfo::State. + static SubtypeCheckInfo::State GetState(ClassPtr klass) + REQUIRES(Locks::subtype_check_lock_) + REQUIRES_SHARED(Locks::mutator_lock_) { + return GetSubtypeCheckInfo(klass).GetState(); + } + // Retrieve the path to root bitstring as a plain uintN_t value that is amenable to // be used by a fast check "encoded_src & mask_target == encoded_target". // @@ -305,8 +316,9 @@ struct SubtypeCheck { static BitString::StorageType GetEncodedPathToRootForTarget(ClassPtr klass) REQUIRES(Locks::subtype_check_lock_) REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK_EQ(SubtypeCheckInfo::kAssigned, GetSubtypeCheckInfo(klass).GetState()); - return GetSubtypeCheckInfo(klass).GetEncodedPathToRoot(); + SubtypeCheckInfo sci = GetSubtypeCheckInfo(klass); + DCHECK_EQ(SubtypeCheckInfo::kAssigned, sci.GetState()); + return sci.GetEncodedPathToRoot(); } // Retrieve the path to root bitstring mask as a plain uintN_t value that is amenable to @@ -318,8 +330,9 @@ struct SubtypeCheck { static BitString::StorageType GetEncodedPathToRootMask(ClassPtr klass) REQUIRES(Locks::subtype_check_lock_) REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK_EQ(SubtypeCheckInfo::kAssigned, GetSubtypeCheckInfo(klass).GetState()); - return GetSubtypeCheckInfo(klass).GetEncodedPathToRootMask(); + SubtypeCheckInfo sci = GetSubtypeCheckInfo(klass); + DCHECK_EQ(SubtypeCheckInfo::kAssigned, sci.GetState()); + return sci.GetEncodedPathToRootMask(); } // Is the source class a subclass of the target? |