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