• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_H_
18 #define ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_
19 #include "object_utils.h"
20 #include "class_linker.h"
21 #include "common_throws.h"
22 #include "dex_file.h"
23 #include "indirect_reference_table.h"
24 #include "invoke_type.h"
25 #include "jni_internal.h"
26 #include "mirror/art_method.h"
27 #include "mirror/array.h"
28 #include "mirror/class-inl.h"
29 #include "mirror/throwable.h"
30 
31 #include "thread.h"
32 
33 namespace art {
34 
35 namespace mirror {
36   class Class;
37   class ArtField;
38   class Object;
39 }  // namespace mirror
40 
41 // Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
42 // cannot be resolved, throw an error. If it can, use it to create an instance.
43 // When verification/compiler hasn't been able to verify access, optionally perform an access
44 // check.
AllocObjectFromCode(uint32_t type_idx,mirror::ArtMethod * method,Thread * self,bool access_check)45 static inline mirror::Object* AllocObjectFromCode(uint32_t type_idx, mirror::ArtMethod* method,
46                                                   Thread* self,
47                                                   bool access_check)
48     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
49   mirror::Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
50   Runtime* runtime = Runtime::Current();
51   if (UNLIKELY(klass == NULL)) {
52     klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
53     if (klass == NULL) {
54       DCHECK(self->IsExceptionPending());
55       return NULL;  // Failure
56     }
57   }
58   if (access_check) {
59     if (UNLIKELY(!klass->IsInstantiable())) {
60       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
61       self->ThrowNewException(throw_location, "Ljava/lang/InstantiationError;",
62                               PrettyDescriptor(klass).c_str());
63       return NULL;  // Failure
64     }
65     mirror::Class* referrer = method->GetDeclaringClass();
66     if (UNLIKELY(!referrer->CanAccess(klass))) {
67       ThrowIllegalAccessErrorClass(referrer, klass);
68       return NULL;  // Failure
69     }
70   }
71   if (!klass->IsInitialized() &&
72       !runtime->GetClassLinker()->EnsureInitialized(klass, true, true)) {
73     DCHECK(self->IsExceptionPending());
74     return NULL;  // Failure
75   }
76   return klass->AllocObject(self);
77 }
78 
79 // Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
80 // it cannot be resolved, throw an error. If it can, use it to create an array.
81 // When verification/compiler hasn't been able to verify access, optionally perform an access
82 // check.
AllocArrayFromCode(uint32_t type_idx,mirror::ArtMethod * method,int32_t component_count,Thread * self,bool access_check)83 static inline mirror::Array* AllocArrayFromCode(uint32_t type_idx, mirror::ArtMethod* method,
84                                                 int32_t component_count,
85                                                 Thread* self, bool access_check)
86     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
87   if (UNLIKELY(component_count < 0)) {
88     ThrowNegativeArraySizeException(component_count);
89     return NULL;  // Failure
90   }
91   mirror::Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
92   if (UNLIKELY(klass == NULL)) {  // Not in dex cache so try to resolve
93     klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
94     if (klass == NULL) {  // Error
95       DCHECK(Thread::Current()->IsExceptionPending());
96       return NULL;  // Failure
97     }
98     CHECK(klass->IsArrayClass()) << PrettyClass(klass);
99   }
100   if (access_check) {
101     mirror::Class* referrer = method->GetDeclaringClass();
102     if (UNLIKELY(!referrer->CanAccess(klass))) {
103       ThrowIllegalAccessErrorClass(referrer, klass);
104       return NULL;  // Failure
105     }
106   }
107   return mirror::Array::Alloc(self, klass, component_count);
108 }
109 
110 extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::ArtMethod* method,
111                                                  int32_t component_count,
112                                                  Thread* self, bool access_check)
113     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
114 
115 // Type of find field operation for fast and slow case.
116 enum FindFieldType {
117   InstanceObjectRead,
118   InstanceObjectWrite,
119   InstancePrimitiveRead,
120   InstancePrimitiveWrite,
121   StaticObjectRead,
122   StaticObjectWrite,
123   StaticPrimitiveRead,
124   StaticPrimitiveWrite,
125 };
126 
127 // Slow field find that can initialize classes and may throw exceptions.
128 extern mirror::ArtField* FindFieldFromCode(uint32_t field_idx, const mirror::ArtMethod* referrer,
129                                            Thread* self, FindFieldType type, size_t expected_size,
130                                            bool access_check)
131     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
132 
133 // Fast path field resolution that can't initialize classes or throw exceptions.
FindFieldFast(uint32_t field_idx,const mirror::ArtMethod * referrer,FindFieldType type,size_t expected_size)134 static inline mirror::ArtField* FindFieldFast(uint32_t field_idx,
135                                               const mirror::ArtMethod* referrer,
136                                               FindFieldType type, size_t expected_size)
137     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
138   mirror::ArtField* resolved_field =
139       referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
140   if (UNLIKELY(resolved_field == NULL)) {
141     return NULL;
142   }
143   mirror::Class* fields_class = resolved_field->GetDeclaringClass();
144   // Check class is initiliazed or initializing.
145   if (UNLIKELY(!fields_class->IsInitializing())) {
146     return NULL;
147   }
148   // Check for incompatible class change.
149   bool is_primitive;
150   bool is_set;
151   bool is_static;
152   switch (type) {
153     case InstanceObjectRead:     is_primitive = false; is_set = false; is_static = false; break;
154     case InstanceObjectWrite:    is_primitive = false; is_set = true;  is_static = false; break;
155     case InstancePrimitiveRead:  is_primitive = true;  is_set = false; is_static = false; break;
156     case InstancePrimitiveWrite: is_primitive = true;  is_set = true;  is_static = false; break;
157     case StaticObjectRead:       is_primitive = false; is_set = false; is_static = true;  break;
158     case StaticObjectWrite:      is_primitive = false; is_set = true;  is_static = true;  break;
159     case StaticPrimitiveRead:    is_primitive = true;  is_set = false; is_static = true;  break;
160     case StaticPrimitiveWrite:   is_primitive = true;  is_set = true;  is_static = true;  break;
161     default:
162       LOG(FATAL) << "UNREACHABLE";  // Assignment below to avoid GCC warnings.
163       is_primitive = true;
164       is_set = true;
165       is_static = true;
166       break;
167   }
168   if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
169     // Incompatible class change.
170     return NULL;
171   }
172   mirror::Class* referring_class = referrer->GetDeclaringClass();
173   if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
174                !referring_class->CanAccessMember(fields_class,
175                                                  resolved_field->GetAccessFlags()) ||
176                (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
177     // Illegal access.
178     return NULL;
179   }
180   FieldHelper fh(resolved_field);
181   if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
182                fh.FieldSize() != expected_size)) {
183     return NULL;
184   }
185   return resolved_field;
186 }
187 
188 // Fast path method resolution that can't throw exceptions.
FindMethodFast(uint32_t method_idx,mirror::Object * this_object,const mirror::ArtMethod * referrer,bool access_check,InvokeType type)189 static inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx,
190                                                 mirror::Object* this_object,
191                                                 const mirror::ArtMethod* referrer,
192                                                 bool access_check, InvokeType type)
193     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
194   bool is_direct = type == kStatic || type == kDirect;
195   if (UNLIKELY(this_object == NULL && !is_direct)) {
196     return NULL;
197   }
198   mirror::ArtMethod* resolved_method =
199       referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
200   if (UNLIKELY(resolved_method == NULL)) {
201     return NULL;
202   }
203   if (access_check) {
204     // Check for incompatible class change errors and access.
205     bool icce = resolved_method->CheckIncompatibleClassChange(type);
206     if (UNLIKELY(icce)) {
207       return NULL;
208     }
209     mirror::Class* methods_class = resolved_method->GetDeclaringClass();
210     mirror::Class* referring_class = referrer->GetDeclaringClass();
211     if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
212                  !referring_class->CanAccessMember(methods_class,
213                                                    resolved_method->GetAccessFlags()))) {
214       // Potential illegal access, may need to refine the method's class.
215       return NULL;
216     }
217   }
218   if (type == kInterface) {  // Most common form of slow path dispatch.
219     return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
220   } else if (is_direct) {
221     return resolved_method;
222   } else if (type == kSuper) {
223     return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->
224         Get(resolved_method->GetMethodIndex());
225   } else {
226     DCHECK(type == kVirtual);
227     return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
228   }
229 }
230 
231 extern mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror::Object* this_object,
232                                              mirror::ArtMethod* referrer,
233                                              Thread* self, bool access_check, InvokeType type)
234     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
235 
ResolveVerifyAndClinit(uint32_t type_idx,const mirror::ArtMethod * referrer,Thread * self,bool can_run_clinit,bool verify_access)236 static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
237                                                     const mirror::ArtMethod* referrer,
238                                                     Thread* self, bool can_run_clinit,
239                                                     bool verify_access)
240     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
241   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
242   mirror::Class* klass = class_linker->ResolveType(type_idx, referrer);
243   if (UNLIKELY(klass == NULL)) {
244     CHECK(self->IsExceptionPending());
245     return NULL;  // Failure - Indicate to caller to deliver exception
246   }
247   // Perform access check if necessary.
248   mirror::Class* referring_class = referrer->GetDeclaringClass();
249   if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
250     ThrowIllegalAccessErrorClass(referring_class, klass);
251     return NULL;  // Failure - Indicate to caller to deliver exception
252   }
253   // If we're just implementing const-class, we shouldn't call <clinit>.
254   if (!can_run_clinit) {
255     return klass;
256   }
257   // If we are the <clinit> of this class, just return our storage.
258   //
259   // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
260   // running.
261   if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
262     return klass;
263   }
264   if (!class_linker->EnsureInitialized(klass, true, true)) {
265     CHECK(self->IsExceptionPending());
266     return NULL;  // Failure - Indicate to caller to deliver exception
267   }
268   referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
269   return klass;
270 }
271 
272 extern void ThrowStackOverflowError(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
273 
ResolveStringFromCode(const mirror::ArtMethod * referrer,uint32_t string_idx)274 static inline mirror::String* ResolveStringFromCode(const mirror::ArtMethod* referrer,
275                                                     uint32_t string_idx)
276     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
277   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
278   return class_linker->ResolveString(string_idx, referrer);
279 }
280 
UnlockJniSynchronizedMethod(jobject locked,Thread * self)281 static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
282     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
283     UNLOCK_FUNCTION(monitor_lock_) {
284   // Save any pending exception over monitor exit call.
285   mirror::Throwable* saved_exception = NULL;
286   ThrowLocation saved_throw_location;
287   if (UNLIKELY(self->IsExceptionPending())) {
288     saved_exception = self->GetException(&saved_throw_location);
289     self->ClearException();
290   }
291   // Decode locked object and unlock, before popping local references.
292   self->DecodeJObject(locked)->MonitorExit(self);
293   if (UNLIKELY(self->IsExceptionPending())) {
294     LOG(FATAL) << "Synchronized JNI code returning with an exception:\n"
295         << saved_exception->Dump()
296         << "\nEncountered second exception during implicit MonitorExit:\n"
297         << self->GetException(NULL)->Dump();
298   }
299   // Restore pending exception.
300   if (saved_exception != NULL) {
301     self->SetException(saved_throw_location, saved_exception);
302   }
303 }
304 
CheckReferenceResult(mirror::Object * o,Thread * self)305 static inline void CheckReferenceResult(mirror::Object* o, Thread* self)
306     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
307   if (o == NULL) {
308     return;
309   }
310   mirror::ArtMethod* m = self->GetCurrentMethod(NULL);
311   if (o == kInvalidIndirectRefObject) {
312     JniAbortF(NULL, "invalid reference returned from %s", PrettyMethod(m).c_str());
313   }
314   // Make sure that the result is an instance of the type this method was expected to return.
315   mirror::Class* return_type = MethodHelper(m).GetReturnType();
316 
317   if (!o->InstanceOf(return_type)) {
318     JniAbortF(NULL, "attempt to return an instance of %s from %s",
319               PrettyTypeOf(o).c_str(), PrettyMethod(m).c_str());
320   }
321 }
322 
CheckSuspend(Thread * thread)323 static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
324   for (;;) {
325     if (thread->ReadFlag(kCheckpointRequest)) {
326       thread->RunCheckpointFunction();
327       thread->AtomicClearFlag(kCheckpointRequest);
328     } else if (thread->ReadFlag(kSuspendRequest)) {
329       thread->FullSuspendCheck();
330     } else {
331       break;
332     }
333   }
334 }
335 
336 JValue InvokeProxyInvocationHandler(ScopedObjectAccessUnchecked& soa, const char* shorty,
337                                     jobject rcvr_jobj, jobject interface_art_method_jobj,
338                                     std::vector<jvalue>& args)
339     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
340 
341 // Entry point for deoptimization.
342 extern "C" void art_quick_deoptimize();
GetQuickDeoptimizationEntryPoint()343 static inline uintptr_t GetQuickDeoptimizationEntryPoint() {
344   return reinterpret_cast<uintptr_t>(art_quick_deoptimize);
345 }
346 
347 // Return address of instrumentation stub.
348 extern "C" void art_quick_instrumentation_entry(void*);
GetQuickInstrumentationEntryPoint()349 static inline void* GetQuickInstrumentationEntryPoint() {
350   return reinterpret_cast<void*>(art_quick_instrumentation_entry);
351 }
352 
353 // The return_pc of instrumentation exit stub.
354 extern "C" void art_quick_instrumentation_exit();
GetQuickInstrumentationExitPc()355 static inline uintptr_t GetQuickInstrumentationExitPc() {
356   return reinterpret_cast<uintptr_t>(art_quick_instrumentation_exit);
357 }
358 
359 extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
GetPortableToInterpreterBridge()360 static inline const void* GetPortableToInterpreterBridge() {
361   return reinterpret_cast<void*>(art_portable_to_interpreter_bridge);
362 }
363 
364 extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
GetQuickToInterpreterBridge()365 static inline const void* GetQuickToInterpreterBridge() {
366   return reinterpret_cast<void*>(art_quick_to_interpreter_bridge);
367 }
368 
369 // Return address of interpreter stub.
GetCompiledCodeToInterpreterBridge()370 static inline const void* GetCompiledCodeToInterpreterBridge() {
371 #if defined(ART_USE_PORTABLE_COMPILER)
372   return GetPortableToInterpreterBridge();
373 #else
374   return GetQuickToInterpreterBridge();
375 #endif
376 }
377 
378 
GetPortableResolutionTrampoline(ClassLinker * class_linker)379 static inline const void* GetPortableResolutionTrampoline(ClassLinker* class_linker) {
380   return class_linker->GetPortableResolutionTrampoline();
381 }
382 
GetQuickResolutionTrampoline(ClassLinker * class_linker)383 static inline const void* GetQuickResolutionTrampoline(ClassLinker* class_linker) {
384   return class_linker->GetQuickResolutionTrampoline();
385 }
386 
387 // Return address of resolution trampoline stub for defined compiler.
GetResolutionTrampoline(ClassLinker * class_linker)388 static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) {
389 #if defined(ART_USE_PORTABLE_COMPILER)
390   return GetPortableResolutionTrampoline(class_linker);
391 #else
392   return GetQuickResolutionTrampoline(class_linker);
393 #endif
394 }
395 
396 extern "C" void art_portable_proxy_invoke_handler();
GetPortableProxyInvokeHandler()397 static inline const void* GetPortableProxyInvokeHandler() {
398   return reinterpret_cast<void*>(art_portable_proxy_invoke_handler);
399 }
400 
401 extern "C" void art_quick_proxy_invoke_handler();
GetQuickProxyInvokeHandler()402 static inline const void* GetQuickProxyInvokeHandler() {
403   return reinterpret_cast<void*>(art_quick_proxy_invoke_handler);
404 }
405 
GetProxyInvokeHandler()406 static inline const void* GetProxyInvokeHandler() {
407 #if defined(ART_USE_PORTABLE_COMPILER)
408   return GetPortableProxyInvokeHandler();
409 #else
410   return GetQuickProxyInvokeHandler();
411 #endif
412 }
413 
414 extern "C" void* art_jni_dlsym_lookup_stub(JNIEnv*, jobject);
GetJniDlsymLookupStub()415 static inline void* GetJniDlsymLookupStub() {
416   return reinterpret_cast<void*>(art_jni_dlsym_lookup_stub);
417 }
418 
419 }  // namespace art
420 
421 #endif  // ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_
422