| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -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 | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -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 |  | 
 | 17 | #include "runtime_support.h" | 
 | 18 |  | 
| TDYa127 | 5bb8601 | 2012-04-11 05:57:28 -0700 | [diff] [blame] | 19 | #include "ScopedLocalRef.h" | 
 | 20 |  | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 21 | namespace art { | 
 | 22 |  | 
| Ian Rogers | 776ac1f | 2012-04-13 23:36:36 -0700 | [diff] [blame^] | 23 | /* | 
 | 24 |  * Float/double conversion requires clamping to min and max of integer form.  If | 
 | 25 |  * target doesn't support this normally, use these. | 
 | 26 |  */ | 
 | 27 | int64_t D2L(double d) { | 
 | 28 |   static const double kMaxLong = (double) (int64_t) 0x7fffffffffffffffULL; | 
 | 29 |   static const double kMinLong = (double) (int64_t) 0x8000000000000000ULL; | 
 | 30 |   if (d >= kMaxLong) { | 
 | 31 |     return (int64_t) 0x7fffffffffffffffULL; | 
 | 32 |   } else if (d <= kMinLong) { | 
 | 33 |     return (int64_t) 0x8000000000000000ULL; | 
 | 34 |   } else if (d != d)  { // NaN case | 
 | 35 |     return 0; | 
 | 36 |   } else { | 
 | 37 |     return (int64_t) d; | 
 | 38 |   } | 
 | 39 | } | 
 | 40 |  | 
 | 41 | int64_t F2L(float f) { | 
 | 42 |   static const float kMaxLong = (float) (int64_t) 0x7fffffffffffffffULL; | 
 | 43 |   static const float kMinLong = (float) (int64_t) 0x8000000000000000ULL; | 
 | 44 |   if (f >= kMaxLong) { | 
 | 45 |     return (int64_t) 0x7fffffffffffffffULL; | 
 | 46 |   } else if (f <= kMinLong) { | 
 | 47 |     return (int64_t) 0x8000000000000000ULL; | 
 | 48 |   } else if (f != f) { // NaN case | 
 | 49 |     return 0; | 
 | 50 |   } else { | 
 | 51 |     return (int64_t) f; | 
 | 52 |   } | 
 | 53 | } | 
 | 54 |  | 
 | 55 | int32_t D2I(double d) { | 
 | 56 |   static const double kMaxInt = (double) (int32_t) 0x7fffffffUL; | 
 | 57 |   static const double kMinInt = (double) (int32_t) 0x80000000UL; | 
 | 58 |   if (d >= kMaxInt) { | 
 | 59 |     return (int32_t) 0x7fffffffUL; | 
 | 60 |   } else if (d <= kMinInt) { | 
 | 61 |     return (int32_t) 0x80000000UL; | 
 | 62 |   } else if (d != d)  { // NaN case | 
 | 63 |     return 0; | 
 | 64 |   } else { | 
 | 65 |     return (int32_t) d; | 
 | 66 |   } | 
 | 67 | } | 
 | 68 |  | 
 | 69 | int32_t F2I(float f) { | 
 | 70 |   static const float kMaxInt = (float) (int32_t) 0x7fffffffUL; | 
 | 71 |   static const float kMinInt = (float) (int32_t) 0x80000000UL; | 
 | 72 |   if (f >= kMaxInt) { | 
 | 73 |     return (int32_t) 0x7fffffffUL; | 
 | 74 |   } else if (f <= kMinInt) { | 
 | 75 |     return (int32_t) 0x80000000UL; | 
 | 76 |   } else if (f != f) { // NaN case | 
 | 77 |     return 0; | 
 | 78 |   } else { | 
 | 79 |     return (int32_t) f; | 
 | 80 |   } | 
 | 81 | } | 
 | 82 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 83 | void ThrowNewIllegalAccessErrorClass(Thread* self, | 
 | 84 |                                      Class* referrer, | 
 | 85 |                                      Class* accessed) { | 
 | 86 |   self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;", | 
 | 87 |                            "illegal class access: '%s' -> '%s'", | 
 | 88 |                            PrettyDescriptor(referrer).c_str(), | 
 | 89 |                            PrettyDescriptor(accessed).c_str()); | 
| Shih-wei Liao | ddbd01a | 2012-03-09 14:42:12 -0800 | [diff] [blame] | 90 | } | 
 | 91 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 92 | void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self, | 
 | 93 |                                                       Class* referrer, | 
 | 94 |                                                       Class* accessed, | 
 | 95 |                                                       const Method* caller, | 
 | 96 |                                                       const Method* called, | 
 | 97 |                                                       InvokeType type) { | 
 | 98 |   std::ostringstream type_stream; | 
 | 99 |   type_stream << type; | 
 | 100 |   self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;", | 
 | 101 |                            "illegal class access ('%s' -> '%s')" | 
 | 102 |                            "in attempt to invoke %s method '%s' from '%s'", | 
 | 103 |                            PrettyDescriptor(referrer).c_str(), | 
 | 104 |                            PrettyDescriptor(accessed).c_str(), | 
 | 105 |                            type_stream.str().c_str(), | 
 | 106 |                            PrettyMethod(called).c_str(), | 
 | 107 |                            PrettyMethod(caller).c_str()); | 
| buzbee | 44b412b | 2012-02-04 08:50:53 -0800 | [diff] [blame] | 108 | } | 
 | 109 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 110 | void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self, | 
 | 111 |                                                                    const Method* referrer, | 
 | 112 |                                                                    const Method* interface_method, | 
 | 113 |                                                                    Object* this_object) { | 
 | 114 |   self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;", | 
 | 115 |                            "class '%s' does not implement interface '%s' in call to '%s' from '%s'", | 
 | 116 |                            PrettyDescriptor(this_object->GetClass()).c_str(), | 
 | 117 |                            PrettyDescriptor(interface_method->GetDeclaringClass()).c_str(), | 
 | 118 |                            PrettyMethod(interface_method).c_str(), PrettyMethod(referrer).c_str()); | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 119 | } | 
 | 120 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 121 | void ThrowNewIllegalAccessErrorField(Thread* self, | 
 | 122 |                                      Class* referrer, | 
 | 123 |                                      Field* accessed) { | 
 | 124 |   self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;", | 
 | 125 |                            "Field '%s' is inaccessible to class '%s'", | 
 | 126 |                            PrettyField(accessed, false).c_str(), | 
 | 127 |                            PrettyDescriptor(referrer).c_str()); | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 128 | } | 
 | 129 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 130 | void ThrowNewIllegalAccessErrorFinalField(Thread* self, | 
 | 131 |                                           const Method* referrer, | 
 | 132 |                                           Field* accessed) { | 
 | 133 |   self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;", | 
 | 134 |                            "Final field '%s' cannot be written to by method '%s'", | 
 | 135 |                            PrettyField(accessed, false).c_str(), | 
 | 136 |                            PrettyMethod(referrer).c_str()); | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 137 | } | 
 | 138 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 139 | void ThrowNewIllegalAccessErrorMethod(Thread* self, | 
 | 140 |                                       Class* referrer, | 
 | 141 |                                       Method* accessed) { | 
 | 142 |   self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;", | 
 | 143 |                            "Method '%s' is inaccessible to class '%s'", | 
 | 144 |                            PrettyMethod(accessed).c_str(), | 
 | 145 |                            PrettyDescriptor(referrer).c_str()); | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 146 | } | 
 | 147 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 148 | void ThrowNullPointerExceptionForFieldAccess(Thread* self, | 
 | 149 |                                                            Field* field, | 
 | 150 |                                                            bool is_read) { | 
 | 151 |   self->ThrowNewExceptionF("Ljava/lang/NullPointerException;", | 
 | 152 |                            "Attempt to %s field '%s' on a null object reference", | 
 | 153 |                            is_read ? "read from" : "write to", | 
 | 154 |                            PrettyField(field, true).c_str()); | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 155 | } | 
 | 156 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 157 | void ThrowNullPointerExceptionForMethodAccess(Thread* self, | 
 | 158 |                                               Method* caller, | 
 | 159 |                                               uint32_t method_idx, | 
 | 160 |                                               InvokeType type) { | 
 | 161 |   const DexFile& dex_file = | 
 | 162 |       Runtime::Current()->GetClassLinker()->FindDexFile(caller->GetDeclaringClass()->GetDexCache()); | 
 | 163 |   std::ostringstream type_stream; | 
 | 164 |   type_stream << type; | 
 | 165 |   self->ThrowNewExceptionF("Ljava/lang/NullPointerException;", | 
 | 166 |                            "Attempt to invoke %s method '%s' on a null object reference", | 
 | 167 |                            type_stream.str().c_str(), | 
 | 168 |                            PrettyMethod(method_idx, dex_file, true).c_str()); | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 169 | } | 
 | 170 |  | 
| TDYa127 | 3f9137d | 2012-04-08 15:59:19 -0700 | [diff] [blame] | 171 | void ThrowNullPointerExceptionFromDexPC(Thread* self, Method* throw_method, uint32_t dex_pc) { | 
 | 172 |   const DexFile::CodeItem* code = MethodHelper(throw_method).GetCodeItem(); | 
 | 173 |   CHECK_LT(dex_pc, code->insns_size_in_code_units_); | 
 | 174 |   const Instruction* instr = Instruction::At(&code->insns_[dex_pc]); | 
 | 175 |   DecodedInstruction dec_insn(instr); | 
 | 176 |   switch (instr->Opcode()) { | 
 | 177 |     case Instruction::INVOKE_DIRECT: | 
 | 178 |     case Instruction::INVOKE_DIRECT_RANGE: | 
 | 179 |       ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kDirect); | 
 | 180 |       break; | 
 | 181 |     case Instruction::INVOKE_VIRTUAL: | 
 | 182 |     case Instruction::INVOKE_VIRTUAL_RANGE: | 
 | 183 |       ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kVirtual); | 
 | 184 |       break; | 
 | 185 |     case Instruction::IGET: | 
 | 186 |     case Instruction::IGET_WIDE: | 
 | 187 |     case Instruction::IGET_OBJECT: | 
 | 188 |     case Instruction::IGET_BOOLEAN: | 
 | 189 |     case Instruction::IGET_BYTE: | 
 | 190 |     case Instruction::IGET_CHAR: | 
 | 191 |     case Instruction::IGET_SHORT: { | 
 | 192 |       Field* field = | 
 | 193 |           Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false); | 
 | 194 |       ThrowNullPointerExceptionForFieldAccess(self, field, true /* read */); | 
 | 195 |       break; | 
 | 196 |     } | 
 | 197 |     case Instruction::IPUT: | 
 | 198 |     case Instruction::IPUT_WIDE: | 
 | 199 |     case Instruction::IPUT_OBJECT: | 
 | 200 |     case Instruction::IPUT_BOOLEAN: | 
 | 201 |     case Instruction::IPUT_BYTE: | 
 | 202 |     case Instruction::IPUT_CHAR: | 
 | 203 |     case Instruction::IPUT_SHORT: { | 
 | 204 |       Field* field = | 
 | 205 |           Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false); | 
 | 206 |       ThrowNullPointerExceptionForFieldAccess(self, field, false /* write */); | 
 | 207 |       break; | 
 | 208 |     } | 
 | 209 |     case Instruction::AGET: | 
 | 210 |     case Instruction::AGET_WIDE: | 
 | 211 |     case Instruction::AGET_OBJECT: | 
 | 212 |     case Instruction::AGET_BOOLEAN: | 
 | 213 |     case Instruction::AGET_BYTE: | 
 | 214 |     case Instruction::AGET_CHAR: | 
 | 215 |     case Instruction::AGET_SHORT: | 
 | 216 |       self->ThrowNewException("Ljava/lang/NullPointerException;", | 
 | 217 |                               "Attempt to read from null array"); | 
 | 218 |       break; | 
 | 219 |     case Instruction::APUT: | 
 | 220 |     case Instruction::APUT_WIDE: | 
 | 221 |     case Instruction::APUT_OBJECT: | 
 | 222 |     case Instruction::APUT_BOOLEAN: | 
 | 223 |     case Instruction::APUT_BYTE: | 
 | 224 |     case Instruction::APUT_CHAR: | 
 | 225 |     case Instruction::APUT_SHORT: | 
 | 226 |       self->ThrowNewException("Ljava/lang/NullPointerException;", | 
 | 227 |                               "Attempt to write to null array"); | 
 | 228 |       break; | 
 | 229 |     default: { | 
 | 230 |       const DexFile& dex_file = Runtime::Current()->GetClassLinker() | 
 | 231 |           ->FindDexFile(throw_method->GetDeclaringClass()->GetDexCache()); | 
 | 232 |       std::string message("Null pointer exception during instruction '"); | 
 | 233 |       message += instr->DumpString(&dex_file); | 
 | 234 |       message += "'"; | 
 | 235 |       self->ThrowNewException("Ljava/lang/NullPointerException;", message.c_str()); | 
 | 236 |       break; | 
 | 237 |     } | 
 | 238 |   } | 
 | 239 | } | 
 | 240 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 241 | std::string FieldNameFromIndex(const Method* method, uint32_t ref, | 
 | 242 |                                verifier::VerifyErrorRefType ref_type, bool access) { | 
| Ian Rogers | d81871c | 2011-10-03 13:57:23 -0700 | [diff] [blame] | 243 |   CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_FIELD)); | 
| Elliott Hughes | 6c8867d | 2011-10-03 16:34:05 -0700 | [diff] [blame] | 244 |  | 
 | 245 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 246 |   const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache()); | 
 | 247 |  | 
 | 248 |   const DexFile::FieldId& id = dex_file.GetFieldId(ref); | 
| Brian Carlstrom | 6b4ef02 | 2011-10-23 14:59:04 -0700 | [diff] [blame] | 249 |   std::string class_name(PrettyDescriptor(dex_file.GetFieldDeclaringClassDescriptor(id))); | 
| Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 250 |   const char* field_name = dex_file.StringDataByIdx(id.name_idx_); | 
| Elliott Hughes | 6c8867d | 2011-10-03 16:34:05 -0700 | [diff] [blame] | 251 |   if (!access) { | 
 | 252 |     return class_name + "." + field_name; | 
 | 253 |   } | 
 | 254 |  | 
 | 255 |   std::string result; | 
 | 256 |   result += "tried to access field "; | 
 | 257 |   result += class_name + "." + field_name; | 
 | 258 |   result += " from class "; | 
| Ian Rogers | 6d4d9fc | 2011-11-30 16:24:48 -0800 | [diff] [blame] | 259 |   result += PrettyDescriptor(method->GetDeclaringClass()); | 
| Elliott Hughes | 6c8867d | 2011-10-03 16:34:05 -0700 | [diff] [blame] | 260 |   return result; | 
 | 261 | } | 
 | 262 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 263 | std::string MethodNameFromIndex(const Method* method, uint32_t ref, | 
 | 264 |                                 verifier::VerifyErrorRefType ref_type, bool access) { | 
| Ian Rogers | d81871c | 2011-10-03 13:57:23 -0700 | [diff] [blame] | 265 |   CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_METHOD)); | 
| Elliott Hughes | 6c8867d | 2011-10-03 16:34:05 -0700 | [diff] [blame] | 266 |  | 
 | 267 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 268 |   const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache()); | 
 | 269 |  | 
 | 270 |   const DexFile::MethodId& id = dex_file.GetMethodId(ref); | 
| Brian Carlstrom | 6b4ef02 | 2011-10-23 14:59:04 -0700 | [diff] [blame] | 271 |   std::string class_name(PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(id))); | 
| Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 272 |   const char* method_name = dex_file.StringDataByIdx(id.name_idx_); | 
| Elliott Hughes | 6c8867d | 2011-10-03 16:34:05 -0700 | [diff] [blame] | 273 |   if (!access) { | 
 | 274 |     return class_name + "." + method_name; | 
 | 275 |   } | 
 | 276 |  | 
 | 277 |   std::string result; | 
 | 278 |   result += "tried to access method "; | 
| Ian Rogers | 4f0d07c | 2011-10-06 23:38:47 -0700 | [diff] [blame] | 279 |   result += class_name + "." + method_name + ":" + | 
| Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 280 |       dex_file.CreateMethodSignature(id.proto_idx_, NULL); | 
| Elliott Hughes | 6c8867d | 2011-10-03 16:34:05 -0700 | [diff] [blame] | 281 |   result += " from class "; | 
| Ian Rogers | 6d4d9fc | 2011-11-30 16:24:48 -0800 | [diff] [blame] | 282 |   result += PrettyDescriptor(method->GetDeclaringClass()); | 
| Elliott Hughes | 6c8867d | 2011-10-03 16:34:05 -0700 | [diff] [blame] | 283 |   return result; | 
 | 284 | } | 
 | 285 |  | 
| TDYa127 | b92bcab | 2012-04-08 00:09:51 -0700 | [diff] [blame] | 286 | static std::string ClassNameFromIndex(const Method* method, uint32_t ref, | 
 | 287 |                                       verifier::VerifyErrorRefType ref_type, bool access) { | 
| Logan Chien | 9e5f5c1 | 2012-04-10 13:51:45 +0800 | [diff] [blame] | 288 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 289 |   const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache()); | 
 | 290 |  | 
 | 291 |   uint16_t type_idx = 0; | 
 | 292 |   if (ref_type == verifier::VERIFY_ERROR_REF_FIELD) { | 
 | 293 |     const DexFile::FieldId& id = dex_file.GetFieldId(ref); | 
 | 294 |     type_idx = id.class_idx_; | 
 | 295 |   } else if (ref_type == verifier::VERIFY_ERROR_REF_METHOD) { | 
 | 296 |     const DexFile::MethodId& id = dex_file.GetMethodId(ref); | 
 | 297 |     type_idx = id.class_idx_; | 
 | 298 |   } else if (ref_type == verifier::VERIFY_ERROR_REF_CLASS) { | 
 | 299 |     type_idx = ref; | 
 | 300 |   } else { | 
 | 301 |     CHECK(false) << static_cast<int>(ref_type); | 
 | 302 |   } | 
 | 303 |  | 
 | 304 |   std::string class_name(PrettyDescriptor(dex_file.StringByTypeIdx(type_idx))); | 
 | 305 |   if (!access) { | 
 | 306 |     return class_name; | 
 | 307 |   } | 
 | 308 |  | 
 | 309 |   std::string result; | 
 | 310 |   result += "tried to access class "; | 
 | 311 |   result += class_name; | 
 | 312 |   result += " from class "; | 
 | 313 |   result += PrettyDescriptor(method->GetDeclaringClass()); | 
 | 314 |   return result; | 
 | 315 | } | 
 | 316 |  | 
 | 317 | void ThrowVerificationError(Thread* self, const Method* method, | 
 | 318 |                             int32_t kind, int32_t ref) { | 
 | 319 |   verifier::VerifyErrorRefType ref_type = | 
 | 320 |       static_cast<verifier::VerifyErrorRefType>(kind >> verifier::kVerifyErrorRefTypeShift); | 
 | 321 |  | 
 | 322 |   const char* exception_class = "Ljava/lang/VerifyError;"; | 
 | 323 |   std::string msg; | 
 | 324 |  | 
 | 325 |   switch (static_cast<verifier::VerifyError>(kind & ~(0xff << verifier::kVerifyErrorRefTypeShift))) { | 
 | 326 |   case verifier::VERIFY_ERROR_NO_CLASS: | 
 | 327 |     exception_class = "Ljava/lang/NoClassDefFoundError;"; | 
 | 328 |     msg = ClassNameFromIndex(method, ref, ref_type, false); | 
 | 329 |     break; | 
 | 330 |   case verifier::VERIFY_ERROR_NO_FIELD: | 
 | 331 |     exception_class = "Ljava/lang/NoSuchFieldError;"; | 
 | 332 |     msg = FieldNameFromIndex(method, ref, ref_type, false); | 
 | 333 |     break; | 
 | 334 |   case verifier::VERIFY_ERROR_NO_METHOD: | 
 | 335 |     exception_class = "Ljava/lang/NoSuchMethodError;"; | 
 | 336 |     msg = MethodNameFromIndex(method, ref, ref_type, false); | 
 | 337 |     break; | 
 | 338 |   case verifier::VERIFY_ERROR_ACCESS_CLASS: | 
 | 339 |     exception_class = "Ljava/lang/IllegalAccessError;"; | 
 | 340 |     msg = ClassNameFromIndex(method, ref, ref_type, true); | 
 | 341 |     break; | 
 | 342 |   case verifier::VERIFY_ERROR_ACCESS_FIELD: | 
 | 343 |     exception_class = "Ljava/lang/IllegalAccessError;"; | 
 | 344 |     msg = FieldNameFromIndex(method, ref, ref_type, true); | 
 | 345 |     break; | 
 | 346 |   case verifier::VERIFY_ERROR_ACCESS_METHOD: | 
 | 347 |     exception_class = "Ljava/lang/IllegalAccessError;"; | 
 | 348 |     msg = MethodNameFromIndex(method, ref, ref_type, true); | 
 | 349 |     break; | 
 | 350 |   case verifier::VERIFY_ERROR_CLASS_CHANGE: | 
 | 351 |     exception_class = "Ljava/lang/IncompatibleClassChangeError;"; | 
 | 352 |     msg = ClassNameFromIndex(method, ref, ref_type, false); | 
 | 353 |     break; | 
 | 354 |   case verifier::VERIFY_ERROR_INSTANTIATION: | 
 | 355 |     exception_class = "Ljava/lang/InstantiationError;"; | 
 | 356 |     msg = ClassNameFromIndex(method, ref, ref_type, false); | 
 | 357 |     break; | 
 | 358 |   case verifier::VERIFY_ERROR_BAD_CLASS_SOFT: | 
 | 359 |   case verifier::VERIFY_ERROR_BAD_CLASS_HARD: | 
 | 360 |     // Generic VerifyError; use default exception, no message. | 
 | 361 |     break; | 
 | 362 |   case verifier::VERIFY_ERROR_NONE: | 
 | 363 |     CHECK(false); | 
 | 364 |     break; | 
 | 365 |   } | 
 | 366 |  | 
 | 367 |   self->ThrowNewException(exception_class, msg.c_str()); | 
 | 368 | } | 
 | 369 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 370 | // Helper function to allocate array for FILLED_NEW_ARRAY. | 
 | 371 | Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count, | 
 | 372 |                                   Thread* self, bool access_check) { | 
 | 373 |   if (UNLIKELY(component_count < 0)) { | 
 | 374 |     self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count); | 
 | 375 |     return NULL;  // Failure | 
| Elliott Hughes | 6c8867d | 2011-10-03 16:34:05 -0700 | [diff] [blame] | 376 |   } | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 377 |   Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx); | 
 | 378 |   if (UNLIKELY(klass == NULL)) {  // Not in dex cache so try to resolve | 
 | 379 |     klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method); | 
 | 380 |     if (klass == NULL) {  // Error | 
 | 381 |       DCHECK(Thread::Current()->IsExceptionPending()); | 
 | 382 |       return NULL;  // Failure | 
| Ian Rogers | 1984651 | 2012-02-24 11:42:47 -0800 | [diff] [blame] | 383 |     } | 
| Ian Rogers | ea2a11d | 2011-10-11 16:48:51 -0700 | [diff] [blame] | 384 |   } | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 385 |   if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) { | 
 | 386 |     if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) { | 
 | 387 |       Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", | 
 | 388 |                                             "Bad filled array request for type %s", | 
 | 389 |                                             PrettyDescriptor(klass).c_str()); | 
| Ian Rogers | 573db4a | 2011-12-13 15:30:50 -0800 | [diff] [blame] | 390 |     } else { | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 391 |       Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;", | 
 | 392 |                                             "Found type %s; filled-new-array not implemented for anything but \'int\'", | 
 | 393 |                                             PrettyDescriptor(klass).c_str()); | 
| Ian Rogers | 573db4a | 2011-12-13 15:30:50 -0800 | [diff] [blame] | 394 |     } | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 395 |     return NULL;  // Failure | 
| Ian Rogers | ad25ac5 | 2011-10-04 19:13:33 -0700 | [diff] [blame] | 396 |   } else { | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 397 |     if (access_check) { | 
 | 398 |       Class* referrer = method->GetDeclaringClass(); | 
 | 399 |       if (UNLIKELY(!referrer->CanAccess(klass))) { | 
 | 400 |         ThrowNewIllegalAccessErrorClass(self, referrer, klass); | 
 | 401 |         return NULL;  // Failure | 
 | 402 |       } | 
| Ian Rogers | 60db5ab | 2012-02-20 17:02:00 -0800 | [diff] [blame] | 403 |     } | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 404 |     DCHECK(klass->IsArrayClass()) << PrettyClass(klass); | 
 | 405 |     return Array::Alloc(klass, component_count); | 
 | 406 |   } | 
 | 407 | } | 
 | 408 |  | 
 | 409 | // Slow path field resolution and declaring class initialization | 
 | 410 | Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self, | 
 | 411 |                          bool is_static, bool is_primitive, bool is_set, size_t expected_size) { | 
 | 412 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 413 |   Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static); | 
 | 414 |   if (UNLIKELY(resolved_field == NULL)) { | 
 | 415 |     DCHECK(self->IsExceptionPending());  // Throw exception and unwind | 
 | 416 |     return NULL;  // failure | 
 | 417 |   } else { | 
 | 418 |     Class* fields_class = resolved_field->GetDeclaringClass(); | 
 | 419 |     Class* referring_class = referrer->GetDeclaringClass(); | 
| Ian Rogers | e2645d3 | 2012-04-11 14:42:42 -0700 | [diff] [blame] | 420 |     if (UNLIKELY(!referring_class->CanAccess(fields_class) || | 
 | 421 |                  !referring_class->CanAccessMember(fields_class, | 
 | 422 |                                                    resolved_field->GetAccessFlags()))) { | 
 | 423 |       // The referring class can't access the resolved field, this may occur as a result of a | 
 | 424 |       // protected field being made public by a sub-class. Resort to the dex file to determine | 
 | 425 |       // the correct class for the access check. | 
 | 426 |       const DexFile& dex_file = class_linker->FindDexFile(referring_class->GetDexCache()); | 
 | 427 |       fields_class = class_linker->ResolveType(dex_file, | 
 | 428 |                                                dex_file.GetFieldId(field_idx).class_idx_, | 
 | 429 |                                                referring_class); | 
 | 430 |       if (UNLIKELY(!referring_class->CanAccess(fields_class))) { | 
 | 431 |         ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class); | 
 | 432 |         return NULL;  // failure | 
 | 433 |       } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class, | 
 | 434 |                                                             resolved_field->GetAccessFlags()))) { | 
 | 435 |         ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field); | 
 | 436 |         return NULL;  // failure | 
 | 437 |       } | 
 | 438 |     } | 
 | 439 |     if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) { | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 440 |       ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field); | 
 | 441 |       return NULL;  // failure | 
 | 442 |     } else { | 
 | 443 |       FieldHelper fh(resolved_field); | 
 | 444 |       if (UNLIKELY(fh.IsPrimitiveType() != is_primitive || | 
 | 445 |                    fh.FieldSize() != expected_size)) { | 
 | 446 |         self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;", | 
 | 447 |                                  "Attempted read of %zd-bit %s on field '%s'", | 
 | 448 |                                  expected_size * (32 / sizeof(int32_t)), | 
 | 449 |                                  is_primitive ? "primitive" : "non-primitive", | 
 | 450 |                                  PrettyField(resolved_field, true).c_str()); | 
 | 451 |         return NULL;  // failure | 
 | 452 |       } else if (!is_static) { | 
 | 453 |         // instance fields must be being accessed on an initialized class | 
 | 454 |         return resolved_field; | 
| Ian Rogers | 60db5ab | 2012-02-20 17:02:00 -0800 | [diff] [blame] | 455 |       } else { | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 456 |         // If the class is already initializing, we must be inside <clinit>, or | 
 | 457 |         // we'd still be waiting for the lock. | 
 | 458 |         if (fields_class->IsInitializing()) { | 
 | 459 |           return resolved_field; | 
| Ian Rogers | 0045a29 | 2012-03-31 21:08:41 -0700 | [diff] [blame] | 460 |         } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) { | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 461 |           return resolved_field; | 
| Ian Rogers | 60db5ab | 2012-02-20 17:02:00 -0800 | [diff] [blame] | 462 |         } else { | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 463 |           DCHECK(self->IsExceptionPending());  // Throw exception and unwind | 
 | 464 |           return NULL;  // failure | 
| Ian Rogers | 60db5ab | 2012-02-20 17:02:00 -0800 | [diff] [blame] | 465 |         } | 
 | 466 |       } | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 467 |     } | 
 | 468 |   } | 
 | 469 | } | 
 | 470 |  | 
 | 471 | // Slow path method resolution | 
 | 472 | Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer, | 
 | 473 |                            Thread* self, bool access_check, InvokeType type) { | 
 | 474 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 475 |   bool is_direct = type == kStatic || type == kDirect; | 
 | 476 |   Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, is_direct); | 
 | 477 |   if (UNLIKELY(resolved_method == NULL)) { | 
 | 478 |     DCHECK(self->IsExceptionPending());  // Throw exception and unwind | 
 | 479 |     return NULL;  // failure | 
 | 480 |   } else { | 
 | 481 |     if (!access_check) { | 
 | 482 |       if (is_direct) { | 
 | 483 |         return resolved_method; | 
 | 484 |       } else if (type == kInterface) { | 
 | 485 |         Method* interface_method = | 
 | 486 |             this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); | 
 | 487 |         if (UNLIKELY(interface_method == NULL)) { | 
 | 488 |           ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer, | 
 | 489 |                                                                         resolved_method, | 
 | 490 |                                                                         this_object); | 
 | 491 |           return NULL;  // failure | 
 | 492 |         } else { | 
 | 493 |           return interface_method; | 
 | 494 |         } | 
| Ian Rogers | 60db5ab | 2012-02-20 17:02:00 -0800 | [diff] [blame] | 495 |       } else { | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 496 |         ObjectArray<Method>* vtable; | 
 | 497 |         uint16_t vtable_index = resolved_method->GetMethodIndex(); | 
 | 498 |         if (type == kSuper) { | 
 | 499 |           vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable(); | 
 | 500 |         } else { | 
 | 501 |           vtable = this_object->GetClass()->GetVTable(); | 
 | 502 |         } | 
 | 503 |         // TODO: eliminate bounds check? | 
 | 504 |         return vtable->Get(vtable_index); | 
 | 505 |       } | 
 | 506 |     } else { | 
 | 507 |       Class* methods_class = resolved_method->GetDeclaringClass(); | 
 | 508 |       Class* referring_class = referrer->GetDeclaringClass(); | 
 | 509 |       if (UNLIKELY(!referring_class->CanAccess(methods_class) || | 
 | 510 |                    !referring_class->CanAccessMember(methods_class, | 
 | 511 |                                                      resolved_method->GetAccessFlags()))) { | 
 | 512 |         // The referring class can't access the resolved method, this may occur as a result of a | 
 | 513 |         // protected method being made public by implementing an interface that re-declares the | 
 | 514 |         // method public. Resort to the dex file to determine the correct class for the access check | 
 | 515 |         const DexFile& dex_file = class_linker->FindDexFile(referring_class->GetDexCache()); | 
 | 516 |         methods_class = class_linker->ResolveType(dex_file, | 
 | 517 |                                                   dex_file.GetMethodId(method_idx).class_idx_, | 
 | 518 |                                                   referring_class); | 
 | 519 |         if (UNLIKELY(!referring_class->CanAccess(methods_class))) { | 
 | 520 |           ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class, | 
 | 521 |                                                            referrer, resolved_method, type); | 
 | 522 |           return NULL;  // failure | 
 | 523 |         } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class, | 
 | 524 |                                                               resolved_method->GetAccessFlags()))) { | 
 | 525 |           ThrowNewIllegalAccessErrorMethod(self, referring_class, resolved_method); | 
 | 526 |           return NULL;  // failure | 
 | 527 |         } | 
 | 528 |       } | 
 | 529 |       if (is_direct) { | 
 | 530 |         return resolved_method; | 
 | 531 |       } else if (type == kInterface) { | 
 | 532 |         Method* interface_method = | 
 | 533 |             this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); | 
 | 534 |         if (UNLIKELY(interface_method == NULL)) { | 
 | 535 |           ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer, | 
 | 536 |                                                                         resolved_method, | 
 | 537 |                                                                         this_object); | 
 | 538 |           return NULL;  // failure | 
 | 539 |         } else { | 
 | 540 |           return interface_method; | 
 | 541 |         } | 
 | 542 |       } else { | 
 | 543 |         ObjectArray<Method>* vtable; | 
 | 544 |         uint16_t vtable_index = resolved_method->GetMethodIndex(); | 
 | 545 |         if (type == kSuper) { | 
 | 546 |           Class* super_class = referring_class->GetSuperClass(); | 
 | 547 |           if (LIKELY(super_class != NULL)) { | 
 | 548 |             vtable = referring_class->GetSuperClass()->GetVTable(); | 
 | 549 |           } else { | 
 | 550 |             vtable = NULL; | 
 | 551 |           } | 
 | 552 |         } else { | 
 | 553 |           vtable = this_object->GetClass()->GetVTable(); | 
 | 554 |         } | 
 | 555 |         if (LIKELY(vtable != NULL && | 
 | 556 |                    vtable_index < static_cast<uint32_t>(vtable->GetLength()))) { | 
 | 557 |           return vtable->GetWithoutChecks(vtable_index); | 
 | 558 |         } else { | 
 | 559 |           // Behavior to agree with that of the verifier | 
 | 560 |           self->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;", | 
 | 561 |                                    "attempt to invoke %s method '%s' from '%s'" | 
 | 562 |                                    " using incorrect form of method dispatch", | 
 | 563 |                                    (type == kSuper ? "super class" : "virtual"), | 
 | 564 |                                    PrettyMethod(resolved_method).c_str(), | 
 | 565 |                                    PrettyMethod(referrer).c_str()); | 
 | 566 |           return NULL;  // failure | 
 | 567 |         } | 
| Ian Rogers | 60db5ab | 2012-02-20 17:02:00 -0800 | [diff] [blame] | 568 |       } | 
 | 569 |     } | 
 | 570 |   } | 
| Ian Rogers | 60db5ab | 2012-02-20 17:02:00 -0800 | [diff] [blame] | 571 | } | 
 | 572 |  | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 573 | Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self, | 
 | 574 |                                bool can_run_clinit, bool verify_access) { | 
 | 575 |   ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); | 
 | 576 |   Class* klass = class_linker->ResolveType(type_idx, referrer); | 
 | 577 |   if (UNLIKELY(klass == NULL)) { | 
| jeffhao | 441d912 | 2012-03-21 17:29:10 -0700 | [diff] [blame] | 578 |     CHECK(self->IsExceptionPending()); | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 579 |     return NULL;  // Failure - Indicate to caller to deliver exception | 
| jeffhao | 441d912 | 2012-03-21 17:29:10 -0700 | [diff] [blame] | 580 |   } | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 581 |   // Perform access check if necessary. | 
 | 582 |   Class* referring_class = referrer->GetDeclaringClass(); | 
 | 583 |   if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) { | 
 | 584 |     ThrowNewIllegalAccessErrorClass(self, referring_class, klass); | 
 | 585 |     return NULL;  // Failure - Indicate to caller to deliver exception | 
| Ian Rogers | 14b1b24 | 2011-10-11 18:54:34 -0700 | [diff] [blame] | 586 |   } | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 587 |   // If we're just implementing const-class, we shouldn't call <clinit>. | 
 | 588 |   if (!can_run_clinit) { | 
 | 589 |     return klass; | 
| Ian Rogers | dfcdf1a | 2011-10-10 17:50:35 -0700 | [diff] [blame] | 590 |   } | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 591 |   // If we are the <clinit> of this class, just return our storage. | 
 | 592 |   // | 
 | 593 |   // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished | 
 | 594 |   // running. | 
 | 595 |   if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) { | 
 | 596 |     return klass; | 
| Ian Rogers | dfcdf1a | 2011-10-10 17:50:35 -0700 | [diff] [blame] | 597 |   } | 
| Ian Rogers | 0045a29 | 2012-03-31 21:08:41 -0700 | [diff] [blame] | 598 |   if (!class_linker->EnsureInitialized(klass, true, true)) { | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 599 |     CHECK(self->IsExceptionPending()); | 
 | 600 |     return NULL;  // Failure - Indicate to caller to deliver exception | 
| Ian Rogers | dfcdf1a | 2011-10-10 17:50:35 -0700 | [diff] [blame] | 601 |   } | 
| Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 602 |   referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass); | 
 | 603 |   return klass; | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 604 | } | 
 | 605 |  | 
| TDYa127 | 5bb8601 | 2012-04-11 05:57:28 -0700 | [diff] [blame] | 606 | void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) { | 
 | 607 |   ScopedLocalRef<jclass> jlr_UTE_class(env, | 
 | 608 |       env->FindClass("java/lang/reflect/UndeclaredThrowableException")); | 
 | 609 |   if (jlr_UTE_class.get() == NULL) { | 
 | 610 |     LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\""; | 
 | 611 |   } else { | 
 | 612 |     jmethodID jlre_UTE_constructor = env->GetMethodID(jlr_UTE_class.get(), "<init>", | 
 | 613 |                                                       "(Ljava/lang/Throwable;)V"); | 
 | 614 |     jthrowable jexception = AddLocalReference<jthrowable>(env, exception); | 
 | 615 |     ScopedLocalRef<jthrowable> jlr_UTE(env, | 
 | 616 |         reinterpret_cast<jthrowable>(env->NewObject(jlr_UTE_class.get(), jlre_UTE_constructor, | 
 | 617 |                                                     jexception))); | 
 | 618 |     int rc = env->Throw(jlr_UTE.get()); | 
 | 619 |     if (rc != JNI_OK) { | 
 | 620 |       LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\""; | 
 | 621 |     } | 
 | 622 |   } | 
 | 623 |   CHECK(self->IsExceptionPending()); | 
 | 624 | } | 
 | 625 |  | 
| Shih-wei Liao | 2d83101 | 2011-09-28 22:06:53 -0700 | [diff] [blame] | 626 | }  // namespace art |