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