blob: f323190dbae030538c5ae56644258fa1baee1ba3 [file] [log] [blame]
Ian Rogers6d4d9fc2011-11-30 16:24:48 -08001/*
2 * Copyright (C) 2011 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_SRC_OBJECT_UTILS_H_
18#define ART_SRC_OBJECT_UTILS_H_
19
20#include "class_linker.h"
21#include "dex_cache.h"
22#include "dex_file.h"
23#include "object.h"
24#include "runtime.h"
25
26#include <string>
27
28namespace art {
29
30class ClassHelper {
31 public:
32 ClassHelper() : class_def_(NULL), class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL),
33 interface_type_list_(NULL), klass_(NULL) {}
34 ClassHelper(const Class* c) : class_def_(NULL), class_linker_(NULL), dex_cache_(NULL),
35 dex_file_(NULL), interface_type_list_(NULL), klass_(c) {}
36 ClassHelper(const Class* c, ClassLinker* l) : class_def_(NULL), class_linker_(l),
37 dex_cache_(NULL), dex_file_(NULL), interface_type_list_(NULL), klass_(c) {}
38
39 void ChangeClass(const Class* new_c) {
40 DCHECK(new_c != NULL);
41 if (dex_cache_ != NULL) {
42 DexCache* new_c_dex_cache = new_c->GetDexCache();
43 if (new_c_dex_cache != dex_cache_) {
44 dex_cache_ = new_c_dex_cache;
45 dex_file_ = NULL;
46 }
47 }
48 klass_ = new_c;
49 interface_type_list_ = NULL;
50 class_def_ = NULL;
51 }
52
53 std::string GetDescriptor() {
54 if (klass_->IsArrayClass()) {
55 std::string result = "[";
56 const Class* saved_klass = klass_;
57 ChangeClass(klass_->GetComponentType());
58 result += GetDescriptor();
59 ChangeClass(saved_klass);
60 return result;
61 } else if (klass_->IsPrimitive()){
62 std::string result;
63 result += Primitive::DescriptorChar(klass_->GetPrimitiveType());
64 return result;
65 } else if (klass_->IsProxyClass()) {
66 return GetClassLinker()->GetDescriptorForProxy(klass_);
67 } else {
68 const DexFile& dex_file = GetDexFile();
69 const DexFile::TypeId& type_id = dex_file.GetTypeId(klass_->GetDexTypeIndex());
70 return dex_file.GetTypeDescriptor(type_id);
71 }
72 }
73 const DexFile::ClassDef* GetClassDef() {
74 const DexFile::ClassDef* result = class_def_;
75 if (result == NULL) {
76 result = GetDexFile().FindClassDef(GetDescriptor());
77 class_def_ = result;
78 }
79 return result;
80 }
81 uint32_t NumInterfaces() {
82 if (klass_->IsPrimitive()) {
83 return 0;
84 } else if (klass_->IsArrayClass()) {
85 return 2;
86 } else {
87 CHECK(!klass_->IsProxyClass());
88 const DexFile::TypeList* interfaces = GetInterfaceTypeList();
89 if (interfaces == NULL) {
90 return 0;
91 } else {
92 return interfaces->Size();
93 }
94 }
95 }
96 uint16_t GetInterfaceTypeIdx(uint32_t idx) {
97 DCHECK(!klass_->IsPrimitive());
98 DCHECK(!klass_->IsArrayClass());
99 return GetInterfaceTypeList()->GetTypeItem(idx).type_idx_;
100 }
101 Class* GetInterface(uint32_t idx) {
102 DCHECK(!klass_->IsPrimitive());
103 if (klass_->IsArrayClass()) {
104 if (idx == 0) {
105 return GetClassLinker()->FindSystemClass("Ljava/lang/Cloneable;");
106 } else {
107 DCHECK_EQ(1U, idx);
108 return GetClassLinker()->FindSystemClass("Ljava/io/Serializable;");
109 }
110 } else {
111 uint16_t type_idx = GetInterfaceTypeIdx(idx);
112 Class* interface = GetDexCache()->GetResolvedType(type_idx);
113 if (interface == NULL) {
114 interface = GetClassLinker()->ResolveType(GetDexFile(), type_idx, klass_);
115 CHECK(interface != NULL || Thread::Current()->IsExceptionPending());
116 }
117 return interface;
118 }
119 }
120 const char* GetSourceFile() {
121 std::string descriptor = GetDescriptor();
122 const DexFile& dex_file = GetDexFile();
123 const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor);
124 if (dex_class_def == NULL) {
125 return NULL;
126 } else {
127 return dex_file.GetSourceFile(*dex_class_def);
128 }
129 }
130 std::string GetLocation() {
131 return GetDexCache()->GetLocation()->ToModifiedUtf8();
132 }
133
134 const DexFile& GetDexFile() {
135 const DexFile* result = dex_file_;
136 if (result == NULL) {
137 const DexCache* dex_cache = GetDexCache();
138 result = &GetClassLinker()->FindDexFile(dex_cache);
139 dex_file_ = result;
140 }
141 return *result;
142 }
143
144 private:
145 const DexFile::TypeList* GetInterfaceTypeList() {
146 const DexFile::TypeList* result = interface_type_list_;
147 if (result == NULL) {
148 const DexFile::ClassDef* class_def = GetClassDef();
149 if (class_def != NULL) {
150 result = GetDexFile().GetInterfacesList(*class_def);
151 interface_type_list_ = result;
152 }
153 }
154 return result;
155 }
156 DexCache* GetDexCache() {
157 DexCache* result = dex_cache_;
158 if (result == NULL) {
159 result = klass_->GetDexCache();
160 dex_cache_ = result;
161 }
162 return result;
163 }
164 ClassLinker* GetClassLinker() {
165 ClassLinker* result = class_linker_;
166 if (result == NULL) {
167 result = Runtime::Current()->GetClassLinker();
168 class_linker_ = result;
169 }
170 return result;
171 }
172
173 const DexFile::ClassDef* class_def_;
174 ClassLinker* class_linker_;
175 DexCache* dex_cache_;
176 const DexFile* dex_file_;
177 const DexFile::TypeList* interface_type_list_;
178 const Class* klass_;
179
180 DISALLOW_COPY_AND_ASSIGN(ClassHelper);
181};
182
183class FieldHelper {
184 public:
185 FieldHelper() : class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL), field_(NULL) {}
186 FieldHelper(const Field* f) : class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL), field_(f) {}
187 FieldHelper(const Field* f, ClassLinker* l) : class_linker_(l), dex_cache_(NULL), dex_file_(NULL),
188 field_(f) {}
189
190 void ChangeField(const Field* new_f) {
191 DCHECK(new_f != NULL);
192 if (dex_cache_ != NULL) {
193 DexCache* new_f_dex_cache = new_f->GetDeclaringClass()->GetDexCache();
194 if (new_f_dex_cache != dex_cache_) {
195 dex_cache_ = new_f_dex_cache;
196 dex_file_ = NULL;
197 }
198 }
199 field_ = new_f;
200 }
201 const char* GetName() {
202 const DexFile& dex_file = GetDexFile();
203 return dex_file.GetFieldName(dex_file.GetFieldId(field_->GetDexFieldIndex()));
204 }
205 String* GetNameAsString() {
206 const DexFile& dex_file = GetDexFile();
207 const DexFile::FieldId& field_id = dex_file.GetFieldId(field_->GetDexFieldIndex());
208 return GetClassLinker()->ResolveString(dex_file, field_id.name_idx_, GetDexCache());
209 }
210 Class* GetType() {
211 const DexFile& dex_file = GetDexFile();
212 const DexFile::FieldId& field_id = dex_file.GetFieldId(field_->GetDexFieldIndex());
213 Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_);
214 if (type == NULL) {
215 type = GetClassLinker()->ResolveType(field_id.type_idx_, field_);
216 CHECK(type != NULL || Thread::Current()->IsExceptionPending());
217 }
218 return type;
219 }
220 const char* GetTypeDescriptor() {
221 const DexFile& dex_file = GetDexFile();
222 const DexFile::FieldId& field_id = dex_file.GetFieldId(field_->GetDexFieldIndex());
223 return dex_file.GetFieldTypeDescriptor(field_id);
224 }
225 Primitive::Type GetTypeAsPrimitiveType() {
226 return Primitive::GetType(GetTypeDescriptor()[0]);
227 }
228 bool IsPrimitiveType() {
229 Primitive::Type type = GetTypeAsPrimitiveType();
230 return type != Primitive::kPrimNot;
231 }
232 size_t FieldSize() {
233 Primitive::Type type = GetTypeAsPrimitiveType();
234 return Primitive::FieldSize(type);
235 }
236 const char* GetDeclaringClassDescriptor() {
237 uint16_t type_idx = field_->GetDeclaringClass()->GetDexTypeIndex();
238 const DexFile& dex_file = GetDexFile();
239 return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx));
240 }
241
242 private:
243 DexCache* GetDexCache() {
244 DexCache* result = dex_cache_;
245 if (result == NULL) {
246 result = field_->GetDeclaringClass()->GetDexCache();
247 dex_cache_ = result;
248 }
249 return result;
250 }
251 ClassLinker* GetClassLinker() {
252 ClassLinker* result = class_linker_;
253 if (result == NULL) {
254 result = Runtime::Current()->GetClassLinker();
255 class_linker_ = result;
256 }
257 return result;
258 }
259 const DexFile& GetDexFile() {
260 const DexFile* result = dex_file_;
261 if (result == NULL) {
262 const DexCache* dex_cache = GetDexCache();
263 result = &GetClassLinker()->FindDexFile(dex_cache);
264 dex_file_ = result;
265 }
266 return *result;
267 }
268
269 ClassLinker* class_linker_;
270 DexCache* dex_cache_;
271 const DexFile* dex_file_;
272 const Field* field_;
273
274 DISALLOW_COPY_AND_ASSIGN(FieldHelper);
275};
276
277class MethodHelper {
278 public:
279 MethodHelper() : class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL), method_(NULL),
280 shorty_(NULL), shorty_len_(0) {}
281 MethodHelper(const Method* m) : class_linker_(NULL), dex_cache_(NULL), dex_file_(NULL),
282 method_(NULL), shorty_(NULL), shorty_len_(0) {
283 SetMethod(m);
284 }
285 MethodHelper(const Method* m, ClassLinker* l) : class_linker_(l), dex_cache_(NULL),
286 dex_file_(NULL), method_(NULL), shorty_(NULL), shorty_len_(0) {
287 SetMethod(m);
288 }
289
290 void ChangeMethod(Method* new_m) {
291 DCHECK(new_m != NULL);
292 if (dex_cache_ != NULL) {
293 Class* klass = new_m->GetDeclaringClass();
294 if (klass->IsProxyClass()) {
295 dex_cache_ = NULL;
296 dex_file_ = NULL;
297 } else {
298 DexCache* new_m_dex_cache = klass->GetDexCache();
299 if (new_m_dex_cache != dex_cache_) {
300 dex_cache_ = new_m_dex_cache;
301 dex_file_ = NULL;
302 }
303 }
304 }
305 SetMethod(new_m);
306 shorty_ = NULL;
307 }
308 const char* GetName() {
309 const DexFile& dex_file = GetDexFile();
310 return dex_file.GetMethodName(dex_file.GetMethodId(method_->GetDexMethodIndex()));
311 }
312 String* GetNameAsString() {
313 const DexFile& dex_file = GetDexFile();
314 const DexFile::MethodId& method_id = dex_file.GetMethodId(method_->GetDexMethodIndex());
315 return GetClassLinker()->ResolveString(dex_file, method_id.name_idx_, GetDexCache());
316 }
317 const char* GetShorty() {
318 const char* result = shorty_;
319 if (result == NULL) {
320 const DexFile& dex_file = GetDexFile();
321 result = dex_file.GetMethodShorty(dex_file.GetMethodId(method_->GetDexMethodIndex()),
322 &shorty_len_);
323 shorty_ = result;
324 }
325 return result;
326 }
327 int32_t GetShortyLength() {
328 if (shorty_ == NULL) {
329 GetShorty();
330 }
331 return shorty_len_;
332 }
333 const std::string GetSignature() {
334 const DexFile& dex_file = GetDexFile();
335 return dex_file.GetMethodSignature(dex_file.GetMethodId(method_->GetDexMethodIndex()));
336 }
337 const DexFile::ProtoId& GetPrototype() {
338 const DexFile& dex_file = GetDexFile();
339 return dex_file.GetMethodPrototype(dex_file.GetMethodId(method_->GetDexMethodIndex()));
340 }
341 const DexFile::TypeList* GetParameterTypeList() {
342 const DexFile::ProtoId& proto = GetPrototype();
343 return GetDexFile().GetProtoParameters(proto);
344 }
345 ObjectArray<Class>* GetParameterTypes() {
346 const DexFile::TypeList* params = GetParameterTypeList();
347 Class* array_class = GetClassLinker()->FindSystemClass("[Ljava/lang/Class;");
348 uint32_t num_params = params == NULL ? 0 : params->Size();
349 ObjectArray<Class>* result = ObjectArray<Class>::Alloc(array_class, num_params);
350 for (uint32_t i = 0; i < num_params; i++) {
351 Class* param_type = GetClassFromTypeIdx(params->GetTypeItem(i).type_idx_);
352 result->Set(i, param_type);
353 }
354 return result;
355 }
356 Class* GetReturnType() {
357 const DexFile& dex_file = GetDexFile();
358 const DexFile::MethodId& method_id = dex_file.GetMethodId(method_->GetDexMethodIndex());
359 const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(method_id);
360 uint16_t return_type_idx = proto_id.return_type_idx_;
361 return GetClassFromTypeIdx(return_type_idx);
362 }
363 const char* GetReturnTypeDescriptor() {
364 const DexFile& dex_file = GetDexFile();
365 const DexFile::MethodId& method_id = dex_file.GetMethodId(method_->GetDexMethodIndex());
366 const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(method_id);
367 uint16_t return_type_idx = proto_id.return_type_idx_;
368 return dex_file.GetTypeDescriptor(dex_file.GetTypeId(return_type_idx));
369 }
370 int32_t GetLineNumFromNativePC(uintptr_t raw_pc) {
371 const DexFile& dex_file = GetDexFile();
372 return dex_file.GetLineNumFromPC(method_, method_->ToDexPC(raw_pc));
373 }
374 const char* GetDeclaringClassDescriptor() {
375 Class* klass = method_->GetDeclaringClass();
376 CHECK(!klass->IsProxyClass());
377 uint16_t type_idx = klass->GetDexTypeIndex();
378 const DexFile& dex_file = GetDexFile();
379 return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx));
380 }
381 const char* GetDeclaringClassSourceFile() {
382 const char* descriptor = GetDeclaringClassDescriptor();
383 const DexFile& dex_file = GetDexFile();
384 const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor);
385 if (dex_class_def == NULL) {
386 return NULL;
387 } else {
388 return dex_file.GetSourceFile(*dex_class_def);
389 }
390 }
391 bool IsStatic() {
392 return method_->IsStatic();
393 }
394 bool IsClassInitializer() {
395 return IsStatic() && StringPiece(GetName()) == "<clinit>";
396 }
397 size_t NumArgs() {
398 // "1 +" because the first in Args is the receiver.
399 // "- 1" because we don't count the return type.
400 return (IsStatic() ? 0 : 1) + GetShortyLength() - 1;
401 }
402 // Is the specified parameter a long or double, where parameter 0 is 'this' for instance methods
403 bool IsParamALongOrDouble(size_t param) {
404 CHECK_LT(param, NumArgs());
405 if (IsStatic()) {
406 param++; // 0th argument must skip return value at start of the shorty
407 } else if (param == 0) {
408 return false; // this argument
409 }
410 char ch = GetShorty()[param];
411 return (ch == 'J' || ch == 'D');
412 }
413 // Is the specified parameter a reference, where parameter 0 is 'this' for instance methods
414 bool IsParamAReference(size_t param) {
415 CHECK_LT(param, NumArgs());
416 if (IsStatic()) {
417 param++; // 0th argument must skip return value at start of the shorty
418 } else if (param == 0) {
419 return true; // this argument
420 }
421 return GetShorty()[param] == 'L'; // An array also has a shorty character of 'L' (not '[')
422 }
423 bool HasSameNameAndSignature(MethodHelper* other) {
424 StringPiece name(GetName());
425 StringPiece other_name(other->GetName());
426 if (name != other_name) {
427 return false;
428 }
429 if (GetDexCache() == other->GetDexCache()) {
430 const DexFile& dex_file = GetDexFile();
431 const DexFile::MethodId& mid = dex_file.GetMethodId(method_->GetDexMethodIndex());
432 const DexFile::MethodId& other_mid =
433 dex_file.GetMethodId(other->method_->GetDexMethodIndex());
434 return mid.proto_idx_ == other_mid.proto_idx_;
435 }
436 return GetSignature() == other->GetSignature();
437 }
438 const DexFile::CodeItem* GetCodeItem() {
439 return GetDexFile().GetCodeItem(method_->GetCodeItemOffset());
440 }
Ian Rogers6f1dfe42011-12-08 17:28:34 -0800441 bool IsResolvedTypeIdx(uint16_t type_idx) const {
442 return method_->GetDexCacheResolvedTypes()->Get(type_idx) != NULL;
443 }
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800444 Class* GetClassFromTypeIdx(uint16_t type_idx) {
445 Class* type = method_->GetDexCacheResolvedTypes()->Get(type_idx);
446 if (type == NULL) {
447 type = GetClassLinker()->ResolveType(type_idx, method_);
448 CHECK(type != NULL || Thread::Current()->IsExceptionPending());
449 }
450 return type;
451 }
452 const char* GetTypeDescriptorFromTypeIdx(uint16_t type_idx) {
453 const DexFile& dex_file = GetDexFile();
454 return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx));
455 }
456 Class* GetDexCacheResolvedType(uint16_t type_idx) {
457 return GetDexCache()->GetResolvedType(type_idx);
458 }
459 const DexFile& GetDexFile() {
460 const DexFile* result = dex_file_;
461 if (result == NULL) {
462 const DexCache* dex_cache = GetDexCache();
463 result = &GetClassLinker()->FindDexFile(dex_cache);
464 dex_file_ = result;
465 }
466 return *result;
467 }
468 private:
469 // Set the method_ field, for proxy methods looking up the interface method via the resolved
470 // methods table.
471 void SetMethod(const Method* method) {
472 if (method != NULL) {
473 Class* klass = method->GetDeclaringClass();
474 if (klass->IsProxyClass()) {
475 method = method->GetDexCacheResolvedMethods()->Get(method->GetDexMethodIndex());
476 CHECK(method != NULL);
477 }
478 }
479 method_ = method;
480 }
481 DexCache* GetDexCache() {
482 DexCache* result = dex_cache_;
483 if (result == NULL) {
484 Class* klass = method_->GetDeclaringClass();
485 result = klass->GetDexCache();
486 dex_cache_ = result;
487 }
488 return result;
489 }
490 ClassLinker* GetClassLinker() {
491 ClassLinker* result = class_linker_;
492 if (result == NULL) {
493 result = Runtime::Current()->GetClassLinker();
494 class_linker_ = result;
495 }
496 return result;
497 }
498
499 ClassLinker* class_linker_;
500 DexCache* dex_cache_;
501 const DexFile* dex_file_;
502 const Method* method_;
503 const char* shorty_;
504 int32_t shorty_len_;
505
506 DISALLOW_COPY_AND_ASSIGN(MethodHelper);
507};
508
509} // namespace art
510
511#endif // ART_SRC_OBJECT_UTILS_H_