Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 1 | /* |
Elliott Hughes | 0f3c553 | 2012-03-30 14:51:51 -0700 | [diff] [blame] | 2 | * Copyright (C) 2012 The Android Open Source Project |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 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 | |
David Sehr | 0225f8e | 2018-01-31 08:52:24 +0000 | [diff] [blame] | 17 | #include "art_method-inl.h" |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 18 | #include "callee_save_frame.h" |
Vladimir Marko | 175e786 | 2018-03-27 09:03:13 +0000 | [diff] [blame] | 19 | #include "dex/code_item_accessors-inl.h" |
| 20 | #include "dex/dex_instruction-inl.h" |
Ian Rogers | a9a8254 | 2013-10-04 11:17:26 -0700 | [diff] [blame] | 21 | #include "common_throws.h" |
Ian Rogers | a9a8254 | 2013-10-04 11:17:26 -0700 | [diff] [blame] | 22 | #include "mirror/object-inl.h" |
Vladimir Marko | 175e786 | 2018-03-27 09:03:13 +0000 | [diff] [blame] | 23 | #include "nth_caller_visitor.h" |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 24 | #include "thread.h" |
Ian Rogers | 120f1c7 | 2012-09-28 17:17:10 -0700 | [diff] [blame] | 25 | #include "well_known_classes.h" |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 26 | |
| 27 | namespace art { |
| 28 | |
| 29 | // Deliver an exception that's pending on thread helping set up a callee save frame on the way. |
Andreas Gampe | 65b798e | 2015-04-06 09:35:22 -0700 | [diff] [blame] | 30 | extern "C" NO_RETURN void artDeliverPendingExceptionFromCode(Thread* self) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 31 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 32 | ScopedQuickEntrypointChecks sqec(self); |
| 33 | self->QuickDeliverException(); |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 34 | } |
| 35 | |
Alex Light | db01a09 | 2017-04-03 15:39:55 -0700 | [diff] [blame] | 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 | |
Vladimir Marko | 87f3fcb | 2016-04-28 15:52:11 +0100 | [diff] [blame] | 45 | // Called by generated code to throw an exception. |
Andreas Gampe | 65b798e | 2015-04-06 09:35:22 -0700 | [diff] [blame] | 46 | extern "C" NO_RETURN void artDeliverExceptionFromCode(mirror::Throwable* exception, Thread* self) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 47 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 48 | /* |
Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 49 | * exception may be null, in which case this routine should |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 50 | * throw NPE. NOTE: this is a convenience for generated code, |
| 51 | * which previously did the null check inline and constructed |
Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 52 | * and threw a NPE if null. This routine responsible for setting |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 53 | * exception_ in thread and delivering the exception. |
| 54 | */ |
Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 55 | ScopedQuickEntrypointChecks sqec(self); |
Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 56 | if (exception == nullptr) { |
Nicolas Geoffray | 635967b | 2019-08-07 10:15:39 +0100 | [diff] [blame] | 57 | self->ThrowNewException("Ljava/lang/NullPointerException;", nullptr); |
Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 58 | } else { |
Nicolas Geoffray | 14691c5 | 2015-03-05 10:40:17 +0000 | [diff] [blame] | 59 | self->SetException(exception); |
Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 60 | } |
| 61 | self->QuickDeliverException(); |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 62 | } |
| 63 | |
Vladimir Marko | 87f3fcb | 2016-04-28 15:52:11 +0100 | [diff] [blame] | 64 | // Called by generated code to throw a NPE exception. |
Andreas Gampe | 65b798e | 2015-04-06 09:35:22 -0700 | [diff] [blame] | 65 | extern "C" NO_RETURN void artThrowNullPointerExceptionFromCode(Thread* self) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 66 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 67 | ScopedQuickEntrypointChecks sqec(self); |
Nicolas Geoffray | e8e1127 | 2016-06-28 18:08:46 +0100 | [diff] [blame] | 68 | // We come from an explicit check in the generated code. This path is triggered |
| 69 | // only if the object is indeed null. |
Andreas Gampe | 98ea9d9 | 2018-10-19 14:06:15 -0700 | [diff] [blame] | 70 | ThrowNullPointerExceptionFromDexPC(/* check_address= */ false, 0U); |
Nicolas Geoffray | e8e1127 | 2016-06-28 18:08:46 +0100 | [diff] [blame] | 71 | self->QuickDeliverException(); |
| 72 | } |
| 73 | |
| 74 | // Installed by a signal handler to throw a NPE exception. |
| 75 | extern "C" NO_RETURN void artThrowNullPointerExceptionFromSignal(uintptr_t addr, Thread* self) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 76 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Nicolas Geoffray | e8e1127 | 2016-06-28 18:08:46 +0100 | [diff] [blame] | 77 | ScopedQuickEntrypointChecks sqec(self); |
Andreas Gampe | 98ea9d9 | 2018-10-19 14:06:15 -0700 | [diff] [blame] | 78 | ThrowNullPointerExceptionFromDexPC(/* check_address= */ true, addr); |
jeffhao | 94d6df4 | 2012-11-26 16:02:12 -0800 | [diff] [blame] | 79 | self->QuickDeliverException(); |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 80 | } |
| 81 | |
Vladimir Marko | 87f3fcb | 2016-04-28 15:52:11 +0100 | [diff] [blame] | 82 | // Called by generated code to throw an arithmetic divide by zero exception. |
Andreas Gampe | 65b798e | 2015-04-06 09:35:22 -0700 | [diff] [blame] | 83 | extern "C" NO_RETURN void artThrowDivZeroFromCode(Thread* self) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 84 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 85 | ScopedQuickEntrypointChecks sqec(self); |
Sebastien Hertz | 0a3b863 | 2013-06-26 11:16:01 +0200 | [diff] [blame] | 86 | ThrowArithmeticExceptionDivideByZero(); |
Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 87 | self->QuickDeliverException(); |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 88 | } |
| 89 | |
Vladimir Marko | 87f3fcb | 2016-04-28 15:52:11 +0100 | [diff] [blame] | 90 | // Called by generated code to throw an array index out of bounds exception. |
Andreas Gampe | 65b798e | 2015-04-06 09:35:22 -0700 | [diff] [blame] | 91 | extern "C" NO_RETURN void artThrowArrayBoundsFromCode(int index, int length, Thread* self) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 92 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 93 | ScopedQuickEntrypointChecks sqec(self); |
Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 94 | ThrowArrayIndexOutOfBoundsException(index, length); |
| 95 | self->QuickDeliverException(); |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 96 | } |
| 97 | |
Vladimir Marko | 87f3fcb | 2016-04-28 15:52:11 +0100 | [diff] [blame] | 98 | // Called by generated code to throw a string index out of bounds exception. |
| 99 | extern "C" NO_RETURN void artThrowStringBoundsFromCode(int index, int length, Thread* self) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 100 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Vladimir Marko | 87f3fcb | 2016-04-28 15:52:11 +0100 | [diff] [blame] | 101 | ScopedQuickEntrypointChecks sqec(self); |
| 102 | ThrowStringIndexOutOfBoundsException(index, length); |
| 103 | self->QuickDeliverException(); |
| 104 | } |
| 105 | |
Andreas Gampe | 65b798e | 2015-04-06 09:35:22 -0700 | [diff] [blame] | 106 | extern "C" NO_RETURN void artThrowStackOverflowFromCode(Thread* self) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 107 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 108 | ScopedQuickEntrypointChecks sqec(self); |
jeffhao | d752132 | 2012-11-21 15:38:24 -0800 | [diff] [blame] | 109 | ThrowStackOverflowError(self); |
jeffhao | 94d6df4 | 2012-11-26 16:02:12 -0800 | [diff] [blame] | 110 | self->QuickDeliverException(); |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 111 | } |
| 112 | |
Andreas Gampe | 65b798e | 2015-04-06 09:35:22 -0700 | [diff] [blame] | 113 | extern "C" NO_RETURN void artThrowClassCastException(mirror::Class* dest_type, |
| 114 | mirror::Class* src_type, |
| 115 | Thread* self) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 116 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 117 | ScopedQuickEntrypointChecks sqec(self); |
Vladimir Marko | 175e786 | 2018-03-27 09:03:13 +0000 | [diff] [blame] | 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 | } |
Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 138 | DCHECK(!dest_type->IsAssignableFrom(src_type)); |
Ian Rogers | a9a8254 | 2013-10-04 11:17:26 -0700 | [diff] [blame] | 139 | ThrowClassCastException(dest_type, src_type); |
| 140 | self->QuickDeliverException(); |
| 141 | } |
| 142 | |
Mathieu Chartier | b99f4d6 | 2016-11-07 16:17:26 -0800 | [diff] [blame] | 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 | |
Andreas Gampe | 65b798e | 2015-04-06 09:35:22 -0700 | [diff] [blame] | 151 | extern "C" NO_RETURN void artThrowArrayStoreException(mirror::Object* array, mirror::Object* value, |
| 152 | Thread* self) |
Andreas Gampe | bdf7f1c | 2016-08-30 16:38:47 -0700 | [diff] [blame] | 153 | REQUIRES_SHARED(Locks::mutator_lock_) { |
Ian Rogers | 1d8cdbc | 2014-09-22 22:51:09 -0700 | [diff] [blame] | 154 | ScopedQuickEntrypointChecks sqec(self); |
Ian Rogers | a9a8254 | 2013-10-04 11:17:26 -0700 | [diff] [blame] | 155 | ThrowArrayStoreException(value->GetClass(), array->GetClass()); |
| 156 | self->QuickDeliverException(); |
| 157 | } |
| 158 | |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 159 | } // namespace art |