entrypoint_utils-inl.h revision 58c016c3f85d6d5496cea25325778de3a8d9a3ac
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_INL_H_
18#define ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_INL_H_
19
20#include "entrypoint_utils.h"
21
22#include "class_linker-inl.h"
23#include "common_throws.h"
24#include "dex_file.h"
25#include "indirect_reference_table.h"
26#include "invoke_type.h"
27#include "jni_internal.h"
28#include "mirror/art_method.h"
29#include "mirror/array.h"
30#include "mirror/class-inl.h"
31#include "mirror/object-inl.h"
32#include "mirror/throwable.h"
33#include "handle_scope-inl.h"
34#include "thread.h"
35
36namespace art {
37
38// TODO: Fix no thread safety analysis when GCC can handle template specialization.
39template <const bool kAccessCheck>
40static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
41                                              mirror::ArtMethod* method,
42                                              Thread* self, bool* slow_path) {
43  mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx);
44  if (UNLIKELY(klass == NULL)) {
45    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
46    *slow_path = true;
47    if (klass == NULL) {
48      DCHECK(self->IsExceptionPending());
49      return nullptr;  // Failure
50    } else {
51      DCHECK(!self->IsExceptionPending());
52    }
53  }
54  if (kAccessCheck) {
55    if (UNLIKELY(!klass->IsInstantiable())) {
56      ThrowLocation throw_location = self->GetCurrentLocationForThrow();
57      self->ThrowNewException(throw_location, "Ljava/lang/InstantiationError;",
58                              PrettyDescriptor(klass).c_str());
59      *slow_path = true;
60      return nullptr;  // Failure
61    }
62    mirror::Class* referrer = method->GetDeclaringClass();
63    if (UNLIKELY(!referrer->CanAccess(klass))) {
64      ThrowIllegalAccessErrorClass(referrer, klass);
65      *slow_path = true;
66      return nullptr;  // Failure
67    }
68  }
69  if (UNLIKELY(!klass->IsInitialized())) {
70    StackHandleScope<1> hs(self);
71    Handle<mirror::Class> h_klass(hs.NewHandle(klass));
72    // EnsureInitialized (the class initializer) might cause a GC.
73    // may cause us to suspend meaning that another thread may try to
74    // change the allocator while we are stuck in the entrypoints of
75    // an old allocator. Also, the class initialization may fail. To
76    // handle these cases we mark the slow path boolean as true so
77    // that the caller knows to check the allocator type to see if it
78    // has changed and to null-check the return value in case the
79    // initialization fails.
80    *slow_path = true;
81    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true)) {
82      DCHECK(self->IsExceptionPending());
83      return nullptr;  // Failure
84    } else {
85      DCHECK(!self->IsExceptionPending());
86    }
87    return h_klass.Get();
88  }
89  return klass;
90}
91
92// TODO: Fix no thread safety analysis when annotalysis is smarter.
93static inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass,
94                                                                 Thread* self,
95                                                                 bool* slow_path) {
96  if (UNLIKELY(!klass->IsInitialized())) {
97    StackHandleScope<1> hs(self);
98    Handle<mirror::Class> h_class(hs.NewHandle(klass));
99    // EnsureInitialized (the class initializer) might cause a GC.
100    // may cause us to suspend meaning that another thread may try to
101    // change the allocator while we are stuck in the entrypoints of
102    // an old allocator. Also, the class initialization may fail. To
103    // handle these cases we mark the slow path boolean as true so
104    // that the caller knows to check the allocator type to see if it
105    // has changed and to null-check the return value in case the
106    // initialization fails.
107    *slow_path = true;
108    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) {
109      DCHECK(self->IsExceptionPending());
110      return nullptr;  // Failure
111    }
112    return h_class.Get();
113  }
114  return klass;
115}
116
117// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
118// cannot be resolved, throw an error. If it can, use it to create an instance.
119// When verification/compiler hasn't been able to verify access, optionally perform an access
120// check.
121// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
122template <bool kAccessCheck, bool kInstrumented>
123static inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
124                                                  mirror::ArtMethod* method,
125                                                  Thread* self,
126                                                  gc::AllocatorType allocator_type) {
127  bool slow_path = false;
128  mirror::Class* klass = CheckObjectAlloc<kAccessCheck>(type_idx, method, self, &slow_path);
129  if (UNLIKELY(slow_path)) {
130    if (klass == nullptr) {
131      return nullptr;
132    }
133    return klass->Alloc<kInstrumented>(self, Runtime::Current()->GetHeap()->GetCurrentAllocator());
134  }
135  DCHECK(klass != nullptr);
136  return klass->Alloc<kInstrumented>(self, allocator_type);
137}
138
139// Given the context of a calling Method and a resolved class, create an instance.
140// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
141template <bool kInstrumented>
142static inline mirror::Object* AllocObjectFromCodeResolved(mirror::Class* klass,
143                                                          mirror::ArtMethod* method,
144                                                          Thread* self,
145                                                          gc::AllocatorType allocator_type) {
146  DCHECK(klass != nullptr);
147  bool slow_path = false;
148  klass = CheckClassInitializedForObjectAlloc(klass, self, &slow_path);
149  if (UNLIKELY(slow_path)) {
150    if (klass == nullptr) {
151      return nullptr;
152    }
153    gc::Heap* heap = Runtime::Current()->GetHeap();
154    // Pass in false since the object can not be finalizable.
155    return klass->Alloc<kInstrumented, false>(self, heap->GetCurrentAllocator());
156  }
157  // Pass in false since the object can not be finalizable.
158  return klass->Alloc<kInstrumented, false>(self, allocator_type);
159}
160
161// Given the context of a calling Method and an initialized class, create an instance.
162// TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter.
163template <bool kInstrumented>
164static inline mirror::Object* AllocObjectFromCodeInitialized(mirror::Class* klass,
165                                                             mirror::ArtMethod* method,
166                                                             Thread* self,
167                                                             gc::AllocatorType allocator_type) {
168  DCHECK(klass != nullptr);
169  // Pass in false since the object can not be finalizable.
170  return klass->Alloc<kInstrumented, false>(self, allocator_type);
171}
172
173
174// TODO: Fix no thread safety analysis when GCC can handle template specialization.
175template <bool kAccessCheck>
176static inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
177                                             mirror::ArtMethod* method,
178                                             int32_t component_count,
179                                             bool* slow_path) {
180  if (UNLIKELY(component_count < 0)) {
181    ThrowNegativeArraySizeException(component_count);
182    *slow_path = true;
183    return nullptr;  // Failure
184  }
185  mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx);
186  if (UNLIKELY(klass == nullptr)) {  // Not in dex cache so try to resolve
187    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
188    *slow_path = true;
189    if (klass == nullptr) {  // Error
190      DCHECK(Thread::Current()->IsExceptionPending());
191      return nullptr;  // Failure
192    }
193    CHECK(klass->IsArrayClass()) << PrettyClass(klass);
194  }
195  if (kAccessCheck) {
196    mirror::Class* referrer = method->GetDeclaringClass();
197    if (UNLIKELY(!referrer->CanAccess(klass))) {
198      ThrowIllegalAccessErrorClass(referrer, klass);
199      *slow_path = true;
200      return nullptr;  // Failure
201    }
202  }
203  return klass;
204}
205
206// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
207// it cannot be resolved, throw an error. If it can, use it to create an array.
208// When verification/compiler hasn't been able to verify access, optionally perform an access
209// check.
210// TODO: Fix no thread safety analysis when GCC can handle template specialization.
211template <bool kAccessCheck, bool kInstrumented>
212static inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
213                                                mirror::ArtMethod* method,
214                                                int32_t component_count,
215                                                Thread* self,
216                                                gc::AllocatorType allocator_type) {
217  bool slow_path = false;
218  mirror::Class* klass = CheckArrayAlloc<kAccessCheck>(type_idx, method, component_count,
219                                                       &slow_path);
220  if (UNLIKELY(slow_path)) {
221    if (klass == nullptr) {
222      return nullptr;
223    }
224    gc::Heap* heap = Runtime::Current()->GetHeap();
225    return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
226                                               klass->GetComponentSize(),
227                                               heap->GetCurrentAllocator());
228  }
229  return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
230                                             klass->GetComponentSize(), allocator_type);
231}
232
233template <bool kAccessCheck, bool kInstrumented>
234static inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass,
235                                                        mirror::ArtMethod* method,
236                                                        int32_t component_count,
237                                                        Thread* self,
238                                                        gc::AllocatorType allocator_type) {
239  DCHECK(klass != nullptr);
240  if (UNLIKELY(component_count < 0)) {
241    ThrowNegativeArraySizeException(component_count);
242    return nullptr;  // Failure
243  }
244  if (kAccessCheck) {
245    mirror::Class* referrer = method->GetDeclaringClass();
246    if (UNLIKELY(!referrer->CanAccess(klass))) {
247      ThrowIllegalAccessErrorClass(referrer, klass);
248      return nullptr;  // Failure
249    }
250  }
251  // No need to retry a slow-path allocation as the above code won't cause a GC or thread
252  // suspension.
253  return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
254                                             klass->GetComponentSize(), allocator_type);
255}
256
257template<FindFieldType type, bool access_check>
258static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::ArtMethod* referrer,
259                                                  Thread* self, size_t expected_size) {
260  bool is_primitive;
261  bool is_set;
262  bool is_static;
263  switch (type) {
264    case InstanceObjectRead:     is_primitive = false; is_set = false; is_static = false; break;
265    case InstanceObjectWrite:    is_primitive = false; is_set = true;  is_static = false; break;
266    case InstancePrimitiveRead:  is_primitive = true;  is_set = false; is_static = false; break;
267    case InstancePrimitiveWrite: is_primitive = true;  is_set = true;  is_static = false; break;
268    case StaticObjectRead:       is_primitive = false; is_set = false; is_static = true;  break;
269    case StaticObjectWrite:      is_primitive = false; is_set = true;  is_static = true;  break;
270    case StaticPrimitiveRead:    is_primitive = true;  is_set = false; is_static = true;  break;
271    case StaticPrimitiveWrite:   // Keep GCC happy by having a default handler, fall-through.
272    default:                     is_primitive = true;  is_set = true;  is_static = true;  break;
273  }
274  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
275  mirror::ArtField* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
276  if (UNLIKELY(resolved_field == nullptr)) {
277    DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
278    return nullptr;  // Failure.
279  }
280  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
281  if (access_check) {
282    if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
283      ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
284      return nullptr;
285    }
286    mirror::Class* referring_class = referrer->GetDeclaringClass();
287    if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class, resolved_field,
288                                                            field_idx))) {
289      DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
290      return nullptr;  // Failure.
291    }
292    if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
293      ThrowIllegalAccessErrorFinalField(referrer, resolved_field);
294      return nullptr;  // Failure.
295    } else {
296      if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
297                   resolved_field->FieldSize() != expected_size)) {
298        ThrowLocation throw_location = self->GetCurrentLocationForThrow();
299        DCHECK(throw_location.GetMethod() == referrer);
300        self->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
301                                 "Attempted read of %zd-bit %s on field '%s'",
302                                 expected_size * (32 / sizeof(int32_t)),
303                                 is_primitive ? "primitive" : "non-primitive",
304                                 PrettyField(resolved_field, true).c_str());
305        return nullptr;  // Failure.
306      }
307    }
308  }
309  if (!is_static) {
310    // instance fields must be being accessed on an initialized class
311    return resolved_field;
312  } else {
313    // If the class is initialized we're done.
314    if (LIKELY(fields_class->IsInitialized())) {
315      return resolved_field;
316    } else {
317      StackHandleScope<1> hs(self);
318      Handle<mirror::Class> h_class(hs.NewHandle(fields_class));
319      if (LIKELY(class_linker->EnsureInitialized(h_class, true, true))) {
320        // Otherwise let's ensure the class is initialized before resolving the field.
321        return resolved_field;
322      }
323      DCHECK(self->IsExceptionPending());  // Throw exception and unwind
324      return nullptr;  // Failure.
325    }
326  }
327}
328
329// Explicit template declarations of FindFieldFromCode for all field access types.
330#define EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \
331template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
332mirror::ArtField* FindFieldFromCode<_type, _access_check>(uint32_t field_idx, \
333                                                          mirror::ArtMethod* referrer, \
334                                                          Thread* self, size_t expected_size) \
335
336#define EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
337    EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, false); \
338    EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, true)
339
340EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectRead);
341EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectWrite);
342EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveRead);
343EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveWrite);
344EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectRead);
345EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectWrite);
346EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveRead);
347EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveWrite);
348
349#undef EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL
350#undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
351
352template<InvokeType type, bool access_check>
353static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx,
354                                                    mirror::Object** this_object,
355                                                    mirror::ArtMethod** referrer, Thread* self) {
356  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
357  mirror::ArtMethod* resolved_method = class_linker->GetResolvedMethod(method_idx, *referrer, type);
358  if (resolved_method == nullptr) {
359    StackHandleScope<1> hs(self);
360    mirror::Object* null_this = nullptr;
361    HandleWrapper<mirror::Object> h_this(
362        hs.NewHandleWrapper(type == kStatic ? &null_this : this_object));
363    resolved_method = class_linker->ResolveMethod(self, method_idx, referrer, type);
364  }
365  if (UNLIKELY(resolved_method == nullptr)) {
366    DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
367    return nullptr;  // Failure.
368  } else if (UNLIKELY(*this_object == nullptr && type != kStatic)) {
369    // Maintain interpreter-like semantics where NullPointerException is thrown
370    // after potential NoSuchMethodError from class linker.
371    ThrowLocation throw_location = self->GetCurrentLocationForThrow();
372    DCHECK_EQ(*referrer, throw_location.GetMethod());
373    ThrowNullPointerExceptionForMethodAccess(throw_location, method_idx, type);
374    return nullptr;  // Failure.
375  } else if (access_check) {
376    // Incompatible class change should have been handled in resolve method.
377    if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
378      ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method,
379                                        *referrer);
380      return nullptr;  // Failure.
381    }
382    mirror::Class* methods_class = resolved_method->GetDeclaringClass();
383    mirror::Class* referring_class = (*referrer)->GetDeclaringClass();
384    bool can_access_resolved_method =
385        referring_class->CheckResolvedMethodAccess<type>(methods_class, resolved_method,
386                                                         method_idx);
387    if (UNLIKELY(!can_access_resolved_method)) {
388      DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
389      return nullptr;  // Failure.
390    }
391  }
392  switch (type) {
393    case kStatic:
394    case kDirect:
395      return resolved_method;
396    case kVirtual: {
397      mirror::Class* klass = (*this_object)->GetClass();
398      uint16_t vtable_index = resolved_method->GetMethodIndex();
399      if (access_check &&
400          (!klass->HasVTable() ||
401           vtable_index >= static_cast<uint32_t>(klass->GetVTableLength()))) {
402        // Behavior to agree with that of the verifier.
403        ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
404                               resolved_method->GetName(), resolved_method->GetSignature());
405        return nullptr;  // Failure.
406      }
407      DCHECK(klass->HasVTable()) << PrettyClass(klass);
408      return klass->GetVTableEntry(vtable_index);
409    }
410    case kSuper: {
411      mirror::Class* super_class = (*referrer)->GetDeclaringClass()->GetSuperClass();
412      uint16_t vtable_index = resolved_method->GetMethodIndex();
413      if (access_check) {
414        // Check existence of super class.
415        if (super_class == nullptr || !super_class->HasVTable() ||
416            vtable_index >= static_cast<uint32_t>(super_class->GetVTableLength())) {
417          // Behavior to agree with that of the verifier.
418          ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
419                                 resolved_method->GetName(), resolved_method->GetSignature());
420          return nullptr;  // Failure.
421        }
422      } else {
423        // Super class must exist.
424        DCHECK(super_class != nullptr);
425      }
426      DCHECK(super_class->HasVTable());
427      return super_class->GetVTableEntry(vtable_index);
428    }
429    case kInterface: {
430      uint32_t imt_index = resolved_method->GetDexMethodIndex() % mirror::Class::kImtSize;
431      mirror::ArtMethod* imt_method = (*this_object)->GetClass()->GetEmbeddedImTableEntry(imt_index);
432      if (!imt_method->IsImtConflictMethod()) {
433        return imt_method;
434      } else {
435        mirror::ArtMethod* interface_method =
436            (*this_object)->GetClass()->FindVirtualMethodForInterface(resolved_method);
437        if (UNLIKELY(interface_method == nullptr)) {
438          ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method,
439                                                                     *this_object, *referrer);
440          return nullptr;  // Failure.
441        }
442        return interface_method;
443      }
444    }
445    default:
446      LOG(FATAL) << "Unknown invoke type " << type;
447      return nullptr;  // Failure.
448  }
449}
450
451// Explicit template declarations of FindMethodFromCode for all invoke types.
452#define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check)                 \
453  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                       \
454  mirror::ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx,         \
455                                                              mirror::Object** this_object, \
456                                                              mirror::ArtMethod** referrer, \
457                                                              Thread* self)
458#define EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
459    EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, false);   \
460    EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, true)
461
462EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kStatic);
463EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kDirect);
464EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kVirtual);
465EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kSuper);
466EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kInterface);
467
468#undef EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL
469#undef EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL
470
471// Fast path field resolution that can't initialize classes or throw exceptions.
472static inline mirror::ArtField* FindFieldFast(uint32_t field_idx,
473                                              mirror::ArtMethod* referrer,
474                                              FindFieldType type, size_t expected_size) {
475  mirror::ArtField* resolved_field =
476      referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
477  if (UNLIKELY(resolved_field == nullptr)) {
478    return nullptr;
479  }
480  // Check for incompatible class change.
481  bool is_primitive;
482  bool is_set;
483  bool is_static;
484  switch (type) {
485    case InstanceObjectRead:     is_primitive = false; is_set = false; is_static = false; break;
486    case InstanceObjectWrite:    is_primitive = false; is_set = true;  is_static = false; break;
487    case InstancePrimitiveRead:  is_primitive = true;  is_set = false; is_static = false; break;
488    case InstancePrimitiveWrite: is_primitive = true;  is_set = true;  is_static = false; break;
489    case StaticObjectRead:       is_primitive = false; is_set = false; is_static = true;  break;
490    case StaticObjectWrite:      is_primitive = false; is_set = true;  is_static = true;  break;
491    case StaticPrimitiveRead:    is_primitive = true;  is_set = false; is_static = true;  break;
492    case StaticPrimitiveWrite:   is_primitive = true;  is_set = true;  is_static = true;  break;
493    default:
494      LOG(FATAL) << "UNREACHABLE";  // Assignment below to avoid GCC warnings.
495      is_primitive = true;
496      is_set = true;
497      is_static = true;
498      break;
499  }
500  if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
501    // Incompatible class change.
502    return nullptr;
503  }
504  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
505  if (is_static) {
506    // Check class is initialized else fail so that we can contend to initialize the class with
507    // other threads that may be racing to do this.
508    if (UNLIKELY(!fields_class->IsInitialized())) {
509      return nullptr;
510    }
511  }
512  mirror::Class* referring_class = referrer->GetDeclaringClass();
513  if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
514               !referring_class->CanAccessMember(fields_class,
515                                                 resolved_field->GetAccessFlags()) ||
516               (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
517    // Illegal access.
518    return nullptr;
519  }
520  if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
521               resolved_field->FieldSize() != expected_size)) {
522    return nullptr;
523  }
524  return resolved_field;
525}
526
527// Fast path method resolution that can't throw exceptions.
528static inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx,
529                                                mirror::Object* this_object,
530                                                mirror::ArtMethod* referrer,
531                                                bool access_check, InvokeType type) {
532  bool is_direct = type == kStatic || type == kDirect;
533  if (UNLIKELY(this_object == NULL && !is_direct)) {
534    return NULL;
535  }
536  mirror::ArtMethod* resolved_method =
537      referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
538  if (UNLIKELY(resolved_method == NULL)) {
539    return NULL;
540  }
541  if (access_check) {
542    // Check for incompatible class change errors and access.
543    bool icce = resolved_method->CheckIncompatibleClassChange(type);
544    if (UNLIKELY(icce)) {
545      return NULL;
546    }
547    mirror::Class* methods_class = resolved_method->GetDeclaringClass();
548    mirror::Class* referring_class = referrer->GetDeclaringClass();
549    if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
550                 !referring_class->CanAccessMember(methods_class,
551                                                   resolved_method->GetAccessFlags()))) {
552      // Potential illegal access, may need to refine the method's class.
553      return NULL;
554    }
555  }
556  if (type == kInterface) {  // Most common form of slow path dispatch.
557    return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
558  } else if (is_direct) {
559    return resolved_method;
560  } else if (type == kSuper) {
561    return referrer->GetDeclaringClass()->GetSuperClass()
562                   ->GetVTableEntry(resolved_method->GetMethodIndex());
563  } else {
564    DCHECK(type == kVirtual);
565    return this_object->GetClass()->GetVTableEntry(resolved_method->GetMethodIndex());
566  }
567}
568
569static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
570                                                    mirror::ArtMethod* referrer,
571                                                    Thread* self, bool can_run_clinit,
572                                                    bool verify_access) {
573  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
574  mirror::Class* klass = class_linker->ResolveType(type_idx, referrer);
575  if (UNLIKELY(klass == nullptr)) {
576    CHECK(self->IsExceptionPending());
577    return nullptr;  // Failure - Indicate to caller to deliver exception
578  }
579  // Perform access check if necessary.
580  mirror::Class* referring_class = referrer->GetDeclaringClass();
581  if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
582    ThrowIllegalAccessErrorClass(referring_class, klass);
583    return nullptr;  // Failure - Indicate to caller to deliver exception
584  }
585  // If we're just implementing const-class, we shouldn't call <clinit>.
586  if (!can_run_clinit) {
587    return klass;
588  }
589  // If we are the <clinit> of this class, just return our storage.
590  //
591  // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
592  // running.
593  if (klass == referring_class && referrer->IsConstructor() && referrer->IsStatic()) {
594    return klass;
595  }
596  StackHandleScope<1> hs(self);
597  Handle<mirror::Class> h_class(hs.NewHandle(klass));
598  if (!class_linker->EnsureInitialized(h_class, true, true)) {
599    CHECK(self->IsExceptionPending());
600    return nullptr;  // Failure - Indicate to caller to deliver exception
601  }
602  return h_class.Get();
603}
604
605static inline mirror::String* ResolveStringFromCode(mirror::ArtMethod* referrer,
606                                                    uint32_t string_idx) {
607  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
608  return class_linker->ResolveString(string_idx, referrer);
609}
610
611static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) {
612  // Save any pending exception over monitor exit call.
613  mirror::Throwable* saved_exception = NULL;
614  ThrowLocation saved_throw_location;
615  bool is_exception_reported = self->IsExceptionReportedToInstrumentation();
616  if (UNLIKELY(self->IsExceptionPending())) {
617    saved_exception = self->GetException(&saved_throw_location);
618    self->ClearException();
619  }
620  // Decode locked object and unlock, before popping local references.
621  self->DecodeJObject(locked)->MonitorExit(self);
622  if (UNLIKELY(self->IsExceptionPending())) {
623    LOG(FATAL) << "Synchronized JNI code returning with an exception:\n"
624        << saved_exception->Dump()
625        << "\nEncountered second exception during implicit MonitorExit:\n"
626        << self->GetException(NULL)->Dump();
627  }
628  // Restore pending exception.
629  if (saved_exception != NULL) {
630    self->SetException(saved_throw_location, saved_exception);
631    self->SetExceptionReportedToInstrumentation(is_exception_reported);
632  }
633}
634
635static inline void CheckSuspend(Thread* thread) {
636  for (;;) {
637    if (thread->ReadFlag(kCheckpointRequest)) {
638      thread->RunCheckpointFunction();
639    } else if (thread->ReadFlag(kSuspendRequest)) {
640      thread->FullSuspendCheck();
641    } else {
642      break;
643    }
644  }
645}
646
647template <typename INT_TYPE, typename FLOAT_TYPE>
648static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f) {
649  const INT_TYPE kMaxInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::max());
650  const INT_TYPE kMinInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::min());
651  const FLOAT_TYPE kMaxIntAsFloat = static_cast<FLOAT_TYPE>(kMaxInt);
652  const FLOAT_TYPE kMinIntAsFloat = static_cast<FLOAT_TYPE>(kMinInt);
653  if (LIKELY(f > kMinIntAsFloat)) {
654     if (LIKELY(f < kMaxIntAsFloat)) {
655       return static_cast<INT_TYPE>(f);
656     } else {
657       return kMaxInt;
658     }
659  } else {
660    return (f != f) ? 0 : kMinInt;  // f != f implies NaN
661  }
662}
663
664}  // namespace art
665
666#endif  // ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_INL_H_
667