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