Add support for linking classes.
Change-Id: I0026be6e4c919f7391fd83c654f58c3bc67f44e1
diff --git a/src/object.h b/src/object.h
index fb68419..98e464a 100644
--- a/src/object.h
+++ b/src/object.h
@@ -3,20 +3,23 @@
#ifndef ART_SRC_OBJECT_H_
#define ART_SRC_OBJECT_H_
+#include "src/dex_file.h"
#include "src/globals.h"
#include "src/macros.h"
+#include "src/stringpiece.h"
+#include "src/monitor.h"
namespace art {
class Array;
class Class;
class DexFile;
-class IField;
+class InstanceField;
class InterfaceEntry;
class Monitor;
class Method;
class Object;
-class SField;
+class StaticField;
union JValue {
uint8_t z;
@@ -49,18 +52,142 @@
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 kAccMiranda = 0x8000; // method
+
static const uint32_t kAccConstructor = 0x00010000; // method (Dalvik only)
static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (Dalvik only)
+/*
+ * Definitions for packing refOffsets in ClassObject.
+ */
+/*
+ * A magic value for refOffsets. Ignore the bits and walk the super
+ * chain when this is the value.
+ * [This is an unlikely "natural" value, since it would be 30 non-ref instance
+ * fields followed by 2 ref instance fields.]
+ */
+#define CLASS_WALK_SUPER ((unsigned int)(3))
+#define CLASS_SMALLEST_OFFSET (sizeof(struct Object))
+#define CLASS_BITS_PER_WORD (sizeof(unsigned long int) * 8)
+#define CLASS_OFFSET_ALIGNMENT 4
+#define CLASS_HIGH_BIT ((unsigned int)1 << (CLASS_BITS_PER_WORD - 1))
+/*
+ * Given an offset, return the bit number which would encode that offset.
+ * Local use only.
+ */
+#define _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) \
+ (((unsigned int)(byteOffset) - CLASS_SMALLEST_OFFSET) / \
+ CLASS_OFFSET_ALIGNMENT)
+/*
+ * Is the given offset too large to be encoded?
+ */
+#define CLASS_CAN_ENCODE_OFFSET(byteOffset) \
+ (_CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset) < CLASS_BITS_PER_WORD)
+/*
+ * Return a single bit, encoding the offset.
+ * Undefined if the offset is too large, as defined above.
+ */
+#define CLASS_BIT_FROM_OFFSET(byteOffset) \
+ (CLASS_HIGH_BIT >> _CLASS_BIT_NUMBER_FROM_OFFSET(byteOffset))
+/*
+ * Return an offset, given a bit number as returned from CLZ.
+ */
+#define CLASS_OFFSET_FROM_CLZ(rshift) \
+ (((int)(rshift) * CLASS_OFFSET_ALIGNMENT) + CLASS_SMALLEST_OFFSET)
+
+
class Object {
public:
+ Class* GetClass() const {
+ return klass_;
+ }
+
+ void MonitorEnter() {
+ monitor_->Enter();
+ }
+
+ void MonitorExit() {
+ monitor_->Exit();
+ }
+
+ void Notify() {
+ monitor_->Notify();
+ }
+
+ void NotifyAll() {
+ monitor_->NotifyAll();
+ }
+
+ void Wait() {
+ monitor_->Wait();
+ }
+
+ void Wait(int64_t timeout) {
+ monitor_->Wait(timeout);
+ }
+
+ void Wait(int64_t timeout, int32_t nanos) {
+ monitor_->Wait(timeout, nanos);
+ }
+
+ void SetObjectAt(size_t offset, Object* new_value) {
+ byte* raw_addr = reinterpret_cast<byte*>(this) + offset;
+ *reinterpret_cast<Object**>(raw_addr) = new_value;
+ // TODO: write barrier
+ }
+
+ public:
Class* klass_;
- Monitor* lock_;
+ Monitor* monitor_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Object);
+};
+
+class ObjectLock {
+ public:
+ ObjectLock(Object* object) : obj_(object) {
+ CHECK(object != NULL);
+ obj_->MonitorEnter();
+ }
+
+ ~ObjectLock() {
+ obj_->MonitorExit();
+ }
+
+ void Wait(int64_t millis = 0) {
+ return obj_->Wait(millis);
+ }
+
+ void Notify() {
+ obj_->Notify();
+ }
+
+ void NotifyAll() {
+ obj_->NotifyAll();
+ }
+
+ private:
+ Object* obj_;
+ DISALLOW_COPY_AND_ASSIGN(ObjectLock);
};
class Field {
public:
+ Class* GetClass() const {
+ return klass_;
+ }
+
+ const char* GetName() const {
+ return name_;
+ }
+
+ char GetType() const { // TODO: return type
+ return signature_[0];
+ }
+
+ public: // TODO: private
// The class in which this field is declared.
Class* klass_;
@@ -73,19 +200,152 @@
};
// Instance fields.
-class IField : public Field {
- uint32_t offset_;
+class InstanceField : public Field {
+ public:
+ uint32_t GetOffset() const {
+ return offset_;
+ }
+
+ void SetOffset(size_t num_bytes) {
+ offset_ = num_bytes;
+ }
+
+ // TODO: stl::swap
+ void Swap(InstanceField* that) {
+ InstanceField tmp;
+ memcpy(&tmp, this, sizeof(InstanceField));
+ memcpy(this, that, sizeof(InstanceField));
+ memcpy(that, &tmp, sizeof(InstanceField));
+ }
+
+ private:
+ size_t offset_;
};
// Static fields.
-class SField : public Field {
+class StaticField : public Field {
+ private:
JValue value_;
};
+class Method {
+ public:
+ // Returns the method name.
+ // TODO: example
+ const StringPiece& GetName() const {
+ return name_;
+ }
+
+ Class* GetClass() const {
+ return klass_;
+ }
+
+ // const char* GetReturnTypeDescriptor() const {
+ // return dex_file_->GetRaw()->dexStringByTypeIdx(proto_id_.return_type_id_);
+ // }
+
+ // Returns true if the method is declared public.
+ bool IsPublic() const {
+ return (access_flags_ & kAccPublic) != 0;
+ }
+
+ // Returns true if the method is declared private.
+ bool IsPrivate() const {
+ return (access_flags_ & kAccPrivate) != 0;
+ }
+
+ // Returns true if the method is declared static.
+ bool IsStatic() const {
+ return (access_flags_ & kAccStatic) != 0;
+ }
+
+ // Returns true if the method is declared synchronized.
+ bool IsSynchronized() const {
+ uint32_t synchonized = kAccSynchronized | kAccDeclaredSynchronized;
+ return (access_flags_ & synchonized) != 0;
+ }
+
+ // Returns true if the method is declared final.
+ bool IsFinal() const {
+ return (access_flags_ & kAccFinal) != 0;
+ }
+
+ // Returns true if the method is declared native.
+ bool IsNative() const {
+ return (access_flags_ & kAccNative) != 0;
+ }
+
+ // Returns true if the method is declared abstract.
+ bool IsAbstract() const {
+ return (access_flags_ & kAccAbstract) != 0;
+ }
+
+ bool IsSynthetic() const {
+ return (access_flags_ & kAccSynthetic) != 0;
+ }
+
+ // Number of argument registers required by the prototype.
+ uint32_t NumArgRegisters();
+
+ bool HasSameNameAndPrototype(const Method* that) const {
+ return HasSameName(that) && HasSamePrototype(that);
+ }
+
+ bool HasSameName(const Method* that) const {
+ return this->GetName() == that->GetName();
+ }
+
+ bool HasSamePrototype(const Method* that) const {
+ return HasSameReturnType(that) && HasSameArgumentTypes(that);
+ }
+
+ bool HasSameReturnType(const Method* that) const;
+
+ bool HasSameArgumentTypes(const Method* that) const;
+
+ 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"
+ StringPiece 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.
+ StringPiece shorty_;
+
+ // A pointer to the memory-mapped DEX code.
+ const uint16_t* insns_;
+};
+
// Class objects.
class Class : public Object {
public:
- enum ClassStatus {
+ enum Status {
kStatusError = -1,
kStatusNotReady = 0,
kStatusIdx = 1, // loaded, DEX idx in super or ifaces
@@ -101,6 +361,55 @@
kPrimNot = -1
};
+ Class* GetSuperClass() const {
+ return super_class_;
+ }
+
+ uint32_t GetSuperClassIdx() const {
+ return super_class_idx_;
+ }
+
+ bool HasSuperClass() const {
+ return super_class_ != NULL;
+ }
+
+ Object* GetClassLoader() const {
+ return class_loader_;
+ }
+
+ DexFile* GetDexFile() const {
+ return dex_file_;
+ }
+
+ Class* GetComponentType() const {
+ return component_type_;
+ }
+
+ const StringPiece& GetDescriptor() const {
+ return descriptor_;
+ }
+
+ Status GetStatus() const {
+ return status_;
+ }
+
+ void SetStatus(Status new_status) {
+ // TODO: validate transition
+ status_ = new_status;
+ }
+
+ bool IsErroneous() const {
+ return GetStatus() == kStatusError;
+ }
+
+ bool IsVerified() const {
+ return GetStatus() >= kStatusVerified;
+ }
+
+ bool IsLinked() const {
+ return GetStatus() >= kStatusResolved;
+ }
+
// Returns true if this class is in the same packages as that class.
bool IsInSamePackage(const Class* that) const;
@@ -143,23 +452,64 @@
// Returns true if this class can access that class.
bool CanAccess(const Class* that) const {
- return that->IsPublic() && this->IsInSamePackage(that);
+ return that->IsPublic() || this->IsInSamePackage(that);
}
// Returns the size in bytes of a class object instance with the
// given number of static fields.
static size_t Size(size_t num_sfields) {
- return OFFSETOF_MEMBER(Class, sfields_) + sizeof(SField) * num_sfields;
+ return OFFSETOF_MEMBER(Class, sfields_) + sizeof(StaticField) * num_sfields;
}
- uint32_t NumDirectMethods() {
- return num_dmethods_;
+ // Returns the number of static, private, and constructor methods.
+ size_t NumDirectMethods() const {
+ return num_direct_methods_;
}
- uint32_t NumVirtualMethods() {
- return num_vmethods_;
+ Method* GetDirectMethod(uint32_t i) const {
+ return &direct_methods_[i];
}
+ // Returns the number of non-inherited virtual methods.
+ size_t NumVirtualMethods() const {
+ return num_virtual_methods_;
+ }
+
+ Method* GetVirtualMethod(uint32_t i) const {
+ return &virtual_methods_[i];
+ }
+
+ size_t NumInstanceFields() const {
+ return num_ifields_;
+ }
+
+ size_t NumReferenceInstanceFields() const {
+ return num_reference_ifields_;
+ }
+
+ InstanceField* GetInstanceField(uint32_t i) { // TODO: uint16_t
+ return &ifields_[i];
+ }
+
+ size_t NumStaticFields() const {
+ return num_sfields_;
+ }
+
+ StaticField* GetStaticField(uint32_t i) { // TODO: uint16_t
+ return &sfields_[i];
+ }
+
+ uint32_t GetReferenceOffsets() const {
+ return reference_offsets_;
+ }
+
+ void SetReferenceOffsets(uint32_t new_reference_offsets) {
+ reference_offsets_ = new_reference_offsets;
+ }
+
+ Method* FindDirectMethodLocally(const StringPiece& name,
+ const StringPiece& descriptor) const;
+
public: // TODO: private
// leave space for instance data; we could access fields directly if
// we freeze the definition of java/lang/Class
@@ -169,7 +519,7 @@
// UTF-8 descriptor for the class from constant pool
// ("Ljava/lang/Class;"), or on heap if generated ("[C")
- const char* descriptor_;
+ StringPiece descriptor_;
// Proxy classes have their descriptor allocated on the native heap.
// When this field is non-NULL it must be explicitly freed.
@@ -178,15 +528,12 @@
// access flags; low 16 bits are defined by VM spec
uint32_t access_flags_; // TODO: make an instance field?
- // VM-unique class serial number, nonzero, set very early
- //uint32_t serial_number_;
-
// DexFile from which we came; needed to resolve constant pool entries
// (will be NULL for VM-generated, e.g. arrays and primitive classes)
DexFile* dex_file_;
// state of class initialization
- ClassStatus status_;
+ Status status_;
// if class verify fails, we must return same error on subsequent tries
Class* verify_error_class_;
@@ -196,12 +543,12 @@
// Total object size; used when allocating storage on gc heap. (For
// interfaces and abstract classes this will be zero.)
- uint32_t object_size_;
+ size_t object_size_;
// For array classes, the class object for base element, for
// instanceof/checkcast (for String[][][], this will be String).
// Otherwise, NULL.
- Class* array_element_class_; // TODO: make an instance field
+ Class* component_type_; // TODO: make an instance field
// For array classes, the number of array dimensions, e.g. int[][]
// is 2. Otherwise 0.
@@ -212,8 +559,8 @@
// The superclass, or NULL if this is java.lang.Object or a
// primitive type.
- Class* super_; // TODO: make an instance field
- uint32_t super_idx_;
+ Class* super_class_; // TODO: make an instance field
+ uint32_t super_class_idx_;
// defining class loader, or NULL for the "bootstrap" system loader
Object* class_loader_; // TODO: make an instance field
@@ -224,21 +571,21 @@
//InitiatingLoaderList initiating_loader_list_;
// array of interfaces this class implements directly
- uint32_t interface_count_;
+ size_t interface_count_;
Class** interfaces_;
// static, private, and <init> methods
- uint32_t num_dmethods_;
- Method* dmethods_;
+ size_t num_direct_methods_;
+ Method* direct_methods_;
// virtual methods defined in this class; invoked through vtable
- uint32_t num_vmethods_;
- Method* vmethods_;
+ size_t num_virtual_methods_;
+ Method* virtual_methods_;
// Virtual method table (vtable), for use by "invoke-virtual". The
// vtable from the superclass is copied in, and virtual methods from
// our class either replace those from the super or are appended.
- int32_t vtable_count_;
+ size_t vtable_count_;
Method** vtable_;
// Interface table (iftable), one entry per interface supported by
@@ -254,14 +601,14 @@
//
// For every interface a concrete class implements, we create a list
// of virtualMethod indices for the methods in the interface.
- int iftable_count_;
+ size_t iftable_count_;
InterfaceEntry* iftable_;
// The interface vtable indices for iftable get stored here. By
// placing them all in a single pool for each class that implements
// interfaces, we decrease the number of allocations.
- int ifvipool_count;
- int* ifvipool_;
+ size_t ifvi_pool_count_;
+ uint32_t* ifvi_pool_;
// instance fields
//
@@ -273,24 +620,29 @@
// 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.
- uint32_t num_ifields_;
+ size_t num_ifields_;
// number of fields that are object refs
- uint32_t num_reference_ifields_;
- IField* ifields_;
+ size_t num_reference_ifields_;
+ InstanceField* ifields_;
- // bitmap of offsets of ifields
- uint32_t ref_offsets_;
+ // Bitmap of offsets of ifields.
+ uint32_t reference_offsets_;
// source file name, if known. Otherwise, NULL.
const char* source_file_;
// Static fields
- uint32_t num_sfields_;
- SField sfields_[]; // MUST be last item
+ size_t num_sfields_;
+ StaticField sfields_[]; // MUST be last item
};
-class String : Object {
+class DataObject : public Object {
+ public:
+ uint32_t fields_[1];
+};
+
+class String : public Object {
public:
Array* array_;
@@ -301,94 +653,31 @@
uint32_t count_;
};
-class Array : Object {
+class Array : public Object {
public:
// The number of array elements.
uint32_t length_;
};
-class Method {
+class InterfaceEntry {
public:
- // Returns true if the method is declared public.
- bool IsPublic() {
- return (access_flags_ & kAccPublic) != 0;
- }
+ Class* GetClass() const {
+ return klass_;
+ };
- // Returns true if the method is declared private.
- bool IsPrivate() {
- return (access_flags_ & kAccPrivate) != 0;
- }
+ void SetClass(Class* klass) {
+ klass_ = klass;
+ };
- // Returns true if the method is declared static.
- bool IsStatic() {
- return (access_flags_ & kAccStatic) != 0;
- }
-
- // Returns true if the method is declared synchronized.
- bool IsSynchronized() {
- uint32_t synchonized = kAccSynchronized | kAccDeclaredSynchronized;
- return (access_flags_ & synchonized) != 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
+ private:
+ // Points to the interface class.
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_;
+ public: // TODO: private
+ // Index into array of vtable offsets. This points into the
+ // ifviPool, which holds the vtables for all interfaces declared by
+ // this class.
+ uint32_t* method_index_array_;
};
} // namespace art