xref: /aosp_15_r20/art/runtime/entrypoints/quick/quick_throw_entrypoints.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2012 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "arch/context.h"
18*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
19*795d594fSAndroid Build Coastguard Worker #include "callee_save_frame.h"
20*795d594fSAndroid Build Coastguard Worker #include "dex/code_item_accessors-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction-inl.h"
22*795d594fSAndroid Build Coastguard Worker #include "common_throws.h"
23*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "nth_caller_visitor.h"
25*795d594fSAndroid Build Coastguard Worker #include "thread.h"
26*795d594fSAndroid Build Coastguard Worker #include "well_known_classes.h"
27*795d594fSAndroid Build Coastguard Worker 
28*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker // Deliver an exception that's pending on thread helping set up a callee save frame on the way.
artDeliverPendingExceptionFromCode(Thread * self)31*795d594fSAndroid Build Coastguard Worker extern "C" Context* artDeliverPendingExceptionFromCode(Thread* self)
32*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
33*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
34*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
35*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
36*795d594fSAndroid Build Coastguard Worker   return context.release();
37*795d594fSAndroid Build Coastguard Worker }
38*795d594fSAndroid Build Coastguard Worker 
artInvokeObsoleteMethod(ArtMethod * method,Thread * self)39*795d594fSAndroid Build Coastguard Worker extern "C" Context* artInvokeObsoleteMethod(ArtMethod* method, Thread* self)
40*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
41*795d594fSAndroid Build Coastguard Worker   DCHECK(method->IsObsolete());
42*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
43*795d594fSAndroid Build Coastguard Worker   ThrowInternalError("Attempting to invoke obsolete version of '%s'.",
44*795d594fSAndroid Build Coastguard Worker                      method->PrettyMethod().c_str());
45*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
46*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
47*795d594fSAndroid Build Coastguard Worker   return context.release();
48*795d594fSAndroid Build Coastguard Worker }
49*795d594fSAndroid Build Coastguard Worker 
50*795d594fSAndroid Build Coastguard Worker // Called by generated code to throw an exception.
artDeliverExceptionFromCode(mirror::Throwable * exception,Thread * self)51*795d594fSAndroid Build Coastguard Worker extern "C" Context* artDeliverExceptionFromCode(mirror::Throwable* exception, Thread* self)
52*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
53*795d594fSAndroid Build Coastguard Worker   /*
54*795d594fSAndroid Build Coastguard Worker    * exception may be null, in which case this routine should
55*795d594fSAndroid Build Coastguard Worker    * throw NPE.  NOTE: this is a convenience for generated code,
56*795d594fSAndroid Build Coastguard Worker    * which previously did the null check inline and constructed
57*795d594fSAndroid Build Coastguard Worker    * and threw a NPE if null.  This routine responsible for setting
58*795d594fSAndroid Build Coastguard Worker    * exception_ in thread and delivering the exception.
59*795d594fSAndroid Build Coastguard Worker    */
60*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
61*795d594fSAndroid Build Coastguard Worker   if (exception == nullptr) {
62*795d594fSAndroid Build Coastguard Worker     self->ThrowNewException("Ljava/lang/NullPointerException;", nullptr);
63*795d594fSAndroid Build Coastguard Worker   } else {
64*795d594fSAndroid Build Coastguard Worker     self->SetException(exception);
65*795d594fSAndroid Build Coastguard Worker   }
66*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
67*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
68*795d594fSAndroid Build Coastguard Worker   return context.release();
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker // Called by generated code to throw a NPE exception.
artThrowNullPointerExceptionFromCode(Thread * self)72*795d594fSAndroid Build Coastguard Worker extern "C" Context* artThrowNullPointerExceptionFromCode(Thread* self)
73*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
74*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
75*795d594fSAndroid Build Coastguard Worker   // We come from an explicit check in the generated code. This path is triggered
76*795d594fSAndroid Build Coastguard Worker   // only if the object is indeed null.
77*795d594fSAndroid Build Coastguard Worker   ThrowNullPointerExceptionFromDexPC(/* check_address= */ false, 0U);
78*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
79*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
80*795d594fSAndroid Build Coastguard Worker   return context.release();
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker 
83*795d594fSAndroid Build Coastguard Worker // Installed by a signal handler to throw a NPE exception.
artThrowNullPointerExceptionFromSignal(uintptr_t addr,Thread * self)84*795d594fSAndroid Build Coastguard Worker extern "C" Context* artThrowNullPointerExceptionFromSignal(uintptr_t addr, Thread* self)
85*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
86*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
87*795d594fSAndroid Build Coastguard Worker   ThrowNullPointerExceptionFromDexPC(/* check_address= */ true, addr);
88*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
89*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
90*795d594fSAndroid Build Coastguard Worker   return context.release();
91*795d594fSAndroid Build Coastguard Worker }
92*795d594fSAndroid Build Coastguard Worker 
93*795d594fSAndroid Build Coastguard Worker // Called by generated code to throw an arithmetic divide by zero exception.
artThrowDivZeroFromCode(Thread * self)94*795d594fSAndroid Build Coastguard Worker extern "C" Context* artThrowDivZeroFromCode(Thread* self)
95*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
96*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
97*795d594fSAndroid Build Coastguard Worker   ThrowArithmeticExceptionDivideByZero();
98*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
99*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
100*795d594fSAndroid Build Coastguard Worker   return context.release();
101*795d594fSAndroid Build Coastguard Worker }
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker // Called by generated code to throw an array index out of bounds exception.
artThrowArrayBoundsFromCode(int index,int length,Thread * self)104*795d594fSAndroid Build Coastguard Worker extern "C" Context* artThrowArrayBoundsFromCode(int index, int length, Thread* self)
105*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
106*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
107*795d594fSAndroid Build Coastguard Worker   ThrowArrayIndexOutOfBoundsException(index, length);
108*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
109*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
110*795d594fSAndroid Build Coastguard Worker   return context.release();
111*795d594fSAndroid Build Coastguard Worker }
112*795d594fSAndroid Build Coastguard Worker 
113*795d594fSAndroid Build Coastguard Worker // Called by generated code to throw a string index out of bounds exception.
artThrowStringBoundsFromCode(int index,int length,Thread * self)114*795d594fSAndroid Build Coastguard Worker extern "C" Context* artThrowStringBoundsFromCode(int index, int length, Thread* self)
115*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
116*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
117*795d594fSAndroid Build Coastguard Worker   ThrowStringIndexOutOfBoundsException(index, length);
118*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
119*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
120*795d594fSAndroid Build Coastguard Worker   return context.release();
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker 
artThrowStackOverflowFromCode(Thread * self)123*795d594fSAndroid Build Coastguard Worker extern "C" Context* artThrowStackOverflowFromCode(Thread* self)
124*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
125*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
126*795d594fSAndroid Build Coastguard Worker   // Throw a stack overflow error for the quick stack. This is needed to throw stack overflow
127*795d594fSAndroid Build Coastguard Worker   // errors on the simulated stack, which is used for quick code when building for the simulator.
128*795d594fSAndroid Build Coastguard Worker   // See kQuickStackType for more details.
129*795d594fSAndroid Build Coastguard Worker   ThrowStackOverflowError<kQuickStackType>(self);
130*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
131*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
132*795d594fSAndroid Build Coastguard Worker   return context.release();
133*795d594fSAndroid Build Coastguard Worker }
134*795d594fSAndroid Build Coastguard Worker 
artThrowClassCastException(mirror::Class * dest_type,mirror::Class * src_type,Thread * self)135*795d594fSAndroid Build Coastguard Worker extern "C" Context* artThrowClassCastException(mirror::Class* dest_type,
136*795d594fSAndroid Build Coastguard Worker                                                mirror::Class* src_type,
137*795d594fSAndroid Build Coastguard Worker                                                Thread* self)
138*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
139*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
140*795d594fSAndroid Build Coastguard Worker   if (dest_type == nullptr) {
141*795d594fSAndroid Build Coastguard Worker     // Find the target class for check cast using the bitstring check (dest_type == null).
142*795d594fSAndroid Build Coastguard Worker     NthCallerVisitor visitor(self, 0u);
143*795d594fSAndroid Build Coastguard Worker     visitor.WalkStack();
144*795d594fSAndroid Build Coastguard Worker     DCHECK(visitor.caller != nullptr);
145*795d594fSAndroid Build Coastguard Worker     uint32_t dex_pc = visitor.GetDexPc();
146*795d594fSAndroid Build Coastguard Worker     CodeItemDataAccessor accessor(*visitor.caller->GetDexFile(), visitor.caller->GetCodeItem());
147*795d594fSAndroid Build Coastguard Worker     const Instruction& check_cast = accessor.InstructionAt(dex_pc);
148*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(check_cast.Opcode(), Instruction::CHECK_CAST);
149*795d594fSAndroid Build Coastguard Worker     dex::TypeIndex type_index(check_cast.VRegB_21c());
150*795d594fSAndroid Build Coastguard Worker     ClassLinker* linker = Runtime::Current()->GetClassLinker();
151*795d594fSAndroid Build Coastguard Worker     dest_type = linker->LookupResolvedType(type_index, visitor.caller).Ptr();
152*795d594fSAndroid Build Coastguard Worker     CHECK(dest_type != nullptr) << "Target class should have been previously resolved: "
153*795d594fSAndroid Build Coastguard Worker         << visitor.caller->GetDexFile()->PrettyType(type_index);
154*795d594fSAndroid Build Coastguard Worker     CHECK(!dest_type->IsAssignableFrom(src_type))
155*795d594fSAndroid Build Coastguard Worker         << " " << std::hex << dest_type->PrettyDescriptor() << ";" << dest_type->Depth()
156*795d594fSAndroid Build Coastguard Worker         << "/" << dest_type->GetField32(mirror::Class::StatusOffset())
157*795d594fSAndroid Build Coastguard Worker         << " <: " << src_type->PrettyDescriptor() << ";" << src_type->Depth()
158*795d594fSAndroid Build Coastguard Worker         << "/" << src_type->GetField32(mirror::Class::StatusOffset());
159*795d594fSAndroid Build Coastguard Worker   }
160*795d594fSAndroid Build Coastguard Worker   DCHECK(!dest_type->IsAssignableFrom(src_type));
161*795d594fSAndroid Build Coastguard Worker   ThrowClassCastException(dest_type, src_type);
162*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
163*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
164*795d594fSAndroid Build Coastguard Worker   return context.release();
165*795d594fSAndroid Build Coastguard Worker }
166*795d594fSAndroid Build Coastguard Worker 
artThrowClassCastExceptionForObject(mirror::Object * obj,mirror::Class * dest_type,Thread * self)167*795d594fSAndroid Build Coastguard Worker extern "C" Context* artThrowClassCastExceptionForObject(mirror::Object* obj,
168*795d594fSAndroid Build Coastguard Worker                                                         mirror::Class* dest_type,
169*795d594fSAndroid Build Coastguard Worker                                                         Thread* self)
170*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
171*795d594fSAndroid Build Coastguard Worker   DCHECK(obj != nullptr);
172*795d594fSAndroid Build Coastguard Worker   return artThrowClassCastException(dest_type, obj->GetClass(), self);
173*795d594fSAndroid Build Coastguard Worker }
174*795d594fSAndroid Build Coastguard Worker 
artThrowArrayStoreException(mirror::Object * array,mirror::Object * value,Thread * self)175*795d594fSAndroid Build Coastguard Worker extern "C" Context* artThrowArrayStoreException(mirror::Object* array,
176*795d594fSAndroid Build Coastguard Worker                                                 mirror::Object* value,
177*795d594fSAndroid Build Coastguard Worker                                                 Thread* self)
178*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
179*795d594fSAndroid Build Coastguard Worker   ScopedQuickEntrypointChecks sqec(self);
180*795d594fSAndroid Build Coastguard Worker   ThrowArrayStoreException(value->GetClass(), array->GetClass());
181*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<Context> context = self->QuickDeliverException();
182*795d594fSAndroid Build Coastguard Worker   DCHECK(context != nullptr);
183*795d594fSAndroid Build Coastguard Worker   return context.release();
184*795d594fSAndroid Build Coastguard Worker }
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker }  // namespace art
187