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 "art_method-inl.h"
18 #include "callee_save_frame.h"
19 #include "dex/code_item_accessors-inl.h"
20 #include "dex/dex_instruction-inl.h"
21 #include "common_throws.h"
22 #include "mirror/object-inl.h"
23 #include "nth_caller_visitor.h"
24 #include "thread.h"
25 #include "well_known_classes.h"
26 
27 namespace art {
28 
29 // Deliver an exception that's pending on thread helping set up a callee save frame on the way.
artDeliverPendingExceptionFromCode(Thread * self)30 extern "C" NO_RETURN void artDeliverPendingExceptionFromCode(Thread* self)
31     REQUIRES_SHARED(Locks::mutator_lock_) {
32   ScopedQuickEntrypointChecks sqec(self);
33   self->QuickDeliverException();
34 }
35 
artInvokeObsoleteMethod(ArtMethod * method,Thread * self)36 extern "C" NO_RETURN uint64_t artInvokeObsoleteMethod(ArtMethod* method, Thread* self)
37     REQUIRES_SHARED(Locks::mutator_lock_) {
38   DCHECK(method->IsObsolete());
39   ScopedQuickEntrypointChecks sqec(self);
40   ThrowInternalError("Attempting to invoke obsolete version of '%s'.",
41                      method->PrettyMethod().c_str());
42   self->QuickDeliverException();
43 }
44 
45 // Called by generated code to throw an exception.
artDeliverExceptionFromCode(mirror::Throwable * exception,Thread * self)46 extern "C" NO_RETURN void artDeliverExceptionFromCode(mirror::Throwable* exception, Thread* self)
47     REQUIRES_SHARED(Locks::mutator_lock_) {
48   /*
49    * exception may be null, in which case this routine should
50    * throw NPE.  NOTE: this is a convenience for generated code,
51    * which previously did the null check inline and constructed
52    * and threw a NPE if null.  This routine responsible for setting
53    * exception_ in thread and delivering the exception.
54    */
55   ScopedQuickEntrypointChecks sqec(self);
56   if (exception == nullptr) {
57     self->ThrowNewException("Ljava/lang/NullPointerException;", nullptr);
58   } else {
59     self->SetException(exception);
60   }
61   self->QuickDeliverException();
62 }
63 
64 // Called by generated code to throw a NPE exception.
artThrowNullPointerExceptionFromCode(Thread * self)65 extern "C" NO_RETURN void artThrowNullPointerExceptionFromCode(Thread* self)
66     REQUIRES_SHARED(Locks::mutator_lock_) {
67   ScopedQuickEntrypointChecks sqec(self);
68   // We come from an explicit check in the generated code. This path is triggered
69   // only if the object is indeed null.
70   ThrowNullPointerExceptionFromDexPC(/* check_address= */ false, 0U);
71   self->QuickDeliverException();
72 }
73 
74 // Installed by a signal handler to throw a NPE exception.
artThrowNullPointerExceptionFromSignal(uintptr_t addr,Thread * self)75 extern "C" NO_RETURN void artThrowNullPointerExceptionFromSignal(uintptr_t addr, Thread* self)
76     REQUIRES_SHARED(Locks::mutator_lock_) {
77   ScopedQuickEntrypointChecks sqec(self);
78   ThrowNullPointerExceptionFromDexPC(/* check_address= */ true, addr);
79   self->QuickDeliverException();
80 }
81 
82 // Called by generated code to throw an arithmetic divide by zero exception.
artThrowDivZeroFromCode(Thread * self)83 extern "C" NO_RETURN void artThrowDivZeroFromCode(Thread* self)
84     REQUIRES_SHARED(Locks::mutator_lock_) {
85   ScopedQuickEntrypointChecks sqec(self);
86   ThrowArithmeticExceptionDivideByZero();
87   self->QuickDeliverException();
88 }
89 
90 // Called by generated code to throw an array index out of bounds exception.
artThrowArrayBoundsFromCode(int index,int length,Thread * self)91 extern "C" NO_RETURN void artThrowArrayBoundsFromCode(int index, int length, Thread* self)
92     REQUIRES_SHARED(Locks::mutator_lock_) {
93   ScopedQuickEntrypointChecks sqec(self);
94   ThrowArrayIndexOutOfBoundsException(index, length);
95   self->QuickDeliverException();
96 }
97 
98 // Called by generated code to throw a string index out of bounds exception.
artThrowStringBoundsFromCode(int index,int length,Thread * self)99 extern "C" NO_RETURN void artThrowStringBoundsFromCode(int index, int length, Thread* self)
100     REQUIRES_SHARED(Locks::mutator_lock_) {
101   ScopedQuickEntrypointChecks sqec(self);
102   ThrowStringIndexOutOfBoundsException(index, length);
103   self->QuickDeliverException();
104 }
105 
artThrowStackOverflowFromCode(Thread * self)106 extern "C" NO_RETURN void artThrowStackOverflowFromCode(Thread* self)
107     REQUIRES_SHARED(Locks::mutator_lock_) {
108   ScopedQuickEntrypointChecks sqec(self);
109   ThrowStackOverflowError(self);
110   self->QuickDeliverException();
111 }
112 
artThrowClassCastException(mirror::Class * dest_type,mirror::Class * src_type,Thread * self)113 extern "C" NO_RETURN void artThrowClassCastException(mirror::Class* dest_type,
114                                                      mirror::Class* src_type,
115                                                      Thread* self)
116     REQUIRES_SHARED(Locks::mutator_lock_) {
117   ScopedQuickEntrypointChecks sqec(self);
118   if (dest_type == nullptr) {
119     // Find the target class for check cast using the bitstring check (dest_type == null).
120     NthCallerVisitor visitor(self, 0u);
121     visitor.WalkStack();
122     DCHECK(visitor.caller != nullptr);
123     uint32_t dex_pc = visitor.GetDexPc();
124     CodeItemDataAccessor accessor(*visitor.caller->GetDexFile(), visitor.caller->GetCodeItem());
125     const Instruction& check_cast = accessor.InstructionAt(dex_pc);
126     DCHECK_EQ(check_cast.Opcode(), Instruction::CHECK_CAST);
127     dex::TypeIndex type_index(check_cast.VRegB_21c());
128     ClassLinker* linker = Runtime::Current()->GetClassLinker();
129     dest_type = linker->LookupResolvedType(type_index, visitor.caller).Ptr();
130     CHECK(dest_type != nullptr) << "Target class should have been previously resolved: "
131         << visitor.caller->GetDexFile()->PrettyType(type_index);
132     CHECK(!dest_type->IsAssignableFrom(src_type))
133         << " " << std::hex << dest_type->PrettyDescriptor() << ";" << dest_type->Depth()
134         << "/" << dest_type->GetField32(mirror::Class::StatusOffset())
135         << " <: " << src_type->PrettyDescriptor() << ";" << src_type->Depth()
136         << "/" << src_type->GetField32(mirror::Class::StatusOffset());
137   }
138   DCHECK(!dest_type->IsAssignableFrom(src_type));
139   ThrowClassCastException(dest_type, src_type);
140   self->QuickDeliverException();
141 }
142 
artThrowClassCastExceptionForObject(mirror::Object * obj,mirror::Class * dest_type,Thread * self)143 extern "C" NO_RETURN void artThrowClassCastExceptionForObject(mirror::Object* obj,
144                                                               mirror::Class* dest_type,
145                                                               Thread* self)
146     REQUIRES_SHARED(Locks::mutator_lock_) {
147   DCHECK(obj != nullptr);
148   artThrowClassCastException(dest_type, obj->GetClass(), self);
149 }
150 
artThrowArrayStoreException(mirror::Object * array,mirror::Object * value,Thread * self)151 extern "C" NO_RETURN void artThrowArrayStoreException(mirror::Object* array, mirror::Object* value,
152                                                       Thread* self)
153     REQUIRES_SHARED(Locks::mutator_lock_) {
154   ScopedQuickEntrypointChecks sqec(self);
155   ThrowArrayStoreException(value->GetClass(), array->GetClass());
156   self->QuickDeliverException();
157 }
158 
159 }  // namespace art
160