Complete support for loading classes from a DEX file.
Change-Id: I1b9aa105fc78df170e83b259d8d04317c296a1b5
diff --git a/Android.common.mk b/Android.common.mk
index cc870d4..5bb20fa 100644
--- a/Android.common.mk
+++ b/Android.common.mk
@@ -44,6 +44,7 @@
src/dex_file.cc \
src/dex_instruction.cc \
src/memory_region.cc \
+ src/object.cc \
src/raw_dex_file.cc \
src/runtime.cc
diff --git a/src/dex_file.cc b/src/dex_file.cc
index a89baaf..1951af5 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -52,8 +52,7 @@
Class* DexFile::LoadClass(const RawDexFile::ClassDef& class_def) {
const byte* class_data = raw_->GetClassData(class_def);
- RawDexFile::ClassDataHeader header;
- raw_->DecodeClassDataHeader(&header, class_data);
+ RawDexFile::ClassDataHeader header = raw_->ReadClassDataHeader(&class_data);
const char* descriptor = raw_->GetClassDescriptor(class_def);
CHECK(descriptor != NULL);
@@ -61,9 +60,9 @@
// Allocate storage for the new class object.
size_t size = Class::Size(header.static_fields_size_);
Class* klass = Heap::AllocClass(size);
- CHECK(klass != NULL);
+ CHECK(klass != NULL); // TODO: throw an OOME
- //klass->klass_ = NULL; // TODO
+ klass->klass_ = NULL; // TODO
klass->descriptor_ = descriptor;
klass->access_flags_ = class_def.access_flags_;
klass->class_loader_ = NULL; // TODO
@@ -73,32 +72,70 @@
klass->super_ = reinterpret_cast<Class*>(class_def.superclass_idx_);
+ klass->num_sfields_ = header.static_fields_size_;
+ klass->num_ifields_ = header.instance_fields_size_;
+ klass->num_dmethods_ = header.direct_methods_size_;
+ klass->num_vmethods_ = header.virtual_methods_size_;
+
+ klass->source_file_ = raw_->dexGetSourceFile(class_def);
+
// Load class interfaces.
- LoadClassInterfaces(class_def, klass);
+ LoadInterfaces(class_def, klass);
// Load static fields.
- if (header.static_fields_size_ != 0) {
- for (size_t i = 0; i < header.static_fields_size_; ++i) {
- // TODO
+ if (klass->num_sfields_ != 0) {
+ uint32_t last_idx = 0;
+ for (size_t i = 0; i < klass->num_sfields_; ++i) {
+ RawDexFile::Field raw_field;
+ raw_->dexReadClassDataField(&class_data, &raw_field, &last_idx);
+ LoadField(klass, raw_field, &klass->sfields_[i]);
}
}
// Load instance fields.
- if (header.instance_fields_size_ != 0) {
- for (size_t i = 0; i < header.instance_fields_size_; ++i) {
- // TODO
+ if (klass->num_ifields_ != 0) {
+ // TODO: append instance fields to class object
+ klass->ifields_ = new IField[klass->num_ifields_];
+ uint32_t last_idx = 0;
+ for (size_t i = 0; i < klass->num_ifields_; ++i) {
+ RawDexFile::Field raw_field;
+ raw_->dexReadClassDataField(&class_data, &raw_field, &last_idx);
+ LoadField(klass, raw_field, &klass->ifields_[i]);
}
}
// Load direct methods.
+ if (klass->num_dmethods_ != 0) {
+ // TODO: append direct methods to class object
+ klass->dmethods_ = new Method[klass->num_dmethods_];
+ uint32_t last_idx = 0;
+ for (size_t i = 0; i < klass->num_dmethods_; ++i) {
+ RawDexFile::Method raw_method;
+ raw_->dexReadClassDataMethod(&class_data, &raw_method, &last_idx);
+ LoadMethod(klass, raw_method, &klass->dmethods_[i]);
+ // TODO: register maps
+ }
+ }
// Load virtual methods.
+ if (klass->num_vmethods_ != 0) {
+ // TODO: append virtual methods to class object
+ klass->vmethods_ = new Method[klass->num_vmethods_];
+ memset(klass->vmethods_, 0xff, sizeof(Method));
+ uint32_t last_idx = 0;
+ for (size_t i = 0; i < klass->num_vmethods_; ++i) {
+ RawDexFile::Method raw_method;
+ raw_->dexReadClassDataMethod(&class_data, &raw_method, &last_idx);
+ LoadMethod(klass, raw_method, &klass->vmethods_[i]);
+ // TODO: register maps
+ }
+ }
return klass;
}
-void DexFile::LoadClassInterfaces(const RawDexFile::ClassDef& class_def,
- Class* klass) {
+void DexFile::LoadInterfaces(const RawDexFile::ClassDef& class_def,
+ Class* klass) {
const RawDexFile::TypeList* list = raw_->GetInterfacesList(class_def);
if (list != NULL) {
klass->interface_count_ = list->Size();
@@ -110,19 +147,41 @@
}
}
-void DexFile::LoadSFields(Class* klass, const RawDexFile::Field* src,
- Field* dst) {
-
+void DexFile::LoadField(Class* klass, const RawDexFile::Field& src,
+ Field* dst) {
+ const RawDexFile::FieldId& field_id = raw_->GetFieldId(src.field_idx_);
+ dst->klass_ = klass;
+ dst->name_ = raw_->dexStringById(field_id.name_idx_);
+ dst->signature_ = raw_->dexStringByTypeIdx(field_id.type_idx_);
+ dst->access_flags_ = src.access_flags_;
}
-void DexFile::LoadIFields(Class* klass, const RawDexFile::Field* src,
- Field* dst) {
-}
-
-void DexFile::LoadMethod(Class* klass, const RawDexFile::Method* src,
+void DexFile::LoadMethod(Class* klass, const RawDexFile::Method& src,
Method* dst) {
+ const RawDexFile::MethodId& method_id = raw_->GetMethodId(src.method_idx_);
+ dst->klass_ = klass;
+ dst->name_ = raw_->dexStringById(method_id.name_idx_);
+ dst->dex_file_ = this;
+ dst->proto_idx_ = method_id.proto_idx_;
+ dst->shorty_ = raw_->GetShorty(method_id.proto_idx_);
+ dst->access_flags_ = src.access_flags_;
+
+ // TODO: check for finalize method
+
+ const RawDexFile::Code* code_item = raw_->GetCode(src);
+ if (code_item != NULL) {
+ dst->num_registers_ = code_item->registers_size_;
+ dst->num_ins_ = code_item->ins_size_;
+ dst->num_outs_ = code_item->outs_size_;
+ dst->insns_ = code_item->insns_;
+ } else {
+ uint16_t num_args = dst->NumArgRegisters();
+ if (!dst->IsStatic()) {
+ ++num_args;
+ }
+ dst->num_registers_ = dst->num_ins_ + num_args;
+ // TODO: native methods
+ }
}
-
-
} // namespace art
diff --git a/src/dex_file.h b/src/dex_file.h
index 3cd1a57..94ba33d 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -35,17 +35,11 @@
void Init();
- void LoadClassInterfaces(const RawDexFile::ClassDef& class_def,
- Class *klass);
+ void LoadInterfaces(const RawDexFile::ClassDef& class_def, Class *klass);
- void LoadSFields(Class* klass, const RawDexFile::Field* src,
- Field* dst);
+ void LoadField(Class* klass, const RawDexFile::Field& src, Field* dst);
- void LoadIFields(Class* klass, const RawDexFile::Field* src,
- Field* dst);
-
- void LoadMethod(Class* klass, const RawDexFile::Method* src,
- Method* dst);
+ void LoadMethod(Class* klass, const RawDexFile::Method& src, Method* dst);
// Table of contents for interned String objects.
String** strings_;
diff --git a/src/dex_file_test.cc b/src/dex_file_test.cc
index ff80e46..74adca3 100644
--- a/src/dex_file_test.cc
+++ b/src/dex_file_test.cc
@@ -30,6 +30,12 @@
Class* klass = dex->LoadClass("LNested;");
ASSERT_TRUE(klass != NULL);
+
+ uint32_t vmeth = klass->NumVirtualMethods();
+ EXPECT_EQ(vmeth, 0U);
+
+ uint32_t dmeth = klass->NumDirectMethods();
+ EXPECT_EQ(dmeth, 1U);
}
} // namespace art
diff --git a/src/object.cc b/src/object.cc
new file mode 100644
index 0000000..a4f41b7
--- /dev/null
+++ b/src/object.cc
@@ -0,0 +1,23 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "src/globals.h"
+#include "src/object.h"
+#include "src/logging.h"
+
+namespace art {
+
+uint32_t Method::NumArgRegisters() {
+ CHECK(shorty_ != NULL);
+ uint32_t num_registers = 0;
+ for (size_t i = 1; shorty_[0] != '\0'; ++i) {
+ char ch = shorty_[i];
+ if (ch == 'D' || ch == 'J') {
+ num_registers += 2;
+ } else {
+ num_registers += 1;
+ }
+ }
+ return num_registers;
+}
+
+} // namespace art
diff --git a/src/object.h b/src/object.h
index b7d3a50..e8d1ee1 100644
--- a/src/object.h
+++ b/src/object.h
@@ -4,6 +4,7 @@
#define ART_SRC_OBJECT_H_
#include "src/globals.h"
+#include "src/macros.h"
namespace art {
@@ -14,29 +15,75 @@
class InterfaceEntry;
class Monitor;
class Method;
+class Object;
class SField;
+union JValue {
+ uint8_t z;
+ int8_t b;
+ uint16_t c;
+ int16_t s;
+ int32_t i;
+ int64_t j;
+ float f;
+ double d;
+ Object* l;
+};
+
+static const uint32_t kAccPublic = 0x0001; // class, field, method, ic
+static const uint32_t kAccPrivate = 0x0002; // field, method, ic
+static const uint32_t kAccProtected = 0x0004; // field, method, ic
+static const uint32_t kAccStatic = 0x0008; // field, method, ic
+static const uint32_t kAccFinal = 0x0010; // class, field, method, ic
+static const uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives)
+static const uint32_t kAccSuper = 0x0020; // class (not used in Dalvik)
+static const uint32_t kAccVolatile = 0x0040; // field
+static const uint32_t kAccBridge = 0x0040; // method (1.5)
+static const uint32_t kAccTransient = 0x0080; // field
+static const uint32_t kAccVarargs = 0x0080; // method (1.5)
+static const uint32_t kAccNative = 0x0100; // method
+static const uint32_t kAccInterface = 0x0200; // class, ic
+static const uint32_t kAccAbstract = 0x0400; // class, method, ic
+static const uint32_t kAccStrict = 0x0800; // method
+static const uint32_t kAccSynthetic = 0x1000; // field, method, ic
+static const uint32_t kAccAnnotation = 0x2000; // class, ic (1.5)
+static const uint32_t kAccEnum = 0x4000; // class, field, ic (1.5)
+
+static const uint32_t kAccConstructor = 0x00010000; // method (Dalvik only)
+static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (Dalvik only)
+
+
class Object {
+ public:
Class* klass_;
Monitor* lock_;
};
class Field {
+ public:
+ // The class in which this field is declared.
Class* klass_;
+
+ const char* name_;
+
+ // e.g. "I", "[C", "Landroid/os/Debug;"
+ const char* signature_;
+
+ uint32_t access_flags_;
};
// Instance fields.
-class IField : Field {
- // TODO
+class IField : public Field {
+ uint32_t offset_;
};
// Static fields.
-class SField : Field {
- // TODO
+class SField : public Field {
+ JValue value_;
};
// Class objects.
-class Class : Object {
+class Class : public Object {
public:
enum ClassStatus {
kClassError = -1,
@@ -60,6 +107,15 @@
return OFFSETOF_MEMBER(Class, sfields_) + sizeof(SField) * num_sfields;
}
+ uint32_t NumDirectMethods() {
+ return num_dmethods_;
+ }
+
+ uint32_t NumVirtualMethods() {
+ return num_vmethods_;
+ }
+
+
public: // TODO: private
// leave space for instance data; we could access fields directly if
// we freeze the definition of java/lang/Class
@@ -76,7 +132,7 @@
char* descriptor_alloc_;
// access flags; low 16 bits are defined by VM spec
- uint32_t access_flags_;
+ uint32_t access_flags_; // TODO: make an instance field?
// VM-unique class serial number, nonzero, set very early
//uint32_t serial_number_;
@@ -101,7 +157,7 @@
// For array classes, the class object for base element, for
// instanceof/checkcast (for String[][][], this will be String).
// Otherwise, NULL.
- Class* array_element_class_;
+ Class* array_element_class_; // TODO: make an instance field
// For array classes, the number of array dimensions, e.g. int[][]
// is 2. Otherwise 0.
@@ -112,10 +168,10 @@
// The superclass, or NULL if this is java.lang.Object or a
// primitive type.
- Class* super_;
+ Class* super_; // TODO: make an instance field
// defining class loader, or NULL for the "bootstrap" system loader
- Object* class_loader_;
+ Object* class_loader_; // TODO: make an instance field
// initiating class loader list
// NOTE: for classes with low serialNumber, these are unused, and the
@@ -127,12 +183,12 @@
Class** interfaces_;
// static, private, and <init> methods
- int direct_method_count_;
- Method* direct_methods_;
+ uint32_t num_dmethods_;
+ Method* dmethods_;
// virtual methods defined in this class; invoked through vtable
- int virtual_method_count_;
- Method* virtual_methods_;
+ uint32_t num_vmethods_;
+ Method* vmethods_;
// Virtual method table (vtable), for use by "invoke-virtual". The
// vtable from the superclass is copied in, and virtual methods from
@@ -172,8 +228,10 @@
// All instance fields that refer to objects are guaranteed to be at
// the beginning of the field list. ifieldRefCount specifies the
// number of reference fields.
- int ifield_count_;
- int ifield_ref_count_; // number of fields that are object refs
+ uint32_t num_ifields_;
+
+ // number of fields that are object refs
+ uint32_t num_reference_ifields_;
IField* ifields_;
// bitmap of offsets of ifields
@@ -183,7 +241,7 @@
const char* source_file_;
// Static fields
- uint16_t num_sfields_;
+ uint32_t num_sfields_;
SField sfields_[]; // MUST be last item
};
@@ -206,7 +264,90 @@
class Method {
public:
- Class* klass;
+ // Returns true if the method is declared public.
+ bool IsPublic() {
+ return (access_flags_ & kAccPublic) != 0;
+ }
+
+ // Returns true if the method is declared private.
+ bool IsPrivate() {
+ return (access_flags_ & kAccPrivate) != 0;
+ }
+
+ // Returns true if the method is declared static.
+ bool IsStatic() {
+ return (access_flags_ & kAccStatic) != 0;
+ }
+
+ // Returns true if the method is declared native and synchronized.
+ bool IsSynchronized() {
+ return (access_flags_ & kAccSynchronized) != 0;
+ }
+
+ // Returns true if the method is not native and declared synchronized.
+ bool IsDeclaredSynchronized() {
+ return (access_flags_ & kAccDeclaredSynchronized) != 0;
+ }
+
+ // Returns true if the method is declared final.
+ bool IsFinal() {
+ return (access_flags_ & kAccFinal) != 0;
+ }
+
+ // Returns true if the method is declared native.
+ bool IsNative() {
+ return (access_flags_ & kAccNative) != 0;
+ }
+
+ // Returns true if the method is declared abstract.
+ bool IsAbstract() {
+ return (access_flags_ & kAccAbstract) != 0;
+ }
+
+ bool IsSynthetic() {
+ return (access_flags_ & kAccSynthetic) != 0;
+ }
+
+ // Number of argument registers required by the prototype.
+ uint32_t NumArgRegisters();
+
+ public: // TODO: private
+ // the class we are a part of
+ Class* klass_;
+
+ // access flags; low 16 bits are defined by spec (could be uint16_t?)
+ uint32_t access_flags_;
+
+ // For concrete virtual methods, this is the offset of the method
+ // in "vtable".
+ //
+ // For abstract methods in an interface class, this is the offset
+ // of the method in "iftable[n]->methodIndexArray".
+ uint16_t method_index_;
+
+ // Method bounds; not needed for an abstract method.
+ //
+ // For a native method, we compute the size of the argument list, and
+ // set "insSize" and "registerSize" equal to it.
+ uint16_t num_registers_; // ins + locals
+ uint16_t num_outs_;
+ uint16_t num_ins_;
+
+ // method name, e.g. "<init>" or "eatLunch"
+ const char* name_;
+
+ // A pointer to the DEX file this class was loaded from or NULL for
+ // proxy objects.
+ DexFile* dex_file_;
+
+ // Method prototype descriptor string (return and argument types).
+ uint32_t proto_idx_;
+
+ // The short-form method descriptor string.
+ const char* shorty_;
+
+ // A pointer to the memory-mapped DEX code.
+ const uint16_t* insns_;
};
} // namespace art
diff --git a/src/raw_dex_file.h b/src/raw_dex_file.h
index 3cd7c88..ca01486 100644
--- a/src/raw_dex_file.h
+++ b/src/raw_dex_file.h
@@ -57,15 +57,15 @@
// Raw field_id_item.
struct FieldId {
- uint32_t class_idx_; // index into typeIds list for defining class
- uint32_t type_idx_; // index into typeIds for field type
+ uint16_t class_idx_; // index into typeIds list for defining class
+ uint16_t type_idx_; // index into typeIds for field type
uint32_t name_idx_; // index into stringIds for field name
};
// Raw method_id_item.
struct MethodId {
- uint32_t class_idx_; // index into typeIds list for defining class
- uint32_t proto_idx_; // index into protoIds for method prototype
+ uint16_t class_idx_; // index into typeIds list for defining class
+ uint16_t proto_idx_; // index into protoIds for method prototype
uint32_t name_idx_; // index into stringIds for method name
};
@@ -148,6 +148,11 @@
// Closes a .dex file.
~RawDexFile();
+ const Header& GetHeader() {
+ CHECK(header_ != NULL);
+ return *header_;
+ }
+
// Looks up a class definition by its class descriptor.
const ClassDef* FindClassDef(const char* descriptor);
@@ -197,15 +202,13 @@
}
// Decodes the header section from the raw class data bytes.
- void DecodeClassDataHeader(ClassDataHeader* header, const byte* class_data) {
- CHECK(header != NULL);
- memset(header, 0, sizeof(ClassDataHeader));
- if (header != NULL) {
- header->static_fields_size_ = DecodeUnsignedLeb128(&class_data);
- header->instance_fields_size_ = DecodeUnsignedLeb128(&class_data);
- header->direct_methods_size_ = DecodeUnsignedLeb128(&class_data);
- header->virtual_methods_size_ = DecodeUnsignedLeb128(&class_data);
- }
+ ClassDataHeader ReadClassDataHeader(const byte** class_data) {
+ ClassDataHeader header;
+ header.static_fields_size_ = DecodeUnsignedLeb128(class_data);
+ header.instance_fields_size_ = DecodeUnsignedLeb128(class_data);
+ header.direct_methods_size_ = DecodeUnsignedLeb128(class_data);
+ header.virtual_methods_size_ = DecodeUnsignedLeb128(class_data);
+ return header;
}
// Returns the class descriptor string of a class definition.
@@ -258,6 +261,21 @@
}
}
+ const Code* GetCode(const Method& method) const {
+ if (method.code_off_ == 0) {
+ return NULL; // native or abstract method
+ } else {
+ const byte* addr = base_ + method.code_off_;
+ return reinterpret_cast<const Code*>(addr);
+ }
+ }
+
+ // Returns the short form method descriptor for the given prototype.
+ const char* GetShorty(uint32_t proto_idx) {
+ const ProtoId& proto_id = GetProtoId(proto_idx);
+ return dexStringById(proto_id.shorty_idx_);
+ }
+
// From libdex...
// Returns a pointer to the UTF-8 string data referred to by the
@@ -281,6 +299,41 @@
return dexStringById(type_id.descriptor_idx_);
}
+ void dexReadClassDataField(const byte** encoded_field,
+ RawDexFile::Field* field,
+ uint32_t* last_idx) const {
+ uint32_t idx = *last_idx + DecodeUnsignedLeb128(encoded_field);
+ field->access_flags_ = DecodeUnsignedLeb128(encoded_field);
+ field->field_idx_ = idx;
+ *last_idx = idx;
+ }
+
+ void dexReadClassDataMethod(const byte** encoded_method,
+ RawDexFile::Method* method,
+ uint32_t* last_idx) const {
+ uint32_t idx = *last_idx + DecodeUnsignedLeb128(encoded_method);
+ method->access_flags_ = DecodeUnsignedLeb128(encoded_method);
+ method->code_off_ = DecodeUnsignedLeb128(encoded_method);
+ method->method_idx_ = idx;
+ *last_idx = idx;
+ }
+
+
+ // TODO: const reference
+ uint32_t dexGetIndexForClassDef(const ClassDef* class_def) const {
+ CHECK_GE(class_def, class_defs_);
+ CHECK_LT(class_def, class_defs_ + header_->class_defs_size_);
+ return class_def - class_defs_;
+ }
+
+ const char* dexGetSourceFile(const ClassDef& class_def) const {
+ if (class_def.source_file_idx_ == 0xffffffff) {
+ return NULL;
+ } else {
+ return dexStringById(class_def.source_file_idx_);
+ }
+ }
+
private:
RawDexFile(const byte* addr, size_t length)
: base_(addr),