blob: 2ea7f99bc03620c59c7c1aad5c1c9bce8d1a0400 [file] [log] [blame]
Elliott Hughes0f3c5532012-03-30 14:51:51 -07001/*
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 */
buzbee54330722011-08-23 16:46:55 -070016
17#ifndef ART_SRC_RUNTIME_SUPPORT_H_
18#define ART_SRC_RUNTIME_SUPPORT_H_
19
Shih-wei Liao2d831012011-09-28 22:06:53 -070020#include "class_linker.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070021#include "dex_file.h"
Elliott Hughes0f3c5532012-03-30 14:51:51 -070022#include "invoke_type.h"
Shih-wei Liao2d831012011-09-28 22:06:53 -070023#include "object.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070024#include "object_utils.h"
25#include "thread.h"
Ian Rogers776ac1f2012-04-13 23:36:36 -070026#include "verifier/method_verifier.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070027
28extern "C" void art_proxy_invoke_handler();
29extern "C" void art_work_around_app_jni_bugs();
Shih-wei Liao2d831012011-09-28 22:06:53 -070030
jeffhao41005dd2012-05-09 17:58:52 -070031extern "C" double art_l2d(int64_t l);
32extern "C" float art_l2f(int64_t l);
33extern "C" int64_t art_d2l(double d);
34extern "C" int32_t art_d2i(double d);
35extern "C" int64_t art_f2l(float f);
36extern "C" int32_t art_f2i(float f);
37
Shih-wei Liao2d831012011-09-28 22:06:53 -070038namespace art {
39
Ian Rogers57b86d42012-03-27 16:05:41 -070040class Array;
41class Class;
42class Field;
43class Method;
44class Object;
45
46// Helpers to give consistent descriptive exception messages
Ian Rogers00f7d0e2012-07-19 15:28:27 -070047void ThrowNewIllegalAccessErrorClass(Thread* self, Class* referrer, Class* accessed)
48 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -070049void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self, Class* referrer,
50 Class* accessed,
51 const Method* caller,
52 const Method* called,
Ian Rogers00f7d0e2012-07-19 15:28:27 -070053 InvokeType type)
54 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -070055void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
56 const Method* referrer,
57 const Method* interface_method,
Ian Rogers00f7d0e2012-07-19 15:28:27 -070058 Object* this_object)
59 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
60void ThrowNewIllegalAccessErrorField(Thread* self, Class* referrer, Field* accessed)
61 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
62void ThrowNewIllegalAccessErrorFinalField(Thread* self, const Method* referrer, Field* accessed)
63 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -070064
Ian Rogers00f7d0e2012-07-19 15:28:27 -070065void ThrowNewIllegalAccessErrorMethod(Thread* self, Class* referrer, Method* accessed)
66 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
67void ThrowNullPointerExceptionForFieldAccess(Thread* self, Field* field, bool is_read)
68 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -070069void ThrowNullPointerExceptionForMethodAccess(Thread* self, Method* caller, uint32_t method_idx,
Ian Rogers00f7d0e2012-07-19 15:28:27 -070070 InvokeType type)
71 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
72void ThrowNullPointerExceptionFromDexPC(Thread* self, Method* caller, uint32_t dex_pc)
73 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
74void ThrowVerificationError(Thread* self, const Method* method, int32_t kind, int32_t ref)
75 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -070076
77std::string FieldNameFromIndex(const Method* method, uint32_t ref,
Ian Rogers00f7d0e2012-07-19 15:28:27 -070078 verifier::VerifyErrorRefType ref_type, bool access)
79 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -070080std::string MethodNameFromIndex(const Method* method, uint32_t ref,
Ian Rogers00f7d0e2012-07-19 15:28:27 -070081 verifier::VerifyErrorRefType ref_type, bool access)
82 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -070083
84// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
85// cannot be resolved, throw an error. If it can, use it to create an instance.
86// When verification/compiler hasn't been able to verify access, optionally perform an access
87// check.
88static inline Object* AllocObjectFromCode(uint32_t type_idx, Method* method, Thread* self,
Ian Rogers00f7d0e2012-07-19 15:28:27 -070089 bool access_check)
90 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
Ian Rogers57b86d42012-03-27 16:05:41 -070091 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
92 Runtime* runtime = Runtime::Current();
93 if (UNLIKELY(klass == NULL)) {
94 klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
95 if (klass == NULL) {
96 DCHECK(self->IsExceptionPending());
97 return NULL; // Failure
98 }
99 }
100 if (access_check) {
101 if (UNLIKELY(!klass->IsInstantiable())) {
102 self->ThrowNewException("Ljava/lang/InstantiationError;",
103 PrettyDescriptor(klass).c_str());
104 return NULL; // Failure
105 }
106 Class* referrer = method->GetDeclaringClass();
107 if (UNLIKELY(!referrer->CanAccess(klass))) {
108 ThrowNewIllegalAccessErrorClass(self, referrer, klass);
109 return NULL; // Failure
110 }
111 }
Ian Rogers0045a292012-03-31 21:08:41 -0700112 if (!runtime->GetClassLinker()->EnsureInitialized(klass, true, true)) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700113 DCHECK(self->IsExceptionPending());
114 return NULL; // Failure
115 }
116 return klass->AllocObject();
117}
118
119// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
120// it cannot be resolved, throw an error. If it can, use it to create an array.
121// When verification/compiler hasn't been able to verify access, optionally perform an access
122// check.
123static inline Array* AllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700124 Thread* self, bool access_check)
125 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700126 if (UNLIKELY(component_count < 0)) {
127 Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
128 component_count);
129 return NULL; // Failure
130 }
131 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
132 if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
133 klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
134 if (klass == NULL) { // Error
135 DCHECK(Thread::Current()->IsExceptionPending());
136 return NULL; // Failure
137 }
138 CHECK(klass->IsArrayClass()) << PrettyClass(klass);
139 }
140 if (access_check) {
141 Class* referrer = method->GetDeclaringClass();
142 if (UNLIKELY(!referrer->CanAccess(klass))) {
143 ThrowNewIllegalAccessErrorClass(self, referrer, klass);
144 return NULL; // Failure
145 }
146 }
147 return Array::Alloc(klass, component_count);
148}
149
Ian Rogersce9eca62011-10-07 17:11:03 -0700150extern Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700151 Thread* self, bool access_check)
152 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -0700153
Ian Rogers1bddec32012-02-04 12:27:34 -0800154extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
Ian Rogers57b86d42012-03-27 16:05:41 -0700155 bool is_static, bool is_primitive, bool is_set,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700156 size_t expected_size)
157 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -0700158
159// Fast path field resolution that can't throw exceptions
160static inline Field* FindFieldFast(uint32_t field_idx, const Method* referrer, bool is_primitive,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700161 size_t expected_size, bool is_set)
162 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700163 Field* resolved_field = referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
164 if (UNLIKELY(resolved_field == NULL)) {
165 return NULL;
166 }
167 Class* fields_class = resolved_field->GetDeclaringClass();
168 // Check class is initiliazed or initializing
169 if (UNLIKELY(!fields_class->IsInitializing())) {
170 return NULL;
171 }
172 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
189static inline Method* FindMethodFast(uint32_t method_idx, Object* this_object, const Method* referrer,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700190 bool access_check, InvokeType type)
191 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700192 bool is_direct = type == kStatic || type == kDirect;
193 if (UNLIKELY(this_object == NULL && !is_direct)) {
194 return NULL;
195 }
196 Method* resolved_method =
197 referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
198 if (UNLIKELY(resolved_method == NULL)) {
199 return NULL;
200 }
201 if (access_check) {
202 Class* methods_class = resolved_method->GetDeclaringClass();
203 Class* referring_class = referrer->GetDeclaringClass();
204 if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
205 !referring_class->CanAccessMember(methods_class,
206 resolved_method->GetAccessFlags()))) {
207 // potential illegal access
208 return NULL;
209 }
210 }
211 if (type == kInterface) { // Most common form of slow path dispatch.
212 return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
213 } else if (is_direct) {
214 return resolved_method;
215 } else if (type == kSuper) {
216 return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->
217 Get(resolved_method->GetMethodIndex());
218 } else {
219 DCHECK(type == kVirtual);
220 return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
221 }
222}
223
224extern Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700225 Thread* self, bool access_check, InvokeType type)
226 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -0700227
Elliott Hughesf3778f62012-01-26 14:14:35 -0800228extern Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700229 bool can_run_clinit, bool verify_access)
230 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
Ian Rogers57b86d42012-03-27 16:05:41 -0700231
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700232static inline String* ResolveStringFromCode(const Method* referrer, uint32_t string_idx)
233 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700234 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
235 return class_linker->ResolveString(string_idx, referrer);
236}
Shih-wei Liao2d831012011-09-28 22:06:53 -0700237
TDYa1273d71d802012-08-15 03:47:03 -0700238static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
239 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_)
240 UNLOCK_FUNCTION(monitor_lock_) {
241 // Save any pending exception over monitor exit call.
242 Throwable* saved_exception = NULL;
243 if (UNLIKELY(self->IsExceptionPending())) {
244 saved_exception = self->GetException();
245 self->ClearException();
246 }
247 // Decode locked object and unlock, before popping local references.
248 self->DecodeJObject(locked)->MonitorExit(self);
249 if (UNLIKELY(self->IsExceptionPending())) {
250 LOG(FATAL) << "Synchronized JNI code returning with an exception:\n"
251 << saved_exception->Dump()
252 << "\nEncountered second exception during implicit MonitorExit:\n"
253 << self->GetException()->Dump();
254 }
255 // Restore pending exception.
256 if (saved_exception != NULL) {
257 self->SetException(saved_exception);
258 }
259}
260
261static inline void CheckReferenceResult(Object* o, Thread* self)
262 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
263 if (o == NULL) {
264 return;
265 }
266 if (o == kInvalidIndirectRefObject) {
267 JniAbortF(NULL, "invalid reference returned from %s",
268 PrettyMethod(self->GetCurrentMethod()).c_str());
269 }
270 // Make sure that the result is an instance of the type this method was expected to return.
271 Method* m = self->GetCurrentMethod();
272 MethodHelper mh(m);
273 Class* return_type = mh.GetReturnType();
274
275 if (!o->InstanceOf(return_type)) {
276 JniAbortF(NULL, "attempt to return an instance of %s from %s",
277 PrettyTypeOf(o).c_str(), PrettyMethod(m).c_str());
278 }
279}
280
Shih-wei Liao2d831012011-09-28 22:06:53 -0700281} // namespace art
Ian Rogersad42e132011-09-17 20:23:33 -0700282
buzbee54330722011-08-23 16:46:55 -0700283#endif // ART_SRC_RUNTIME_SUPPORT_H_