blob: c5ce4b35088fb78d0ed4ae4f4f90dc1a520994d0 [file] [log] [blame]
Shih-wei Liao2d831012011-09-28 22:06:53 -07001/*
Elliott Hughes0f3c5532012-03-30 14:51:51 -07002 * Copyright (C) 2012 The Android Open Source Project
Shih-wei Liao2d831012011-09-28 22:06:53 -07003 *
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
TDYa1275bb86012012-04-11 05:57:28 -070019#include "ScopedLocalRef.h"
Elliott Hugheseac76672012-05-24 21:56:51 -070020#include "well_known_classes.h"
TDYa1275bb86012012-04-11 05:57:28 -070021
jeffhao41005dd2012-05-09 17:58:52 -070022double art_l2d(int64_t l) {
Elliott Hughes74847412012-06-20 18:10:21 -070023 return static_cast<double>(l);
jeffhao41005dd2012-05-09 17:58:52 -070024}
25
26float art_l2f(int64_t l) {
Elliott Hughes74847412012-06-20 18:10:21 -070027 return static_cast<float>(l);
jeffhao41005dd2012-05-09 17:58:52 -070028}
Shih-wei Liao2d831012011-09-28 22:06:53 -070029
Ian Rogers776ac1f2012-04-13 23:36:36 -070030/*
31 * Float/double conversion requires clamping to min and max of integer form. If
32 * target doesn't support this normally, use these.
33 */
jeffhao41005dd2012-05-09 17:58:52 -070034int64_t art_d2l(double d) {
Elliott Hughes74847412012-06-20 18:10:21 -070035 static const double kMaxLong = static_cast<double>(static_cast<int64_t>(0x7fffffffffffffffULL));
36 static const double kMinLong = static_cast<double>(static_cast<int64_t>(0x8000000000000000ULL));
Ian Rogers776ac1f2012-04-13 23:36:36 -070037 if (d >= kMaxLong) {
Logan Chien008fa512012-06-22 08:09:57 -070038 return static_cast<int64_t>(0x7fffffffffffffffULL);
Ian Rogers776ac1f2012-04-13 23:36:36 -070039 } else if (d <= kMinLong) {
Logan Chien008fa512012-06-22 08:09:57 -070040 return static_cast<int64_t>(0x8000000000000000ULL);
Ian Rogers776ac1f2012-04-13 23:36:36 -070041 } else if (d != d) { // NaN case
42 return 0;
43 } else {
Elliott Hughes74847412012-06-20 18:10:21 -070044 return static_cast<int64_t>(d);
Ian Rogers776ac1f2012-04-13 23:36:36 -070045 }
46}
47
jeffhao41005dd2012-05-09 17:58:52 -070048int64_t art_f2l(float f) {
Elliott Hughes74847412012-06-20 18:10:21 -070049 static const float kMaxLong = static_cast<float>(static_cast<int64_t>(0x7fffffffffffffffULL));
50 static const float kMinLong = static_cast<float>(static_cast<int64_t>(0x8000000000000000ULL));
Ian Rogers776ac1f2012-04-13 23:36:36 -070051 if (f >= kMaxLong) {
Logan Chien008fa512012-06-22 08:09:57 -070052 return static_cast<int64_t>(0x7fffffffffffffffULL);
Ian Rogers776ac1f2012-04-13 23:36:36 -070053 } else if (f <= kMinLong) {
Logan Chien008fa512012-06-22 08:09:57 -070054 return static_cast<int64_t>(0x8000000000000000ULL);
Ian Rogers776ac1f2012-04-13 23:36:36 -070055 } else if (f != f) { // NaN case
56 return 0;
57 } else {
Elliott Hughes74847412012-06-20 18:10:21 -070058 return static_cast<int64_t>(f);
Ian Rogers776ac1f2012-04-13 23:36:36 -070059 }
60}
61
jeffhao41005dd2012-05-09 17:58:52 -070062int32_t art_d2i(double d) {
Logan Chien008fa512012-06-22 08:09:57 -070063 static const double kMaxInt = static_cast<double>(static_cast<int32_t>(0x7fffffffUL));
64 static const double kMinInt = static_cast<double>(static_cast<int32_t>(0x80000000UL));
Ian Rogers776ac1f2012-04-13 23:36:36 -070065 if (d >= kMaxInt) {
Logan Chien008fa512012-06-22 08:09:57 -070066 return static_cast<int32_t>(0x7fffffffUL);
Ian Rogers776ac1f2012-04-13 23:36:36 -070067 } else if (d <= kMinInt) {
Logan Chien008fa512012-06-22 08:09:57 -070068 return static_cast<int32_t>(0x80000000UL);
Ian Rogers776ac1f2012-04-13 23:36:36 -070069 } else if (d != d) { // NaN case
70 return 0;
71 } else {
Elliott Hughes74847412012-06-20 18:10:21 -070072 return static_cast<int32_t>(d);
Ian Rogers776ac1f2012-04-13 23:36:36 -070073 }
74}
75
jeffhao41005dd2012-05-09 17:58:52 -070076int32_t art_f2i(float f) {
Logan Chien008fa512012-06-22 08:09:57 -070077 static const float kMaxInt = static_cast<float>(static_cast<int32_t>(0x7fffffffUL));
78 static const float kMinInt = static_cast<float>(static_cast<int32_t>(0x80000000UL));
Ian Rogers776ac1f2012-04-13 23:36:36 -070079 if (f >= kMaxInt) {
Logan Chien008fa512012-06-22 08:09:57 -070080 return static_cast<int32_t>(0x7fffffffUL);
Ian Rogers776ac1f2012-04-13 23:36:36 -070081 } else if (f <= kMinInt) {
Logan Chien008fa512012-06-22 08:09:57 -070082 return static_cast<int32_t>(0x80000000UL);
Ian Rogers776ac1f2012-04-13 23:36:36 -070083 } else if (f != f) { // NaN case
84 return 0;
85 } else {
Elliott Hughes74847412012-06-20 18:10:21 -070086 return static_cast<int32_t>(f);
Ian Rogers776ac1f2012-04-13 23:36:36 -070087 }
88}
89
jeffhao41005dd2012-05-09 17:58:52 -070090namespace art {
91
Ian Rogers57b86d42012-03-27 16:05:41 -070092void ThrowNewIllegalAccessErrorClass(Thread* self,
93 Class* referrer,
94 Class* accessed) {
95 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
Ian Rogers08f753d2012-08-24 14:35:25 -070096 "Illegal class access: '%s' -> '%s'",
Ian Rogers57b86d42012-03-27 16:05:41 -070097 PrettyDescriptor(referrer).c_str(),
98 PrettyDescriptor(accessed).c_str());
Shih-wei Liaoddbd01a2012-03-09 14:42:12 -080099}
100
Ian Rogers57b86d42012-03-27 16:05:41 -0700101void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self,
102 Class* referrer,
103 Class* accessed,
104 const Method* caller,
105 const Method* called,
106 InvokeType type) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700107 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
Ian Rogers08f753d2012-08-24 14:35:25 -0700108 "Illegal class access ('%s' -> '%s')"
Ian Rogers57b86d42012-03-27 16:05:41 -0700109 "in attempt to invoke %s method '%s' from '%s'",
110 PrettyDescriptor(referrer).c_str(),
111 PrettyDescriptor(accessed).c_str(),
Elliott Hughes6fcce302012-06-19 16:54:19 -0700112 ToStr<InvokeType>(type).c_str(),
Ian Rogers57b86d42012-03-27 16:05:41 -0700113 PrettyMethod(called).c_str(),
114 PrettyMethod(caller).c_str());
buzbee44b412b2012-02-04 08:50:53 -0800115}
116
Ian Rogers08f753d2012-08-24 14:35:25 -0700117static void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
118 const Method* interface_method,
119 Object* this_object)
120 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
121 std::string interface_method_name(PrettyMethod(interface_method));
122 if (this_object != NULL) {
123 std::string this_class_descriptor(PrettyDescriptor(this_object->GetClass()));
124 std::string interface_class_descriptor(PrettyDescriptor(interface_method->GetDeclaringClass()));
125 self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
126 "Class '%s' does not implement interface '%s' in call to '%s'",
127 this_class_descriptor.c_str(),
128 interface_class_descriptor.c_str(),
129 interface_method_name.c_str());
130 } else {
131 self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
132 "Expected '%s' to be an interface method",
133 interface_method_name.c_str());
134 }
135}
136
137static void ThrowNewIncompatibleClassChangeErrorField(Thread* self, const Field* resolved_field,
138 bool is_static)
139 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700140 self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
Ian Rogers08f753d2012-08-24 14:35:25 -0700141 "Expected '%s' to be a %s field",
142 PrettyField(resolved_field).c_str(),
143 is_static ? "static" : "instance");
144}
145
146void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type,
Ian Rogers2fc14272012-08-30 10:56:57 -0700147 Method* method, const Method* referrer) {
Ian Rogers08f753d2012-08-24 14:35:25 -0700148 std::ostringstream msg;
jeffhaoc0228b82012-08-29 18:15:05 -0700149 msg << "The method '" << PrettyMethod(method) << "' was expected to be of type "
Ian Rogers08f753d2012-08-24 14:35:25 -0700150 << expected_type << " but instead was found to be of type " << found_type;
Ian Rogers2fc14272012-08-30 10:56:57 -0700151 ClassHelper kh(referrer->GetDeclaringClass());
Ian Rogers08f753d2012-08-24 14:35:25 -0700152 std::string location(kh.GetLocation());
153 if (!location.empty()) {
154 msg << " (accessed from " << location << ")";
155 }
156 Thread::Current()->ThrowNewException("Ljava/lang/IncompatibleClassChangeError;",
157 msg.str().c_str());
158}
159
160void ThrowNoSuchMethodError(InvokeType type, Class* c, const StringPiece& name,
Ian Rogers2fc14272012-08-30 10:56:57 -0700161 const StringPiece& signature, const Method* referrer) {
Ian Rogers08f753d2012-08-24 14:35:25 -0700162 ClassHelper kh(c);
163 std::ostringstream msg;
164 msg << "No " << type << " method " << name << signature
165 << " in class " << kh.GetDescriptor() << " or its superclasses";
Ian Rogers2fc14272012-08-30 10:56:57 -0700166 kh.ChangeClass(referrer->GetDeclaringClass());
Ian Rogers08f753d2012-08-24 14:35:25 -0700167 std::string location(kh.GetLocation());
168 if (!location.empty()) {
169 msg << " (accessed from " << location << ")";
170 }
171 Thread::Current()->ThrowNewException("Ljava/lang/NoSuchMethodError;", msg.str().c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -0700172}
173
Ian Rogers57b86d42012-03-27 16:05:41 -0700174void ThrowNewIllegalAccessErrorField(Thread* self,
175 Class* referrer,
176 Field* accessed) {
177 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
178 "Field '%s' is inaccessible to class '%s'",
179 PrettyField(accessed, false).c_str(),
180 PrettyDescriptor(referrer).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -0700181}
182
Ian Rogers57b86d42012-03-27 16:05:41 -0700183void ThrowNewIllegalAccessErrorFinalField(Thread* self,
184 const Method* referrer,
185 Field* accessed) {
186 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
187 "Final field '%s' cannot be written to by method '%s'",
188 PrettyField(accessed, false).c_str(),
189 PrettyMethod(referrer).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -0700190}
191
Ian Rogers57b86d42012-03-27 16:05:41 -0700192void ThrowNewIllegalAccessErrorMethod(Thread* self,
193 Class* referrer,
194 Method* accessed) {
195 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
196 "Method '%s' is inaccessible to class '%s'",
197 PrettyMethod(accessed).c_str(),
198 PrettyDescriptor(referrer).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -0700199}
200
Ian Rogers57b86d42012-03-27 16:05:41 -0700201void ThrowNullPointerExceptionForFieldAccess(Thread* self,
202 Field* field,
203 bool is_read) {
204 self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
205 "Attempt to %s field '%s' on a null object reference",
206 is_read ? "read from" : "write to",
207 PrettyField(field, true).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -0700208}
209
Ian Rogers57b86d42012-03-27 16:05:41 -0700210void ThrowNullPointerExceptionForMethodAccess(Thread* self,
211 Method* caller,
212 uint32_t method_idx,
213 InvokeType type) {
214 const DexFile& dex_file =
215 Runtime::Current()->GetClassLinker()->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
Ian Rogers57b86d42012-03-27 16:05:41 -0700216 self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
217 "Attempt to invoke %s method '%s' on a null object reference",
Elliott Hughes6fcce302012-06-19 16:54:19 -0700218 ToStr<InvokeType>(type).c_str(),
Ian Rogers57b86d42012-03-27 16:05:41 -0700219 PrettyMethod(method_idx, dex_file, true).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -0700220}
221
TDYa1273f9137d2012-04-08 15:59:19 -0700222void ThrowNullPointerExceptionFromDexPC(Thread* self, Method* throw_method, uint32_t dex_pc) {
223 const DexFile::CodeItem* code = MethodHelper(throw_method).GetCodeItem();
224 CHECK_LT(dex_pc, code->insns_size_in_code_units_);
225 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
226 DecodedInstruction dec_insn(instr);
227 switch (instr->Opcode()) {
228 case Instruction::INVOKE_DIRECT:
229 case Instruction::INVOKE_DIRECT_RANGE:
230 ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kDirect);
231 break;
232 case Instruction::INVOKE_VIRTUAL:
233 case Instruction::INVOKE_VIRTUAL_RANGE:
234 ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kVirtual);
235 break;
236 case Instruction::IGET:
237 case Instruction::IGET_WIDE:
238 case Instruction::IGET_OBJECT:
239 case Instruction::IGET_BOOLEAN:
240 case Instruction::IGET_BYTE:
241 case Instruction::IGET_CHAR:
242 case Instruction::IGET_SHORT: {
243 Field* field =
244 Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
245 ThrowNullPointerExceptionForFieldAccess(self, field, true /* read */);
246 break;
247 }
248 case Instruction::IPUT:
249 case Instruction::IPUT_WIDE:
250 case Instruction::IPUT_OBJECT:
251 case Instruction::IPUT_BOOLEAN:
252 case Instruction::IPUT_BYTE:
253 case Instruction::IPUT_CHAR:
254 case Instruction::IPUT_SHORT: {
255 Field* field =
256 Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
257 ThrowNullPointerExceptionForFieldAccess(self, field, false /* write */);
258 break;
259 }
260 case Instruction::AGET:
261 case Instruction::AGET_WIDE:
262 case Instruction::AGET_OBJECT:
263 case Instruction::AGET_BOOLEAN:
264 case Instruction::AGET_BYTE:
265 case Instruction::AGET_CHAR:
266 case Instruction::AGET_SHORT:
267 self->ThrowNewException("Ljava/lang/NullPointerException;",
268 "Attempt to read from null array");
269 break;
270 case Instruction::APUT:
271 case Instruction::APUT_WIDE:
272 case Instruction::APUT_OBJECT:
273 case Instruction::APUT_BOOLEAN:
274 case Instruction::APUT_BYTE:
275 case Instruction::APUT_CHAR:
276 case Instruction::APUT_SHORT:
277 self->ThrowNewException("Ljava/lang/NullPointerException;",
278 "Attempt to write to null array");
279 break;
Elliott Hughes6fcce302012-06-19 16:54:19 -0700280 case Instruction::ARRAY_LENGTH:
281 self->ThrowNewException("Ljava/lang/NullPointerException;",
282 "Attempt to get length of null array");
283 break;
TDYa1273f9137d2012-04-08 15:59:19 -0700284 default: {
285 const DexFile& dex_file = Runtime::Current()->GetClassLinker()
286 ->FindDexFile(throw_method->GetDeclaringClass()->GetDexCache());
287 std::string message("Null pointer exception during instruction '");
288 message += instr->DumpString(&dex_file);
289 message += "'";
290 self->ThrowNewException("Ljava/lang/NullPointerException;", message.c_str());
291 break;
292 }
293 }
294}
295
Ian Rogers57b86d42012-03-27 16:05:41 -0700296std::string FieldNameFromIndex(const Method* method, uint32_t ref,
297 verifier::VerifyErrorRefType ref_type, bool access) {
Ian Rogersd81871c2011-10-03 13:57:23 -0700298 CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_FIELD));
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700299
300 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
301 const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
302
303 const DexFile::FieldId& id = dex_file.GetFieldId(ref);
Brian Carlstrom6b4ef022011-10-23 14:59:04 -0700304 std::string class_name(PrettyDescriptor(dex_file.GetFieldDeclaringClassDescriptor(id)));
Ian Rogers0571d352011-11-03 19:51:38 -0700305 const char* field_name = dex_file.StringDataByIdx(id.name_idx_);
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700306 if (!access) {
307 return class_name + "." + field_name;
308 }
309
310 std::string result;
311 result += "tried to access field ";
312 result += class_name + "." + field_name;
313 result += " from class ";
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800314 result += PrettyDescriptor(method->GetDeclaringClass());
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700315 return result;
316}
317
Ian Rogers57b86d42012-03-27 16:05:41 -0700318std::string MethodNameFromIndex(const Method* method, uint32_t ref,
319 verifier::VerifyErrorRefType ref_type, bool access) {
Ian Rogersd81871c2011-10-03 13:57:23 -0700320 CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_METHOD));
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700321
322 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
323 const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
324
325 const DexFile::MethodId& id = dex_file.GetMethodId(ref);
Brian Carlstrom6b4ef022011-10-23 14:59:04 -0700326 std::string class_name(PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(id)));
Ian Rogers0571d352011-11-03 19:51:38 -0700327 const char* method_name = dex_file.StringDataByIdx(id.name_idx_);
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700328 if (!access) {
329 return class_name + "." + method_name;
330 }
331
332 std::string result;
333 result += "tried to access method ";
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700334 result += class_name + "." + method_name + ":" +
Ian Rogers0571d352011-11-03 19:51:38 -0700335 dex_file.CreateMethodSignature(id.proto_idx_, NULL);
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700336 result += " from class ";
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800337 result += PrettyDescriptor(method->GetDeclaringClass());
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700338 return result;
339}
340
TDYa127b92bcab2012-04-08 00:09:51 -0700341static std::string ClassNameFromIndex(const Method* method, uint32_t ref,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700342 verifier::VerifyErrorRefType ref_type, bool access)
343 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
Logan Chien9e5f5c12012-04-10 13:51:45 +0800344 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
345 const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
346
347 uint16_t type_idx = 0;
348 if (ref_type == verifier::VERIFY_ERROR_REF_FIELD) {
349 const DexFile::FieldId& id = dex_file.GetFieldId(ref);
350 type_idx = id.class_idx_;
351 } else if (ref_type == verifier::VERIFY_ERROR_REF_METHOD) {
352 const DexFile::MethodId& id = dex_file.GetMethodId(ref);
353 type_idx = id.class_idx_;
354 } else if (ref_type == verifier::VERIFY_ERROR_REF_CLASS) {
355 type_idx = ref;
356 } else {
357 CHECK(false) << static_cast<int>(ref_type);
358 }
359
360 std::string class_name(PrettyDescriptor(dex_file.StringByTypeIdx(type_idx)));
361 if (!access) {
362 return class_name;
363 }
364
365 std::string result;
366 result += "tried to access class ";
367 result += class_name;
368 result += " from class ";
369 result += PrettyDescriptor(method->GetDeclaringClass());
370 return result;
371}
372
373void ThrowVerificationError(Thread* self, const Method* method,
374 int32_t kind, int32_t ref) {
375 verifier::VerifyErrorRefType ref_type =
376 static_cast<verifier::VerifyErrorRefType>(kind >> verifier::kVerifyErrorRefTypeShift);
377
378 const char* exception_class = "Ljava/lang/VerifyError;";
379 std::string msg;
380
381 switch (static_cast<verifier::VerifyError>(kind & ~(0xff << verifier::kVerifyErrorRefTypeShift))) {
382 case verifier::VERIFY_ERROR_NO_CLASS:
383 exception_class = "Ljava/lang/NoClassDefFoundError;";
384 msg = ClassNameFromIndex(method, ref, ref_type, false);
385 break;
386 case verifier::VERIFY_ERROR_NO_FIELD:
387 exception_class = "Ljava/lang/NoSuchFieldError;";
388 msg = FieldNameFromIndex(method, ref, ref_type, false);
389 break;
390 case verifier::VERIFY_ERROR_NO_METHOD:
391 exception_class = "Ljava/lang/NoSuchMethodError;";
392 msg = MethodNameFromIndex(method, ref, ref_type, false);
393 break;
394 case verifier::VERIFY_ERROR_ACCESS_CLASS:
395 exception_class = "Ljava/lang/IllegalAccessError;";
396 msg = ClassNameFromIndex(method, ref, ref_type, true);
397 break;
398 case verifier::VERIFY_ERROR_ACCESS_FIELD:
399 exception_class = "Ljava/lang/IllegalAccessError;";
400 msg = FieldNameFromIndex(method, ref, ref_type, true);
401 break;
402 case verifier::VERIFY_ERROR_ACCESS_METHOD:
403 exception_class = "Ljava/lang/IllegalAccessError;";
404 msg = MethodNameFromIndex(method, ref, ref_type, true);
405 break;
406 case verifier::VERIFY_ERROR_CLASS_CHANGE:
407 exception_class = "Ljava/lang/IncompatibleClassChangeError;";
408 msg = ClassNameFromIndex(method, ref, ref_type, false);
409 break;
410 case verifier::VERIFY_ERROR_INSTANTIATION:
411 exception_class = "Ljava/lang/InstantiationError;";
412 msg = ClassNameFromIndex(method, ref, ref_type, false);
413 break;
414 case verifier::VERIFY_ERROR_BAD_CLASS_SOFT:
415 case verifier::VERIFY_ERROR_BAD_CLASS_HARD:
416 // Generic VerifyError; use default exception, no message.
417 break;
Logan Chien9e5f5c12012-04-10 13:51:45 +0800418 }
419
420 self->ThrowNewException(exception_class, msg.c_str());
421}
422
Ian Rogers57b86d42012-03-27 16:05:41 -0700423// Helper function to allocate array for FILLED_NEW_ARRAY.
424Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
425 Thread* self, bool access_check) {
426 if (UNLIKELY(component_count < 0)) {
427 self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
428 return NULL; // Failure
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700429 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700430 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
431 if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
432 klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
433 if (klass == NULL) { // Error
434 DCHECK(Thread::Current()->IsExceptionPending());
435 return NULL; // Failure
Ian Rogers19846512012-02-24 11:42:47 -0800436 }
Ian Rogersea2a11d2011-10-11 16:48:51 -0700437 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700438 if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) {
439 if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
440 Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
441 "Bad filled array request for type %s",
442 PrettyDescriptor(klass).c_str());
Ian Rogers573db4a2011-12-13 15:30:50 -0800443 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700444 Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;",
445 "Found type %s; filled-new-array not implemented for anything but \'int\'",
446 PrettyDescriptor(klass).c_str());
Ian Rogers573db4a2011-12-13 15:30:50 -0800447 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700448 return NULL; // Failure
Ian Rogersad25ac52011-10-04 19:13:33 -0700449 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700450 if (access_check) {
451 Class* referrer = method->GetDeclaringClass();
452 if (UNLIKELY(!referrer->CanAccess(klass))) {
453 ThrowNewIllegalAccessErrorClass(self, referrer, klass);
454 return NULL; // Failure
455 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800456 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700457 DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
458 return Array::Alloc(klass, component_count);
459 }
460}
461
Ian Rogers57b86d42012-03-27 16:05:41 -0700462Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
Ian Rogers08f753d2012-08-24 14:35:25 -0700463 FindFieldType type, size_t expected_size) {
464 bool is_primitive;
465 bool is_set;
466 bool is_static;
467 switch (type) {
468 case InstanceObjectRead: is_primitive = false; is_set = false; is_static = false; break;
469 case InstanceObjectWrite: is_primitive = false; is_set = true; is_static = false; break;
470 case InstancePrimitiveRead: is_primitive = true; is_set = false; is_static = false; break;
471 case InstancePrimitiveWrite: is_primitive = true; is_set = true; is_static = false; break;
472 case StaticObjectRead: is_primitive = false; is_set = false; is_static = true; break;
473 case StaticObjectWrite: is_primitive = false; is_set = true; is_static = true; break;
474 case StaticPrimitiveRead: is_primitive = true; is_set = false; is_static = true; break;
475 case StaticPrimitiveWrite: // Keep GCC happy by having a default handler, fall-through.
476 default: is_primitive = true; is_set = true; is_static = true; break;
477 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700478 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
479 Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
480 if (UNLIKELY(resolved_field == NULL)) {
Ian Rogers08f753d2012-08-24 14:35:25 -0700481 DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
482 return NULL; // Failure.
Ian Rogers57b86d42012-03-27 16:05:41 -0700483 } else {
Ian Rogers08f753d2012-08-24 14:35:25 -0700484 if (resolved_field->IsStatic() != is_static) {
485 ThrowNewIncompatibleClassChangeErrorField(self, resolved_field, is_static);
486 return NULL;
487 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700488 Class* fields_class = resolved_field->GetDeclaringClass();
489 Class* referring_class = referrer->GetDeclaringClass();
Ian Rogerse2645d32012-04-11 14:42:42 -0700490 if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
491 !referring_class->CanAccessMember(fields_class,
492 resolved_field->GetAccessFlags()))) {
493 // The referring class can't access the resolved field, this may occur as a result of a
494 // protected field being made public by a sub-class. Resort to the dex file to determine
495 // the correct class for the access check.
496 const DexFile& dex_file = class_linker->FindDexFile(referring_class->GetDexCache());
497 fields_class = class_linker->ResolveType(dex_file,
498 dex_file.GetFieldId(field_idx).class_idx_,
499 referring_class);
500 if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
501 ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
502 return NULL; // failure
503 } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
504 resolved_field->GetAccessFlags()))) {
505 ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
506 return NULL; // failure
507 }
508 }
509 if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700510 ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field);
511 return NULL; // failure
512 } else {
513 FieldHelper fh(resolved_field);
514 if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
515 fh.FieldSize() != expected_size)) {
516 self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
517 "Attempted read of %zd-bit %s on field '%s'",
518 expected_size * (32 / sizeof(int32_t)),
519 is_primitive ? "primitive" : "non-primitive",
520 PrettyField(resolved_field, true).c_str());
521 return NULL; // failure
522 } else if (!is_static) {
523 // instance fields must be being accessed on an initialized class
524 return resolved_field;
Ian Rogers60db5ab2012-02-20 17:02:00 -0800525 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700526 // If the class is already initializing, we must be inside <clinit>, or
527 // we'd still be waiting for the lock.
528 if (fields_class->IsInitializing()) {
529 return resolved_field;
Ian Rogers0045a292012-03-31 21:08:41 -0700530 } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700531 return resolved_field;
Ian Rogers60db5ab2012-02-20 17:02:00 -0800532 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700533 DCHECK(self->IsExceptionPending()); // Throw exception and unwind
534 return NULL; // failure
Ian Rogers60db5ab2012-02-20 17:02:00 -0800535 }
536 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700537 }
538 }
539}
540
541// Slow path method resolution
542Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
543 Thread* self, bool access_check, InvokeType type) {
544 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
545 bool is_direct = type == kStatic || type == kDirect;
Ian Rogers08f753d2012-08-24 14:35:25 -0700546 Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, type);
Ian Rogers57b86d42012-03-27 16:05:41 -0700547 if (UNLIKELY(resolved_method == NULL)) {
Ian Rogers08f753d2012-08-24 14:35:25 -0700548 DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
549 return NULL; // Failure.
Ian Rogers57b86d42012-03-27 16:05:41 -0700550 } else {
551 if (!access_check) {
552 if (is_direct) {
553 return resolved_method;
554 } else if (type == kInterface) {
555 Method* interface_method =
556 this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
557 if (UNLIKELY(interface_method == NULL)) {
Ian Rogers08f753d2012-08-24 14:35:25 -0700558 ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self,
Ian Rogers57b86d42012-03-27 16:05:41 -0700559 resolved_method,
560 this_object);
Ian Rogers08f753d2012-08-24 14:35:25 -0700561 return NULL; // Failure.
Ian Rogers57b86d42012-03-27 16:05:41 -0700562 } else {
563 return interface_method;
564 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800565 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700566 ObjectArray<Method>* vtable;
567 uint16_t vtable_index = resolved_method->GetMethodIndex();
568 if (type == kSuper) {
569 vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable();
570 } else {
571 vtable = this_object->GetClass()->GetVTable();
572 }
573 // TODO: eliminate bounds check?
574 return vtable->Get(vtable_index);
575 }
576 } else {
Ian Rogers08f753d2012-08-24 14:35:25 -0700577 // Incompatible class change should have been handled in resolve method.
578 if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
Ian Rogers2fc14272012-08-30 10:56:57 -0700579 ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method,
580 referrer);
Ian Rogers08f753d2012-08-24 14:35:25 -0700581 return NULL; // Failure.
582 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700583 Class* methods_class = resolved_method->GetDeclaringClass();
584 Class* referring_class = referrer->GetDeclaringClass();
585 if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
586 !referring_class->CanAccessMember(methods_class,
587 resolved_method->GetAccessFlags()))) {
588 // The referring class can't access the resolved method, this may occur as a result of a
589 // protected method being made public by implementing an interface that re-declares the
590 // method public. Resort to the dex file to determine the correct class for the access check
591 const DexFile& dex_file = class_linker->FindDexFile(referring_class->GetDexCache());
592 methods_class = class_linker->ResolveType(dex_file,
593 dex_file.GetMethodId(method_idx).class_idx_,
594 referring_class);
595 if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
596 ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class,
597 referrer, resolved_method, type);
Ian Rogers08f753d2012-08-24 14:35:25 -0700598 return NULL; // Failure.
Ian Rogers57b86d42012-03-27 16:05:41 -0700599 } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
600 resolved_method->GetAccessFlags()))) {
601 ThrowNewIllegalAccessErrorMethod(self, referring_class, resolved_method);
Ian Rogers08f753d2012-08-24 14:35:25 -0700602 return NULL; // Failure.
Ian Rogers57b86d42012-03-27 16:05:41 -0700603 }
604 }
605 if (is_direct) {
606 return resolved_method;
607 } else if (type == kInterface) {
608 Method* interface_method =
609 this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
610 if (UNLIKELY(interface_method == NULL)) {
Ian Rogers08f753d2012-08-24 14:35:25 -0700611 ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self,
Ian Rogers57b86d42012-03-27 16:05:41 -0700612 resolved_method,
613 this_object);
Ian Rogers08f753d2012-08-24 14:35:25 -0700614 return NULL; // Failure.
Ian Rogers57b86d42012-03-27 16:05:41 -0700615 } else {
616 return interface_method;
617 }
618 } else {
619 ObjectArray<Method>* vtable;
620 uint16_t vtable_index = resolved_method->GetMethodIndex();
621 if (type == kSuper) {
622 Class* super_class = referring_class->GetSuperClass();
623 if (LIKELY(super_class != NULL)) {
624 vtable = referring_class->GetSuperClass()->GetVTable();
625 } else {
626 vtable = NULL;
627 }
628 } else {
629 vtable = this_object->GetClass()->GetVTable();
630 }
631 if (LIKELY(vtable != NULL &&
632 vtable_index < static_cast<uint32_t>(vtable->GetLength()))) {
633 return vtable->GetWithoutChecks(vtable_index);
634 } else {
Ian Rogers08f753d2012-08-24 14:35:25 -0700635 // Behavior to agree with that of the verifier.
636 MethodHelper mh(resolved_method);
637 ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(), mh.GetName(),
Ian Rogers2fc14272012-08-30 10:56:57 -0700638 mh.GetSignature(), referrer);
Ian Rogers08f753d2012-08-24 14:35:25 -0700639 return NULL; // Failure.
Ian Rogers57b86d42012-03-27 16:05:41 -0700640 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800641 }
642 }
643 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800644}
645
Ian Rogers57b86d42012-03-27 16:05:41 -0700646Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
647 bool can_run_clinit, bool verify_access) {
648 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
649 Class* klass = class_linker->ResolveType(type_idx, referrer);
650 if (UNLIKELY(klass == NULL)) {
jeffhao441d9122012-03-21 17:29:10 -0700651 CHECK(self->IsExceptionPending());
Ian Rogers57b86d42012-03-27 16:05:41 -0700652 return NULL; // Failure - Indicate to caller to deliver exception
jeffhao441d9122012-03-21 17:29:10 -0700653 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700654 // Perform access check if necessary.
655 Class* referring_class = referrer->GetDeclaringClass();
656 if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
657 ThrowNewIllegalAccessErrorClass(self, referring_class, klass);
658 return NULL; // Failure - Indicate to caller to deliver exception
Ian Rogers14b1b242011-10-11 18:54:34 -0700659 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700660 // If we're just implementing const-class, we shouldn't call <clinit>.
661 if (!can_run_clinit) {
662 return klass;
Ian Rogersdfcdf1a2011-10-10 17:50:35 -0700663 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700664 // If we are the <clinit> of this class, just return our storage.
665 //
666 // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
667 // running.
668 if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
669 return klass;
Ian Rogersdfcdf1a2011-10-10 17:50:35 -0700670 }
Ian Rogers0045a292012-03-31 21:08:41 -0700671 if (!class_linker->EnsureInitialized(klass, true, true)) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700672 CHECK(self->IsExceptionPending());
673 return NULL; // Failure - Indicate to caller to deliver exception
Ian Rogersdfcdf1a2011-10-10 17:50:35 -0700674 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700675 referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
676 return klass;
Shih-wei Liao2d831012011-09-28 22:06:53 -0700677}
678
Shih-wei Liao2d831012011-09-28 22:06:53 -0700679} // namespace art