| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 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 "common_throws.h" | 
 | 18 |  | 
| Ian Rogers | 22d5e73 | 2014-07-15 22:23:51 -0700 | [diff] [blame] | 19 | #include <sstream> | 
 | 20 |  | 
| Andreas Gampe | 103992b | 2016-01-04 15:32:43 -0800 | [diff] [blame] | 21 | #include "ScopedLocalRef.h" | 
 | 22 |  | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 23 | #include "art_field-inl.h" | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 24 | #include "art_method-inl.h" | 
| Elliott Hughes | 07ed66b | 2012-12-12 18:34:25 -0800 | [diff] [blame] | 25 | #include "base/logging.h" | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 26 | #include "class_linker-inl.h" | 
| Ian Rogers | 4f6ad8a | 2013-03-18 15:27:28 -0700 | [diff] [blame] | 27 | #include "dex_file-inl.h" | 
| Sebastien Hertz | 75b2a4a | 2013-05-21 09:25:10 +0200 | [diff] [blame] | 28 | #include "dex_instruction-inl.h" | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 29 | #include "invoke_type.h" | 
| Ian Rogers | 4f6ad8a | 2013-03-18 15:27:28 -0700 | [diff] [blame] | 30 | #include "mirror/class-inl.h" | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 31 | #include "mirror/object-inl.h" | 
 | 32 | #include "mirror/object_array-inl.h" | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 33 | #include "thread.h" | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 34 | #include "verifier/method_verifier.h" | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 35 |  | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 36 | namespace art { | 
 | 37 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 38 | static void AddReferrerLocation(std::ostream& os, mirror::Class* referrer) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 39 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 40 |   if (referrer != nullptr) { | 
| Mathieu Chartier | f832284 | 2014-05-16 10:59:25 -0700 | [diff] [blame] | 41 |     std::string location(referrer->GetLocation()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 42 |     if (!location.empty()) { | 
 | 43 |       os << " (declaration of '" << PrettyDescriptor(referrer) | 
 | 44 |             << "' appears in " << location << ")"; | 
 | 45 |     } | 
 | 46 |   } | 
 | 47 | } | 
 | 48 |  | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 49 | static void ThrowException(const char* exception_descriptor, | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 50 |                            mirror::Class* referrer, const char* fmt, va_list* args = nullptr) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 51 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 52 |   std::ostringstream msg; | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 53 |   if (args != nullptr) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 54 |     std::string vmsg; | 
 | 55 |     StringAppendV(&vmsg, fmt, *args); | 
 | 56 |     msg << vmsg; | 
 | 57 |   } else { | 
 | 58 |     msg << fmt; | 
 | 59 |   } | 
 | 60 |   AddReferrerLocation(msg, referrer); | 
 | 61 |   Thread* self = Thread::Current(); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 62 |   self->ThrowNewException(exception_descriptor, msg.str().c_str()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 63 | } | 
 | 64 |  | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 65 | static void ThrowWrappedException(const char* exception_descriptor, | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 66 |                                   mirror::Class* referrer, const char* fmt, va_list* args = nullptr) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 67 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Andreas Gampe | 329d188 | 2014-04-08 10:32:19 -0700 | [diff] [blame] | 68 |   std::ostringstream msg; | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 69 |   if (args != nullptr) { | 
| Andreas Gampe | 329d188 | 2014-04-08 10:32:19 -0700 | [diff] [blame] | 70 |     std::string vmsg; | 
 | 71 |     StringAppendV(&vmsg, fmt, *args); | 
 | 72 |     msg << vmsg; | 
 | 73 |   } else { | 
 | 74 |     msg << fmt; | 
 | 75 |   } | 
 | 76 |   AddReferrerLocation(msg, referrer); | 
 | 77 |   Thread* self = Thread::Current(); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 78 |   self->ThrowNewWrappedException(exception_descriptor, msg.str().c_str()); | 
| Andreas Gampe | 329d188 | 2014-04-08 10:32:19 -0700 | [diff] [blame] | 79 | } | 
 | 80 |  | 
| Sebastien Hertz | 56adf60 | 2013-07-09 17:27:07 +0200 | [diff] [blame] | 81 | // AbstractMethodError | 
 | 82 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 83 | void ThrowAbstractMethodError(ArtMethod* method) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 84 |   ThrowException("Ljava/lang/AbstractMethodError;", nullptr, | 
| Sebastien Hertz | 56adf60 | 2013-07-09 17:27:07 +0200 | [diff] [blame] | 85 |                  StringPrintf("abstract method \"%s\"", | 
 | 86 |                               PrettyMethod(method).c_str()).c_str()); | 
 | 87 | } | 
 | 88 |  | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 89 | // ArithmeticException | 
 | 90 |  | 
| Sebastien Hertz | 0a3b863 | 2013-06-26 11:16:01 +0200 | [diff] [blame] | 91 | void ThrowArithmeticExceptionDivideByZero() { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 92 |   ThrowException("Ljava/lang/ArithmeticException;", nullptr, "divide by zero"); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 93 | } | 
 | 94 |  | 
 | 95 | // ArrayIndexOutOfBoundsException | 
 | 96 |  | 
 | 97 | void ThrowArrayIndexOutOfBoundsException(int index, int length) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 98 |   ThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", nullptr, | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 99 |                  StringPrintf("length=%d; index=%d", length, index).c_str()); | 
 | 100 | } | 
 | 101 |  | 
 | 102 | // ArrayStoreException | 
 | 103 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 104 | void ThrowArrayStoreException(mirror::Class* element_class, mirror::Class* array_class) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 105 |   ThrowException("Ljava/lang/ArrayStoreException;", nullptr, | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 106 |                  StringPrintf("%s cannot be stored in an array of type %s", | 
 | 107 |                               PrettyDescriptor(element_class).c_str(), | 
 | 108 |                               PrettyDescriptor(array_class).c_str()).c_str()); | 
 | 109 | } | 
 | 110 |  | 
 | 111 | // ClassCastException | 
 | 112 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 113 | void ThrowClassCastException(mirror::Class* dest_type, mirror::Class* src_type) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 114 |   ThrowException("Ljava/lang/ClassCastException;", nullptr, | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 115 |                  StringPrintf("%s cannot be cast to %s", | 
 | 116 |                               PrettyDescriptor(src_type).c_str(), | 
 | 117 |                               PrettyDescriptor(dest_type).c_str()).c_str()); | 
 | 118 | } | 
 | 119 |  | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 120 | void ThrowClassCastException(const char* msg) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 121 |   ThrowException("Ljava/lang/ClassCastException;", nullptr, msg); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 122 | } | 
 | 123 |  | 
 | 124 | // ClassCircularityError | 
 | 125 |  | 
 | 126 | void ThrowClassCircularityError(mirror::Class* c) { | 
 | 127 |   std::ostringstream msg; | 
 | 128 |   msg << PrettyDescriptor(c); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 129 |   ThrowException("Ljava/lang/ClassCircularityError;", c, msg.str().c_str()); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 130 | } | 
 | 131 |  | 
 | 132 | // ClassFormatError | 
 | 133 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 134 | void ThrowClassFormatError(mirror::Class* referrer, const char* fmt, ...) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 135 |   va_list args; | 
 | 136 |   va_start(args, fmt); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 137 |   ThrowException("Ljava/lang/ClassFormatError;", referrer, fmt, &args); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 138 |   va_end(args);} | 
 | 139 |  | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 140 | // IllegalAccessError | 
 | 141 |  | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 142 | void ThrowIllegalAccessErrorClass(mirror::Class* referrer, mirror::Class* accessed) { | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 143 |   std::ostringstream msg; | 
| Ian Rogers | b726dcb | 2012-09-05 08:57:23 -0700 | [diff] [blame] | 144 |   msg << "Illegal class access: '" << PrettyDescriptor(referrer) << "' attempting to access '" | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 145 |       << PrettyDescriptor(accessed) << "'"; | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 146 |   ThrowException("Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 147 | } | 
 | 148 |  | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 149 | void ThrowIllegalAccessErrorClassForMethodDispatch(mirror::Class* referrer, mirror::Class* accessed, | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 150 |                                                    ArtMethod* called, | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 151 |                                                    InvokeType type) { | 
 | 152 |   std::ostringstream msg; | 
| Ian Rogers | b726dcb | 2012-09-05 08:57:23 -0700 | [diff] [blame] | 153 |   msg << "Illegal class access ('" << PrettyDescriptor(referrer) << "' attempting to access '" | 
 | 154 |       << PrettyDescriptor(accessed) << "') in attempt to invoke " << type | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 155 |       << " method " << PrettyMethod(called).c_str(); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 156 |   ThrowException("Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 157 | } | 
 | 158 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 159 | void ThrowIllegalAccessErrorMethod(mirror::Class* referrer, ArtMethod* accessed) { | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 160 |   std::ostringstream msg; | 
 | 161 |   msg << "Method '" << PrettyMethod(accessed) << "' is inaccessible to class '" | 
 | 162 |       << PrettyDescriptor(referrer) << "'"; | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 163 |   ThrowException("Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 164 | } | 
 | 165 |  | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 166 | void ThrowIllegalAccessErrorField(mirror::Class* referrer, ArtField* accessed) { | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 167 |   std::ostringstream msg; | 
 | 168 |   msg << "Field '" << PrettyField(accessed, false) << "' is inaccessible to class '" | 
 | 169 |       << PrettyDescriptor(referrer) << "'"; | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 170 |   ThrowException("Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 171 | } | 
 | 172 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 173 | void ThrowIllegalAccessErrorFinalField(ArtMethod* referrer, ArtField* accessed) { | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 174 |   std::ostringstream msg; | 
 | 175 |   msg << "Final field '" << PrettyField(accessed, false) << "' cannot be written to by method '" | 
 | 176 |       << PrettyMethod(referrer) << "'"; | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 177 |   ThrowException("Ljava/lang/IllegalAccessError;", | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 178 |                  referrer != nullptr ? referrer->GetDeclaringClass() : nullptr, | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 179 |                  msg.str().c_str()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 180 | } | 
 | 181 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 182 | void ThrowIllegalAccessError(mirror::Class* referrer, const char* fmt, ...) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 183 |   va_list args; | 
 | 184 |   va_start(args, fmt); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 185 |   ThrowException("Ljava/lang/IllegalAccessError;", referrer, fmt, &args); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 186 |   va_end(args); | 
 | 187 | } | 
 | 188 |  | 
| Jeff Hao | 11d5d8f | 2014-03-26 15:08:20 -0700 | [diff] [blame] | 189 | // IllegalAccessException | 
 | 190 |  | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 191 | void ThrowIllegalAccessException(const char* msg) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 192 |   ThrowException("Ljava/lang/IllegalAccessException;", nullptr, msg); | 
| Jeff Hao | 11d5d8f | 2014-03-26 15:08:20 -0700 | [diff] [blame] | 193 | } | 
 | 194 |  | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 195 | // IllegalArgumentException | 
 | 196 |  | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 197 | void ThrowIllegalArgumentException(const char* msg) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 198 |   ThrowException("Ljava/lang/IllegalArgumentException;", nullptr, msg); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 199 | } | 
 | 200 |  | 
 | 201 |  | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 202 | // IncompatibleClassChangeError | 
 | 203 |  | 
 | 204 | void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type, | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 205 |                                        ArtMethod* method, ArtMethod* referrer) { | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 206 |   std::ostringstream msg; | 
 | 207 |   msg << "The method '" << PrettyMethod(method) << "' was expected to be of type " | 
 | 208 |       << expected_type << " but instead was found to be of type " << found_type; | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 209 |   ThrowException("Ljava/lang/IncompatibleClassChangeError;", | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 210 |                  referrer != nullptr ? referrer->GetDeclaringClass() : nullptr, | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 211 |                  msg.str().c_str()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 212 | } | 
 | 213 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 214 | void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(ArtMethod* interface_method, | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 215 |                                                                 mirror::Object* this_object, | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 216 |                                                                 ArtMethod* referrer) { | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 217 |   // Referrer is calling interface_method on this_object, however, the interface_method isn't | 
 | 218 |   // implemented by this_object. | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 219 |   CHECK(this_object != nullptr); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 220 |   std::ostringstream msg; | 
 | 221 |   msg << "Class '" << PrettyDescriptor(this_object->GetClass()) | 
 | 222 |       << "' does not implement interface '" | 
 | 223 |       << PrettyDescriptor(interface_method->GetDeclaringClass()) | 
 | 224 |       << "' in call to '" << PrettyMethod(interface_method) << "'"; | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 225 |   ThrowException("Ljava/lang/IncompatibleClassChangeError;", | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 226 |                  referrer != nullptr ? referrer->GetDeclaringClass() : nullptr, | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 227 |                  msg.str().c_str()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 228 | } | 
 | 229 |  | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 230 | void ThrowIncompatibleClassChangeErrorField(ArtField* resolved_field, bool is_static, | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 231 |                                             ArtMethod* referrer) { | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 232 |   std::ostringstream msg; | 
 | 233 |   msg << "Expected '" << PrettyField(resolved_field) << "' to be a " | 
| Ian Rogers | b726dcb | 2012-09-05 08:57:23 -0700 | [diff] [blame] | 234 |       << (is_static ? "static" : "instance") << " field" << " rather than a " | 
 | 235 |       << (is_static ? "instance" : "static") << " field"; | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 236 |   ThrowException("Ljava/lang/IncompatibleClassChangeError;", referrer->GetDeclaringClass(), | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 237 |                  msg.str().c_str()); | 
 | 238 | } | 
 | 239 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 240 | void ThrowIncompatibleClassChangeError(mirror::Class* referrer, const char* fmt, ...) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 241 |   va_list args; | 
 | 242 |   va_start(args, fmt); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 243 |   ThrowException("Ljava/lang/IncompatibleClassChangeError;", referrer, fmt, &args); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 244 |   va_end(args); | 
 | 245 | } | 
 | 246 |  | 
| Alex Light | 9139e00 | 2015-10-09 15:59:48 -0700 | [diff] [blame] | 247 | void ThrowIncompatibleClassChangeErrorForMethodConflict(ArtMethod* method) { | 
 | 248 |   DCHECK(method != nullptr); | 
 | 249 |   ThrowException("Ljava/lang/IncompatibleClassChangeError;", | 
 | 250 |                  /*referrer*/nullptr, | 
 | 251 |                  StringPrintf("Conflicting default method implementations %s", | 
 | 252 |                               PrettyMethod(method).c_str()).c_str()); | 
 | 253 | } | 
 | 254 |  | 
 | 255 |  | 
| Ian Rogers | 8d31bbd | 2013-10-13 10:44:14 -0700 | [diff] [blame] | 256 | // IOException | 
 | 257 |  | 
 | 258 | void ThrowIOException(const char* fmt, ...) { | 
 | 259 |   va_list args; | 
 | 260 |   va_start(args, fmt); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 261 |   ThrowException("Ljava/io/IOException;", nullptr, fmt, &args); | 
| Ian Rogers | 8d31bbd | 2013-10-13 10:44:14 -0700 | [diff] [blame] | 262 |   va_end(args); | 
 | 263 | } | 
 | 264 |  | 
| Andreas Gampe | 329d188 | 2014-04-08 10:32:19 -0700 | [diff] [blame] | 265 | void ThrowWrappedIOException(const char* fmt, ...) { | 
 | 266 |   va_list args; | 
 | 267 |   va_start(args, fmt); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 268 |   ThrowWrappedException("Ljava/io/IOException;", nullptr, fmt, &args); | 
| Andreas Gampe | 329d188 | 2014-04-08 10:32:19 -0700 | [diff] [blame] | 269 |   va_end(args); | 
 | 270 | } | 
 | 271 |  | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 272 | // LinkageError | 
 | 273 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 274 | void ThrowLinkageError(mirror::Class* referrer, const char* fmt, ...) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 275 |   va_list args; | 
 | 276 |   va_start(args, fmt); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 277 |   ThrowException("Ljava/lang/LinkageError;", referrer, fmt, &args); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 278 |   va_end(args); | 
 | 279 | } | 
 | 280 |  | 
| Vladimir Marko | d5e5a0e | 2015-05-08 12:26:59 +0100 | [diff] [blame] | 281 | void ThrowWrappedLinkageError(mirror::Class* referrer, const char* fmt, ...) { | 
 | 282 |   va_list args; | 
 | 283 |   va_start(args, fmt); | 
 | 284 |   ThrowWrappedException("Ljava/lang/LinkageError;", referrer, fmt, &args); | 
 | 285 |   va_end(args); | 
 | 286 | } | 
 | 287 |  | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 288 | // NegativeArraySizeException | 
 | 289 |  | 
 | 290 | void ThrowNegativeArraySizeException(int size) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 291 |   ThrowException("Ljava/lang/NegativeArraySizeException;", nullptr, | 
| Brian Carlstrom | ea46f95 | 2013-07-30 01:26:50 -0700 | [diff] [blame] | 292 |                  StringPrintf("%d", size).c_str()); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 293 | } | 
 | 294 |  | 
 | 295 | void ThrowNegativeArraySizeException(const char* msg) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 296 |   ThrowException("Ljava/lang/NegativeArraySizeException;", nullptr, msg); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 297 | } | 
 | 298 |  | 
 | 299 | // NoSuchFieldError | 
 | 300 |  | 
 | 301 | void ThrowNoSuchFieldError(const StringPiece& scope, mirror::Class* c, | 
| Mathieu Chartier | 4e06778 | 2015-05-13 13:13:24 -0700 | [diff] [blame] | 302 |                            const StringPiece& type, const StringPiece& name) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 303 |   std::ostringstream msg; | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 304 |   std::string temp; | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 305 |   msg << "No " << scope << "field " << name << " of type " << type | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 306 |       << " in class " << c->GetDescriptor(&temp) << " or its superclasses"; | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 307 |   ThrowException("Ljava/lang/NoSuchFieldError;", c, msg.str().c_str()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 308 | } | 
 | 309 |  | 
| Mathieu Chartier | 4e06778 | 2015-05-13 13:13:24 -0700 | [diff] [blame] | 310 | void ThrowNoSuchFieldException(mirror::Class* c, const StringPiece& name) { | 
 | 311 |   std::ostringstream msg; | 
 | 312 |   std::string temp; | 
 | 313 |   msg << "No field " << name << " in class " << c->GetDescriptor(&temp); | 
 | 314 |   ThrowException("Ljava/lang/NoSuchFieldException;", c, msg.str().c_str()); | 
 | 315 | } | 
 | 316 |  | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 317 | // NoSuchMethodError | 
 | 318 |  | 
| Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 319 | void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name, | 
| Ian Rogers | d91d6d6 | 2013-09-25 20:26:14 -0700 | [diff] [blame] | 320 |                             const Signature& signature) { | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 321 |   std::ostringstream msg; | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 322 |   std::string temp; | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 323 |   msg << "No " << type << " method " << name << signature | 
| Ian Rogers | 1ff3c98 | 2014-08-12 02:30:58 -0700 | [diff] [blame] | 324 |       << " in class " << c->GetDescriptor(&temp) << " or its super classes"; | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 325 |   ThrowException("Ljava/lang/NoSuchMethodError;", c, msg.str().c_str()); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 326 | } | 
 | 327 |  | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 328 | void ThrowNoSuchMethodError(uint32_t method_idx) { | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 329 |   ArtMethod* method = Thread::Current()->GetCurrentMethod(nullptr); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 330 |   mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache(); | 
| Ian Rogers | 4445a7e | 2012-10-05 17:19:13 -0700 | [diff] [blame] | 331 |   const DexFile& dex_file = *dex_cache->GetDexFile(); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 332 |   std::ostringstream msg; | 
 | 333 |   msg << "No method '" << PrettyMethod(method_idx, dex_file, true) << "'"; | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 334 |   ThrowException("Ljava/lang/NoSuchMethodError;", | 
 | 335 |                  method->GetDeclaringClass(), msg.str().c_str()); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 336 | } | 
 | 337 |  | 
 | 338 | // NullPointerException | 
 | 339 |  | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 340 | void ThrowNullPointerExceptionForFieldAccess(ArtField* field, bool is_read) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 341 |   std::ostringstream msg; | 
 | 342 |   msg << "Attempt to " << (is_read ? "read from" : "write to") | 
 | 343 |       << " field '" << PrettyField(field, true) << "' on a null object reference"; | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 344 |   ThrowException("Ljava/lang/NullPointerException;", nullptr, msg.str().c_str()); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 345 | } | 
 | 346 |  | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 347 | static void ThrowNullPointerExceptionForMethodAccessImpl(uint32_t method_idx, | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 348 |                                                          const DexFile& dex_file, | 
 | 349 |                                                          InvokeType type) | 
| Mathieu Chartier | 9044347 | 2015-07-16 20:32:27 -0700 | [diff] [blame] | 350 |     SHARED_REQUIRES(Locks::mutator_lock_) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 351 |   std::ostringstream msg; | 
 | 352 |   msg << "Attempt to invoke " << type << " method '" | 
 | 353 |       << PrettyMethod(method_idx, dex_file, true) << "' on a null object reference"; | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 354 |   ThrowException("Ljava/lang/NullPointerException;", nullptr, msg.str().c_str()); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 355 | } | 
 | 356 |  | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 357 | void ThrowNullPointerExceptionForMethodAccess(uint32_t method_idx, | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 358 |                                               InvokeType type) { | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 359 |   mirror::DexCache* dex_cache = | 
 | 360 |       Thread::Current()->GetCurrentMethod(nullptr)->GetDeclaringClass()->GetDexCache(); | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 361 |   const DexFile& dex_file = *dex_cache->GetDexFile(); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 362 |   ThrowNullPointerExceptionForMethodAccessImpl(method_idx, dex_file, type); | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 363 | } | 
 | 364 |  | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 365 | void ThrowNullPointerExceptionForMethodAccess(ArtMethod* method, | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 366 |                                               InvokeType type) { | 
 | 367 |   mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache(); | 
 | 368 |   const DexFile& dex_file = *dex_cache->GetDexFile(); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 369 |   ThrowNullPointerExceptionForMethodAccessImpl(method->GetDexMethodIndex(), | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 370 |                                                dex_file, type); | 
 | 371 | } | 
 | 372 |  | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 373 | void ThrowNullPointerExceptionFromDexPC() { | 
 | 374 |   uint32_t throw_dex_pc; | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 375 |   ArtMethod* method = Thread::Current()->GetCurrentMethod(&throw_dex_pc); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 376 |   const DexFile::CodeItem* code = method->GetCodeItem(); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 377 |   CHECK_LT(throw_dex_pc, code->insns_size_in_code_units_); | 
 | 378 |   const Instruction* instr = Instruction::At(&code->insns_[throw_dex_pc]); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 379 |   switch (instr->Opcode()) { | 
 | 380 |     case Instruction::INVOKE_DIRECT: | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 381 |       ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kDirect); | 
| Sebastien Hertz | 75b2a4a | 2013-05-21 09:25:10 +0200 | [diff] [blame] | 382 |       break; | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 383 |     case Instruction::INVOKE_DIRECT_RANGE: | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 384 |       ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kDirect); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 385 |       break; | 
 | 386 |     case Instruction::INVOKE_VIRTUAL: | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 387 |       ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kVirtual); | 
| Sebastien Hertz | 75b2a4a | 2013-05-21 09:25:10 +0200 | [diff] [blame] | 388 |       break; | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 389 |     case Instruction::INVOKE_VIRTUAL_RANGE: | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 390 |       ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kVirtual); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 391 |       break; | 
 | 392 |     case Instruction::INVOKE_INTERFACE: | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 393 |       ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kInterface); | 
| Sebastien Hertz | 75b2a4a | 2013-05-21 09:25:10 +0200 | [diff] [blame] | 394 |       break; | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 395 |     case Instruction::INVOKE_INTERFACE_RANGE: | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 396 |       ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kInterface); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 397 |       break; | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 398 |     case Instruction::INVOKE_VIRTUAL_QUICK: | 
 | 399 |     case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: { | 
 | 400 |       // Since we replaced the method index, we ask the verifier to tell us which | 
 | 401 |       // method is invoked at this location. | 
| Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 402 |       ArtMethod* invoked_method = | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 403 |           verifier::MethodVerifier::FindInvokedMethodAtDexPc(method, throw_dex_pc); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 404 |       if (invoked_method != nullptr) { | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 405 |         // NPE with precise message. | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 406 |         ThrowNullPointerExceptionForMethodAccess(invoked_method, kVirtual); | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 407 |       } else { | 
 | 408 |         // NPE with imprecise message. | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 409 |         ThrowNullPointerException("Attempt to invoke a virtual method on a null object reference"); | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 410 |       } | 
 | 411 |       break; | 
 | 412 |     } | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 413 |     case Instruction::IGET: | 
 | 414 |     case Instruction::IGET_WIDE: | 
 | 415 |     case Instruction::IGET_OBJECT: | 
 | 416 |     case Instruction::IGET_BOOLEAN: | 
 | 417 |     case Instruction::IGET_BYTE: | 
 | 418 |     case Instruction::IGET_CHAR: | 
 | 419 |     case Instruction::IGET_SHORT: { | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 420 |       ArtField* field = | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 421 |           Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(), method, false); | 
 | 422 |       ThrowNullPointerExceptionForFieldAccess(field, true /* read */); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 423 |       break; | 
 | 424 |     } | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 425 |     case Instruction::IGET_QUICK: | 
| Mathieu Chartier | ffc605c | 2014-12-10 10:35:44 -0800 | [diff] [blame] | 426 |     case Instruction::IGET_BOOLEAN_QUICK: | 
 | 427 |     case Instruction::IGET_BYTE_QUICK: | 
 | 428 |     case Instruction::IGET_CHAR_QUICK: | 
 | 429 |     case Instruction::IGET_SHORT_QUICK: | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 430 |     case Instruction::IGET_WIDE_QUICK: | 
 | 431 |     case Instruction::IGET_OBJECT_QUICK: { | 
 | 432 |       // Since we replaced the field index, we ask the verifier to tell us which | 
 | 433 |       // field is accessed at this location. | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 434 |       ArtField* field = | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 435 |           verifier::MethodVerifier::FindAccessedFieldAtDexPc(method, throw_dex_pc); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 436 |       if (field != nullptr) { | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 437 |         // NPE with precise message. | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 438 |         ThrowNullPointerExceptionForFieldAccess(field, true /* read */); | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 439 |       } else { | 
 | 440 |         // NPE with imprecise message. | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 441 |         ThrowNullPointerException("Attempt to read from a field on a null object reference"); | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 442 |       } | 
 | 443 |       break; | 
 | 444 |     } | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 445 |     case Instruction::IPUT: | 
 | 446 |     case Instruction::IPUT_WIDE: | 
 | 447 |     case Instruction::IPUT_OBJECT: | 
 | 448 |     case Instruction::IPUT_BOOLEAN: | 
 | 449 |     case Instruction::IPUT_BYTE: | 
 | 450 |     case Instruction::IPUT_CHAR: | 
 | 451 |     case Instruction::IPUT_SHORT: { | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 452 |       ArtField* field = | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 453 |           Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(), method, false); | 
 | 454 |       ThrowNullPointerExceptionForFieldAccess(field, false /* write */); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 455 |       break; | 
 | 456 |     } | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 457 |     case Instruction::IPUT_QUICK: | 
| Fred Shih | 37f05ef | 2014-07-16 18:38:08 -0700 | [diff] [blame] | 458 |     case Instruction::IPUT_BOOLEAN_QUICK: | 
 | 459 |     case Instruction::IPUT_BYTE_QUICK: | 
 | 460 |     case Instruction::IPUT_CHAR_QUICK: | 
 | 461 |     case Instruction::IPUT_SHORT_QUICK: | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 462 |     case Instruction::IPUT_WIDE_QUICK: | 
 | 463 |     case Instruction::IPUT_OBJECT_QUICK: { | 
 | 464 |       // Since we replaced the field index, we ask the verifier to tell us which | 
 | 465 |       // field is accessed at this location. | 
| Mathieu Chartier | c785344 | 2015-03-27 14:35:38 -0700 | [diff] [blame] | 466 |       ArtField* field = | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 467 |           verifier::MethodVerifier::FindAccessedFieldAtDexPc(method, throw_dex_pc); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 468 |       if (field != nullptr) { | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 469 |         // NPE with precise message. | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 470 |         ThrowNullPointerExceptionForFieldAccess(field, false /* write */); | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 471 |       } else { | 
 | 472 |         // NPE with imprecise message. | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 473 |         ThrowNullPointerException("Attempt to write to a field on a null object reference"); | 
| Sebastien Hertz | 2d6ba51 | 2013-05-17 11:31:37 +0200 | [diff] [blame] | 474 |       } | 
 | 475 |       break; | 
 | 476 |     } | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 477 |     case Instruction::AGET: | 
 | 478 |     case Instruction::AGET_WIDE: | 
 | 479 |     case Instruction::AGET_OBJECT: | 
 | 480 |     case Instruction::AGET_BOOLEAN: | 
 | 481 |     case Instruction::AGET_BYTE: | 
 | 482 |     case Instruction::AGET_CHAR: | 
 | 483 |     case Instruction::AGET_SHORT: | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 484 |       ThrowException("Ljava/lang/NullPointerException;", nullptr, | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 485 |                      "Attempt to read from null array"); | 
 | 486 |       break; | 
 | 487 |     case Instruction::APUT: | 
 | 488 |     case Instruction::APUT_WIDE: | 
 | 489 |     case Instruction::APUT_OBJECT: | 
 | 490 |     case Instruction::APUT_BOOLEAN: | 
 | 491 |     case Instruction::APUT_BYTE: | 
 | 492 |     case Instruction::APUT_CHAR: | 
 | 493 |     case Instruction::APUT_SHORT: | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 494 |       ThrowException("Ljava/lang/NullPointerException;", nullptr, | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 495 |                      "Attempt to write to null array"); | 
 | 496 |       break; | 
 | 497 |     case Instruction::ARRAY_LENGTH: | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 498 |       ThrowException("Ljava/lang/NullPointerException;", nullptr, | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 499 |                      "Attempt to get length of null array"); | 
 | 500 |       break; | 
 | 501 |     default: { | 
 | 502 |       // TODO: We should have covered all the cases where we expect a NPE above, this | 
 | 503 |       //       message/logging is so we can improve any cases we've missed in the future. | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 504 |       const DexFile* dex_file = | 
 | 505 |           method->GetDeclaringClass()->GetDexCache()->GetDexFile(); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 506 |       ThrowException("Ljava/lang/NullPointerException;", nullptr, | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 507 |                      StringPrintf("Null pointer exception during instruction '%s'", | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 508 |                                   instr->DumpString(dex_file).c_str()).c_str()); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 509 |       break; | 
 | 510 |     } | 
 | 511 |   } | 
 | 512 | } | 
 | 513 |  | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 514 | void ThrowNullPointerException(const char* msg) { | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 515 |   ThrowException("Ljava/lang/NullPointerException;", nullptr, msg); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 516 | } | 
 | 517 |  | 
 | 518 | // RuntimeException | 
 | 519 |  | 
 | 520 | void ThrowRuntimeException(const char* fmt, ...) { | 
 | 521 |   va_list args; | 
 | 522 |   va_start(args, fmt); | 
| Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 523 |   ThrowException("Ljava/lang/RuntimeException;", nullptr, fmt, &args); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 524 |   va_end(args); | 
 | 525 | } | 
 | 526 |  | 
| Andreas Gampe | 103992b | 2016-01-04 15:32:43 -0800 | [diff] [blame] | 527 | // Stack overflow. | 
 | 528 |  | 
 | 529 | void ThrowStackOverflowError(Thread* self) { | 
 | 530 |   if (self->IsHandlingStackOverflow()) { | 
 | 531 |     LOG(ERROR) << "Recursive stack overflow."; | 
 | 532 |     // We don't fail here because SetStackEndForStackOverflow will print better diagnostics. | 
 | 533 |   } | 
 | 534 |  | 
 | 535 |   self->SetStackEndForStackOverflow();  // Allow space on the stack for constructor to execute. | 
 | 536 |   JNIEnvExt* env = self->GetJniEnv(); | 
 | 537 |   std::string msg("stack size "); | 
 | 538 |   msg += PrettySize(self->GetStackSize()); | 
 | 539 |  | 
 | 540 |   // Avoid running Java code for exception initialization. | 
 | 541 |   // TODO: Checks to make this a bit less brittle. | 
 | 542 |  | 
 | 543 |   std::string error_msg; | 
 | 544 |  | 
 | 545 |   // Allocate an uninitialized object. | 
 | 546 |   ScopedLocalRef<jobject> exc(env, | 
 | 547 |                               env->AllocObject(WellKnownClasses::java_lang_StackOverflowError)); | 
 | 548 |   if (exc.get() != nullptr) { | 
 | 549 |     // "Initialize". | 
 | 550 |     // StackOverflowError -> VirtualMachineError -> Error -> Throwable -> Object. | 
 | 551 |     // Only Throwable has "custom" fields: | 
 | 552 |     //   String detailMessage. | 
 | 553 |     //   Throwable cause (= this). | 
 | 554 |     //   List<Throwable> suppressedExceptions (= Collections.emptyList()). | 
 | 555 |     //   Object stackState; | 
 | 556 |     //   StackTraceElement[] stackTrace; | 
 | 557 |     // Only Throwable has a non-empty constructor: | 
 | 558 |     //   this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT; | 
 | 559 |     //   fillInStackTrace(); | 
 | 560 |  | 
 | 561 |     // detailMessage. | 
 | 562 |     // TODO: Use String::FromModifiedUTF...? | 
 | 563 |     ScopedLocalRef<jstring> s(env, env->NewStringUTF(msg.c_str())); | 
 | 564 |     if (s.get() != nullptr) { | 
 | 565 |       env->SetObjectField(exc.get(), WellKnownClasses::java_lang_Throwable_detailMessage, s.get()); | 
 | 566 |  | 
 | 567 |       // cause. | 
 | 568 |       env->SetObjectField(exc.get(), WellKnownClasses::java_lang_Throwable_cause, exc.get()); | 
 | 569 |  | 
 | 570 |       // suppressedExceptions. | 
 | 571 |       ScopedLocalRef<jobject> emptylist(env, env->GetStaticObjectField( | 
 | 572 |           WellKnownClasses::java_util_Collections, | 
 | 573 |           WellKnownClasses::java_util_Collections_EMPTY_LIST)); | 
 | 574 |       CHECK(emptylist.get() != nullptr); | 
 | 575 |       env->SetObjectField(exc.get(), | 
 | 576 |                           WellKnownClasses::java_lang_Throwable_suppressedExceptions, | 
 | 577 |                           emptylist.get()); | 
 | 578 |  | 
 | 579 |       // stackState is set as result of fillInStackTrace. fillInStackTrace calls | 
 | 580 |       // nativeFillInStackTrace. | 
 | 581 |       ScopedLocalRef<jobject> stack_state_val(env, nullptr); | 
 | 582 |       { | 
 | 583 |         ScopedObjectAccessUnchecked soa(env); | 
 | 584 |         stack_state_val.reset(soa.Self()->CreateInternalStackTrace<false>(soa)); | 
 | 585 |       } | 
 | 586 |       if (stack_state_val.get() != nullptr) { | 
 | 587 |         env->SetObjectField(exc.get(), | 
 | 588 |                             WellKnownClasses::java_lang_Throwable_stackState, | 
 | 589 |                             stack_state_val.get()); | 
 | 590 |  | 
 | 591 |         // stackTrace. | 
 | 592 |         ScopedLocalRef<jobject> stack_trace_elem(env, env->GetStaticObjectField( | 
 | 593 |             WellKnownClasses::libcore_util_EmptyArray, | 
 | 594 |             WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT)); | 
 | 595 |         env->SetObjectField(exc.get(), | 
 | 596 |                             WellKnownClasses::java_lang_Throwable_stackTrace, | 
 | 597 |                             stack_trace_elem.get()); | 
 | 598 |       } else { | 
 | 599 |         error_msg = "Could not create stack trace."; | 
 | 600 |       } | 
 | 601 |       // Throw the exception. | 
 | 602 |       self->SetException(reinterpret_cast<mirror::Throwable*>(self->DecodeJObject(exc.get()))); | 
 | 603 |     } else { | 
 | 604 |       // Could not allocate a string object. | 
 | 605 |       error_msg = "Couldn't throw new StackOverflowError because JNI NewStringUTF failed."; | 
 | 606 |     } | 
 | 607 |   } else { | 
 | 608 |     error_msg = "Could not allocate StackOverflowError object."; | 
 | 609 |   } | 
 | 610 |  | 
 | 611 |   if (!error_msg.empty()) { | 
 | 612 |     LOG(WARNING) << error_msg; | 
 | 613 |     CHECK(self->IsExceptionPending()); | 
 | 614 |   } | 
 | 615 |  | 
 | 616 |   bool explicit_overflow_check = Runtime::Current()->ExplicitStackOverflowChecks(); | 
 | 617 |   self->ResetDefaultStackEnd();  // Return to default stack size. | 
 | 618 |  | 
 | 619 |   // And restore protection if implicit checks are on. | 
 | 620 |   if (!explicit_overflow_check) { | 
 | 621 |     self->ProtectStack(); | 
 | 622 |   } | 
 | 623 | } | 
 | 624 |  | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 625 | // VerifyError | 
 | 626 |  | 
| Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 627 | void ThrowVerifyError(mirror::Class* referrer, const char* fmt, ...) { | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 628 |   va_list args; | 
 | 629 |   va_start(args, fmt); | 
| Nicolas Geoffray | 0aa50ce | 2015-03-10 11:03:29 +0000 | [diff] [blame] | 630 |   ThrowException("Ljava/lang/VerifyError;", referrer, fmt, &args); | 
| Ian Rogers | 62d6c77 | 2013-02-27 08:32:07 -0800 | [diff] [blame] | 631 |   va_end(args); | 
| Ian Rogers | 87e552d | 2012-08-31 15:54:48 -0700 | [diff] [blame] | 632 | } | 
 | 633 |  | 
 | 634 | }  // namespace art |