blob: c5121a99fe5f718e824db5c7fa3f355b5a46f8e8 [file] [log] [blame]
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -08001// Copyright 2012 Google Inc. All Rights Reserved.
2
3#ifndef ART_SRC_RUNTIME_SUPPORT_COMMON_H_
4#define ART_SRC_RUNTIME_SUPPORT_COMMON_H_
5
6#include "class_linker.h"
7#include "constants.h"
8#include "object.h"
9#include "object_utils.h"
10#include "thread.h"
11
12#include <stdint.h>
13
14namespace art {
15
16class Array;
17class Class;
18class Field;
19class Method;
20class Object;
21
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -080022static inline void ThrowNewIllegalAccessErrorClass(Thread* self,
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -080023 Class* referrer,
24 Class* accessed) {
25 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
26 "illegal class access: '%s' -> '%s'",
27 PrettyDescriptor(referrer).c_str(),
28 PrettyDescriptor(accessed).c_str());
29}
30
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -080031static inline void
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -080032ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self,
33 Class* referrer,
34 Class* accessed,
35 const Method* caller,
36 const Method* called,
37 InvokeType type) {
38 std::ostringstream type_stream;
39 type_stream << type;
40 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
41 "illegal class access ('%s' -> '%s')"
42 "in attempt to invoke %s method '%s' from '%s'",
43 PrettyDescriptor(referrer).c_str(),
44 PrettyDescriptor(accessed).c_str(),
45 type_stream.str().c_str(),
46 PrettyMethod(called).c_str(),
47 PrettyMethod(caller).c_str());
48}
49
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -080050static inline void
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -080051ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
52 const Method* referrer,
53 const Method* interface_method,
54 Object* this_object) {
55 self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
56 "class '%s' does not implement interface '%s' in call to '%s' from '%s'",
57 PrettyDescriptor(this_object->GetClass()).c_str(),
58 PrettyDescriptor(interface_method->GetDeclaringClass()).c_str(),
59 PrettyMethod(interface_method).c_str(), PrettyMethod(referrer).c_str());
60}
61
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -080062static inline void ThrowNewIllegalAccessErrorField(Thread* self,
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -080063 Class* referrer,
64 Field* accessed) {
65 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
66 "Field '%s' is inaccessible to class '%s'",
67 PrettyField(accessed, false).c_str(),
68 PrettyDescriptor(referrer).c_str());
69}
70
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -080071static inline void ThrowNewIllegalAccessErrorFinalField(Thread* self,
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -080072 const Method* referrer,
73 Field* accessed) {
74 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
75 "Final field '%s' cannot be written to by method '%s'",
76 PrettyField(accessed, false).c_str(),
77 PrettyMethod(referrer).c_str());
78}
79
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -080080static inline void ThrowNewIllegalAccessErrorMethod(Thread* self,
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -080081 Class* referrer,
82 Method* accessed) {
83 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
84 "Method '%s' is inaccessible to class '%s'",
85 PrettyMethod(accessed).c_str(),
86 PrettyDescriptor(referrer).c_str());
87}
88
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -080089static inline void ThrowNullPointerExceptionForFieldAccess(Thread* self,
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -080090 Field* field,
91 bool is_read) {
92 self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
93 "Attempt to %s field '%s' on a null object reference",
94 is_read ? "read from" : "write to",
95 PrettyField(field, true).c_str());
96}
97
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -080098static inline void ThrowNullPointerExceptionForMethodAccess(Thread* self,
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -080099 Method* caller,
100 uint32_t method_idx,
101 InvokeType type) {
102 const DexFile& dex_file =
103 Runtime::Current()->GetClassLinker()->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
104 std::ostringstream type_stream;
105 type_stream << type;
106 self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
Ian Rogers98d39882012-03-15 01:42:12 -0700107 "Attempt to invoke %s method '%s' on a null object reference",
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -0800108 type_stream.str().c_str(),
Ian Rogers98d39882012-03-15 01:42:12 -0700109 PrettyMethod(method_idx, dex_file, true).c_str());
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -0800110}
111
112// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
113// cannot be resolved, throw an error. If it can, use it to create an instance.
114// When verification/compiler hasn't been able to verify access, optionally perform an access
115// check.
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -0800116static inline Object* AllocObjectFromCode(uint32_t type_idx, Method* method, Thread* self,
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -0800117 bool access_check) {
118 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
119 Runtime* runtime = Runtime::Current();
120 if (UNLIKELY(klass == NULL)) {
121 klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
122 if (klass == NULL) {
123 DCHECK(self->IsExceptionPending());
124 return NULL; // Failure
125 }
126 }
127 if (access_check) {
128 if (UNLIKELY(!klass->IsInstantiable())) {
129 self->ThrowNewException("Ljava/lang/InstantiationError;",
130 PrettyDescriptor(klass).c_str());
131 return NULL; // Failure
132 }
133 Class* referrer = method->GetDeclaringClass();
134 if (UNLIKELY(!referrer->CanAccess(klass))) {
135 ThrowNewIllegalAccessErrorClass(self, referrer, klass);
136 return NULL; // Failure
137 }
138 }
139 if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
140 DCHECK(self->IsExceptionPending());
141 return NULL; // Failure
142 }
143 return klass->AllocObject();
144}
145
146// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
147// it cannot be resolved, throw an error. If it can, use it to create an array.
148// When verification/compiler hasn't been able to verify access, optionally perform an access
149// check.
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -0800150static inline Array* AllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -0800151 Thread* self, bool access_check) {
152 if (UNLIKELY(component_count < 0)) {
153 Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
154 component_count);
155 return NULL; // Failure
156 }
157 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
158 if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
159 klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
160 if (klass == NULL) { // Error
161 DCHECK(Thread::Current()->IsExceptionPending());
162 return NULL; // Failure
163 }
164 CHECK(klass->IsArrayClass()) << PrettyClass(klass);
165 }
166 if (access_check) {
167 Class* referrer = method->GetDeclaringClass();
168 if (UNLIKELY(!referrer->CanAccess(klass))) {
169 ThrowNewIllegalAccessErrorClass(self, referrer, klass);
170 return NULL; // Failure
171 }
172 }
173 return Array::Alloc(klass, component_count);
174}
175
176extern Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
177 Thread* self, bool access_check);
178
179extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
180 bool is_static, bool is_primitive, bool is_set,
181 size_t expected_size);
182
183// Fast path field resolution that can't throw exceptions
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -0800184static inline Field* FindFieldFast(uint32_t field_idx, const Method* referrer, bool is_primitive,
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -0800185 size_t expected_size, bool is_set) {
186 Field* resolved_field = referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
187 if (UNLIKELY(resolved_field == NULL)) {
188 return NULL;
189 }
190 Class* fields_class = resolved_field->GetDeclaringClass();
191 // Check class is initiliazed or initializing
192 if (UNLIKELY(!fields_class->IsInitializing())) {
193 return NULL;
194 }
195 Class* referring_class = referrer->GetDeclaringClass();
196 if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
197 !referring_class->CanAccessMember(fields_class,
198 resolved_field->GetAccessFlags()) ||
199 (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
200 // illegal access
201 return NULL;
202 }
203 FieldHelper fh(resolved_field);
204 if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
205 fh.FieldSize() != expected_size)) {
206 return NULL;
207 }
208 return resolved_field;
209}
210
211// Fast path method resolution that can't throw exceptions
Shih-wei Liaod9c7ad32012-03-08 02:01:18 -0800212static inline Method* FindMethodFast(uint32_t method_idx, Object* this_object, const Method* referrer,
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -0800213 bool access_check, InvokeType type) {
214 bool is_direct = type == kStatic || type == kDirect;
215 if (UNLIKELY(this_object == NULL && !is_direct)) {
216 return NULL;
217 }
218 Method* resolved_method =
219 referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
220 if (UNLIKELY(resolved_method == NULL)) {
221 return NULL;
222 }
223 if (access_check) {
224 Class* methods_class = resolved_method->GetDeclaringClass();
225 Class* referring_class = referrer->GetDeclaringClass();
226 if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
227 !referring_class->CanAccessMember(methods_class,
228 resolved_method->GetAccessFlags()))) {
229 // potential illegal access
230 return NULL;
231 }
232 }
233 if (type == kInterface) { // Most common form of slow path dispatch.
234 return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
235 } else if (is_direct) {
236 return resolved_method;
237 } else if (type == kSuper) {
238 return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->
239 Get(resolved_method->GetMethodIndex());
240 } else {
241 DCHECK(type == kVirtual);
242 return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
243 }
244}
245
246extern Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
247 Thread* self, bool access_check, InvokeType type);
248
Shih-wei Liao399ed3f2012-03-08 01:27:04 -0800249extern Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
250 bool can_run_clinit, bool verify_access);
251
252static inline String* ResolveStringFromCode(const Method* referrer, uint32_t string_idx) {
253 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
254 return class_linker->ResolveString(string_idx, referrer);
255}
256
Shih-wei Liaob0ee9d72012-03-07 16:39:26 -0800257} // namespace art
258
259#endif // ART_SRC_RUNTIME_SUPPORT_COMMON_H_