blob: 9309df9c99bf3c7fec42124439f73e37560b2a50 [file] [log] [blame]
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -08001// Copyright 2012 Google Inc. All Rights Reserved.
2
3#include "runtime_support_common.h"
4
5
6namespace art {
7
8// Helper function to allocate array for FILLED_NEW_ARRAY.
9Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
10 Thread* self, bool access_check) {
11 if (UNLIKELY(component_count < 0)) {
12 self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
13 return NULL; // Failure
14 }
15 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
16 if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
17 klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
18 if (klass == NULL) { // Error
19 DCHECK(Thread::Current()->IsExceptionPending());
20 return NULL; // Failure
21 }
22 }
23 if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) {
24 if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
25 Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
26 "Bad filled array request for type %s",
27 PrettyDescriptor(klass).c_str());
28 } else {
29 Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;",
30 "Found type %s; filled-new-array not implemented for anything but \'int\'",
31 PrettyDescriptor(klass).c_str());
32 }
33 return NULL; // Failure
34 } else {
35 if (access_check) {
36 Class* referrer = method->GetDeclaringClass();
37 if (UNLIKELY(!referrer->CanAccess(klass))) {
38 ThrowNewIllegalAccessErrorClass(self, referrer, klass);
39 return NULL; // Failure
40 }
41 }
42 DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
43 return Array::Alloc(klass, component_count);
44 }
45}
46
47// Slow path field resolution and declaring class initialization
48Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
49 bool is_static, bool is_primitive, bool is_set, size_t expected_size) {
50 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
51 Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
52 if (UNLIKELY(resolved_field == NULL)) {
53 DCHECK(self->IsExceptionPending()); // Throw exception and unwind
54 return NULL; // failure
55 } else {
56 Class* fields_class = resolved_field->GetDeclaringClass();
57 Class* referring_class = referrer->GetDeclaringClass();
58 if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
59 ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
60 return NULL; // failure
61 } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
62 resolved_field->GetAccessFlags()))) {
63 ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
64 return NULL; // failure
65 } else if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
66 ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field);
67 return NULL; // failure
68 } else {
69 FieldHelper fh(resolved_field);
70 if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
71 fh.FieldSize() != expected_size)) {
72 self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
73 "Attempted read of %zd-bit %s on field '%s'",
74 expected_size * (32 / sizeof(int32_t)),
75 is_primitive ? "primitive" : "non-primitive",
76 PrettyField(resolved_field, true).c_str());
77 return NULL; // failure
78 } else if (!is_static) {
79 // instance fields must be being accessed on an initialized class
80 return resolved_field;
81 } else {
82 // If the class is already initializing, we must be inside <clinit>, or
83 // we'd still be waiting for the lock.
84 if (fields_class->IsInitializing()) {
85 return resolved_field;
86 } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
87 return resolved_field;
88 } else {
89 DCHECK(self->IsExceptionPending()); // Throw exception and unwind
90 return NULL; // failure
91 }
92 }
93 }
94 }
95}
96
97// Slow path method resolution
98Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
99 Thread* self, bool access_check, InvokeType type) {
100 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
101 bool is_direct = type == kStatic || type == kDirect;
102 Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
103 if (UNLIKELY(resolved_method == NULL)) {
104 DCHECK(self->IsExceptionPending()); // Throw exception and unwind
105 return NULL; // failure
106 } else {
107 if (!access_check) {
108 if (is_direct) {
109 return resolved_method;
110 } else if (type == kInterface) {
111 Method* interface_method =
112 this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
113 if (UNLIKELY(interface_method == NULL)) {
114 ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
115 resolved_method,
116 this_object);
117 return NULL; // failure
118 } else {
119 return interface_method;
120 }
121 } else {
122 ObjectArray<Method>* vtable;
123 uint16_t vtable_index = resolved_method->GetMethodIndex();
124 if (type == kSuper) {
125 vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable();
126 } else {
127 vtable = this_object->GetClass()->GetVTable();
128 }
129 // TODO: eliminate bounds check?
130 return vtable->Get(vtable_index);
131 }
132 } else {
133 Class* methods_class = resolved_method->GetDeclaringClass();
134 Class* referring_class = referrer->GetDeclaringClass();
135 if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
136 !referring_class->CanAccessMember(methods_class,
137 resolved_method->GetAccessFlags()))) {
138 // The referring class can't access the resolved method, this may occur as a result of a
139 // protected method being made public by implementing an interface that re-declares the
140 // method public. Resort to the dex file to determine the correct class for the access check
141 const DexFile& dex_file = class_linker->FindDexFile(referring_class->GetDexCache());
142 methods_class = class_linker->ResolveType(dex_file,
143 dex_file.GetMethodId(method_idx).class_idx_,
144 referring_class);
145 if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
146 ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class,
147 referrer, resolved_method, type);
148 return NULL; // failure
149 } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
150 resolved_method->GetAccessFlags()))) {
151 ThrowNewIllegalAccessErrorMethod(self, referring_class, resolved_method);
152 return NULL; // failure
153 }
154 }
155 if (is_direct) {
156 return resolved_method;
157 } else if (type == kInterface) {
158 Method* interface_method =
159 this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
160 if (UNLIKELY(interface_method == NULL)) {
161 ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
162 resolved_method,
163 this_object);
164 return NULL; // failure
165 } else {
166 return interface_method;
167 }
168 } else {
169 ObjectArray<Method>* vtable;
170 uint16_t vtable_index = resolved_method->GetMethodIndex();
171 if (type == kSuper) {
172 Class* super_class = referring_class->GetSuperClass();
173 if (LIKELY(super_class != NULL)) {
174 vtable = referring_class->GetSuperClass()->GetVTable();
175 } else {
176 vtable = NULL;
177 }
178 } else {
179 vtable = this_object->GetClass()->GetVTable();
180 }
181 if (LIKELY(vtable != NULL &&
182 vtable_index < static_cast<uint32_t>(vtable->GetLength()))) {
183 return vtable->GetWithoutChecks(vtable_index);
184 } else {
185 // Behavior to agree with that of the verifier
186 self->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
187 "attempt to invoke %s method '%s' from '%s'"
188 " using incorrect form of method dispatch",
189 (type == kSuper ? "super class" : "virtual"),
190 PrettyMethod(resolved_method).c_str(),
191 PrettyMethod(referrer).c_str());
192 return NULL; // failure
193 }
194 }
195 }
196 }
197}
198
Shih-wei Liao399ed3f2012-03-08 01:27:04 -0800199Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
200 bool can_run_clinit, bool verify_access) {
201 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
202 Class* klass = class_linker->ResolveType(type_idx, referrer);
203 if (UNLIKELY(klass == NULL)) {
204 CHECK(self->IsExceptionPending());
205 return NULL; // Failure - Indicate to caller to deliver exception
206 }
207 // Perform access check if necessary.
208 Class* referring_class = referrer->GetDeclaringClass();
209 if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
210 ThrowNewIllegalAccessErrorClass(self, referring_class, klass);
211 return NULL; // Failure - Indicate to caller to deliver exception
212 }
213 // If we're just implementing const-class, we shouldn't call <clinit>.
214 if (!can_run_clinit) {
215 return klass;
216 }
217 // If we are the <clinit> of this class, just return our storage.
218 //
219 // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
220 // running.
221 if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
222 return klass;
223 }
224 if (!class_linker->EnsureInitialized(klass, true)) {
225 CHECK(self->IsExceptionPending());
226 return NULL; // Failure - Indicate to caller to deliver exception
227 }
228 referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
229 return klass;
230}
231
232extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
233 Thread* self, Method** sp) {
234 Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
235 if (LIKELY(field != NULL)) {
236 return field->Get32(NULL);
237 }
238#if !defined(ART_USE_LLVM_COMPILER)
239 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
240#endif
241 field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int32_t));
242 if (LIKELY(field != NULL)) {
243 return field->Get32(NULL);
244 }
245 return 0; // Will throw exception by checking with Thread::Current
246}
247
248extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const Method* referrer,
249 Thread* self, Method** sp) {
250 Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
251 if (LIKELY(field != NULL)) {
252 return field->Get64(NULL);
253 }
254#if !defined(ART_USE_LLVM_COMPILER)
255 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
256#endif
257 field = FindFieldFromCode(field_idx, referrer, self, true, true, false, sizeof(int64_t));
258 if (LIKELY(field != NULL)) {
259 return field->Get64(NULL);
260 }
261 return 0; // Will throw exception by checking with Thread::Current
262}
263
264extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
265 Thread* self, Method** sp) {
266 Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
267 if (LIKELY(field != NULL)) {
268 return field->GetObj(NULL);
269 }
270#if !defined(ART_USE_LLVM_COMPILER)
271 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
272#endif
273 field = FindFieldFromCode(field_idx, referrer, self, true, false, false, sizeof(Object*));
274 if (LIKELY(field != NULL)) {
275 return field->GetObj(NULL);
276 }
277 return NULL; // Will throw exception by checking with Thread::Current
278}
279
280extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, Object* obj,
281 const Method* referrer, Thread* self, Method** sp) {
282 Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
283 if (LIKELY(field != NULL && obj != NULL)) {
284 return field->Get32(obj);
285 }
286#if !defined(ART_USE_LLVM_COMPILER)
287 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
288#endif
289 field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int32_t));
290 if (LIKELY(field != NULL)) {
291 if (UNLIKELY(obj == NULL)) {
292 ThrowNullPointerExceptionForFieldAccess(self, field, true);
293 } else {
294 return field->Get32(obj);
295 }
296 }
297 return 0; // Will throw exception by checking with Thread::Current
298}
299
300extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, Object* obj,
301 const Method* referrer, Thread* self, Method** sp) {
302 Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
303 if (LIKELY(field != NULL && obj != NULL)) {
304 return field->Get64(obj);
305 }
306#if !defined(ART_USE_LLVM_COMPILER)
307 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
308#endif
309 field = FindFieldFromCode(field_idx, referrer, self, false, true, false, sizeof(int64_t));
310 if (LIKELY(field != NULL)) {
311 if (UNLIKELY(obj == NULL)) {
312 ThrowNullPointerExceptionForFieldAccess(self, field, true);
313 } else {
314 return field->Get64(obj);
315 }
316 }
317 return 0; // Will throw exception by checking with Thread::Current
318}
319
320extern "C" Object* artGetObjInstanceFromCode(uint32_t field_idx, Object* obj,
321 const Method* referrer, Thread* self, Method** sp) {
322 Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
323 if (LIKELY(field != NULL && obj != NULL)) {
324 return field->GetObj(obj);
325 }
326#if !defined(ART_USE_LLVM_COMPILER)
327 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
328#endif
329 field = FindFieldFromCode(field_idx, referrer, self, false, false, false, sizeof(Object*));
330 if (LIKELY(field != NULL)) {
331 if (UNLIKELY(obj == NULL)) {
332 ThrowNullPointerExceptionForFieldAccess(self, field, true);
333 } else {
334 return field->GetObj(obj);
335 }
336 }
337 return NULL; // Will throw exception by checking with Thread::Current
338}
339
340extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value,
341 const Method* referrer, Thread* self, Method** sp) {
342 Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
343 if (LIKELY(field != NULL)) {
344 field->Set32(NULL, new_value);
345 return 0; // success
346 }
347#if !defined(ART_USE_LLVM_COMPILER)
348 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
349#endif
350 field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int32_t));
351 if (LIKELY(field != NULL)) {
352 field->Set32(NULL, new_value);
353 return 0; // success
354 }
355 return -1; // failure
356}
357
358extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer,
359 uint64_t new_value, Thread* self, Method** sp) {
360 Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
361 if (LIKELY(field != NULL)) {
362 field->Set64(NULL, new_value);
363 return 0; // success
364 }
365#if !defined(ART_USE_LLVM_COMPILER)
366 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
367#endif
368 field = FindFieldFromCode(field_idx, referrer, self, true, true, true, sizeof(int64_t));
369 if (LIKELY(field != NULL)) {
370 field->Set64(NULL, new_value);
371 return 0; // success
372 }
373 return -1; // failure
374}
375
376extern "C" int artSetObjStaticFromCode(uint32_t field_idx, Object* new_value,
377 const Method* referrer, Thread* self, Method** sp) {
378 Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
379 if (LIKELY(field != NULL)) {
380 if (LIKELY(!FieldHelper(field).IsPrimitiveType())) {
381 field->SetObj(NULL, new_value);
382 return 0; // success
383 }
384 }
385#if !defined(ART_USE_LLVM_COMPILER)
386 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
387#endif
388 field = FindFieldFromCode(field_idx, referrer, self, true, false, true, sizeof(Object*));
389 if (LIKELY(field != NULL)) {
390 field->SetObj(NULL, new_value);
391 return 0; // success
392 }
393 return -1; // failure
394}
395
396extern "C" int artSet32InstanceFromCode(uint32_t field_idx, Object* obj, uint32_t new_value,
397 const Method* referrer, Thread* self, Method** sp) {
398 Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
399 if (LIKELY(field != NULL && obj != NULL)) {
400 field->Set32(obj, new_value);
401 return 0; // success
402 }
403#if !defined(ART_USE_LLVM_COMPILER)
404 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
405#endif
406 field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int32_t));
407 if (LIKELY(field != NULL)) {
408 if (UNLIKELY(obj == NULL)) {
409 ThrowNullPointerExceptionForFieldAccess(self, field, false);
410 } else {
411 field->Set32(obj, new_value);
412 return 0; // success
413 }
414 }
415 return -1; // failure
416}
417
418extern "C" int artSet64InstanceFromCode(uint32_t field_idx, Object* obj, uint64_t new_value,
419#if !defined(ART_USE_LLVM_COMPILER)
420 Thread* self, Method** sp) {
421#else
422 const Method* referrer, Thread* self, Method** sp) {
423#endif
424#if !defined(ART_USE_LLVM_COMPILER)
425 Method* callee_save = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsOnly);
426 Method* referrer = sp[callee_save->GetFrameSizeInBytes() / sizeof(Method*)];
427#endif
428 Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
429 if (LIKELY(field != NULL && obj != NULL)) {
430 field->Set64(obj, new_value);
431 return 0; // success
432 }
433#if !defined(ART_USE_LLVM_COMPILER)
434 *sp = callee_save;
435 self->SetTopOfStack(sp, 0);
436#endif
437 field = FindFieldFromCode(field_idx, referrer, self, false, true, true, sizeof(int64_t));
438 if (LIKELY(field != NULL)) {
439 if (UNLIKELY(obj == NULL)) {
440 ThrowNullPointerExceptionForFieldAccess(self, field, false);
441 } else {
442 field->Set64(obj, new_value);
443 return 0; // success
444 }
445 }
446 return -1; // failure
447}
448
449extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, Object* obj, Object* new_value,
450 const Method* referrer, Thread* self, Method** sp) {
451 Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
452 if (LIKELY(field != NULL && obj != NULL)) {
453 field->SetObj(obj, new_value);
454 return 0; // success
455 }
456#if !defined(ART_USE_LLVM_COMPILER)
457 FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
458#endif
459 field = FindFieldFromCode(field_idx, referrer, self, false, false, true, sizeof(Object*));
460 if (LIKELY(field != NULL)) {
461 if (UNLIKELY(obj == NULL)) {
462 ThrowNullPointerExceptionForFieldAccess(self, field, false);
463 } else {
464 field->SetObj(obj, new_value);
465 return 0; // success
466 }
467 }
468 return -1; // failure
469}
470
471
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -0800472} // namespace art