blob: 33db15ec7a2ea7cb828b1b6986b060e36fdf0e37 [file] [log] [blame]
// Copyright 2011 Google Inc. All Rights Reserved.
#ifndef ART_SRC_OBJECT_H_
#define ART_SRC_OBJECT_H_
#include "constants.h"
#include "casts.h"
#include "globals.h"
#include "heap.h"
#include "logging.h"
#include "macros.h"
#include "offsets.h"
#include "stringpiece.h"
#include "monitor.h"
namespace art {
class Array;
class Class;
class DexCache;
class InstanceField;
class InterfaceEntry;
class Monitor;
class Method;
class Object;
class String;
template<class T> class ObjectArray;
class StaticField;
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 kAccMiranda = 0x8000; // method
static const uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16)
static const uint32_t kAccConstructor = 0x00010000; // method (Dalvik only)
static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (Dalvik only)
/*
* Definitions for packing refOffsets in Class.
*/
/*
* 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) \
((static_cast<int>(rshift) * CLASS_OFFSET_ALIGNMENT) + CLASS_SMALLEST_OFFSET)
class Object {
public:
static Object* Alloc(Class* klass);
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);
}
const Object* GetFieldObject(size_t field_offset) const {
const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset;
return *reinterpret_cast<Object* const*>(raw_addr);
}
Object* GetFieldObject(size_t field_offset) {
return const_cast<Object*>(GetFieldObject(field_offset));
}
void SetFieldObject(size_t offset, Object* new_value) {
byte* raw_addr = reinterpret_cast<byte*>(this) + offset;
*reinterpret_cast<Object**>(raw_addr) = new_value;
// TODO: write barrier
}
bool IsClass() const {
LOG(FATAL) << "Unimplemented";
return true;
}
Class* AsClass() {
return down_cast<Class*>(this);
}
const Class* AsClass() const {
return down_cast<const Class*>(this);
}
bool IsObjectArray() const {
LOG(FATAL) << "Unimplemented";
return true;
}
const ObjectArray<Object>* AsObjectArray() const {
return down_cast<const ObjectArray<Object>*>(this);
}
bool IsReference() const {
LOG(FATAL) << "Unimplemented";
return true;
}
bool IsWeakReference() const {
LOG(FATAL) << "Unimplemented";
return true;
}
bool IsSoftReference() const {
LOG(FATAL) << "Unimplemented";
return true;
}
bool IsFinalizerReference() const {
LOG(FATAL) << "Unimplemented";
return true;
}
bool IsPhantomReference() const {
LOG(FATAL) << "Unimplemented";
return true;
}
bool IsArray() const {
LOG(FATAL) << "Unimplemented";
return true;
}
public:
Class* klass_;
Monitor* monitor_;
private:
Object();
DISALLOW_COPY_AND_ASSIGN(Object);
};
class ObjectLock {
public:
explicit 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 AccessibleObject : public Object {
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
uint32_t java_flag_;
};
class Field : public AccessibleObject {
public:
Class* GetDeclaringClass() const {
return declaring_class_;
}
const String* GetName() const {
return java_name_;
}
char GetType() const { // TODO: return type
return GetDescriptor()[0];
}
const StringPiece& GetDescriptor() const {
DCHECK_NE(0, descriptor_.size());
return descriptor_;
}
public: // TODO: private
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
Class* java_declaring_class_;
Object* java_generic_type_;
uint32_t java_generic_types_are_initialized_;
String* java_name_;
uint32_t java_slot_;
Class* java_type_;
// The class in which this field is declared.
Class* declaring_class_;
StringPiece name_;
// e.g. "I", "[C", "Landroid/os/Debug;"
StringPiece descriptor_;
uint32_t access_flags_;
private:
Field();
};
// Instance fields.
class InstanceField : public Field {
public:
uint32_t GetOffset() const {
return offset_;
}
void SetOffset(size_t num_bytes) {
offset_ = num_bytes;
}
private:
size_t offset_;
InstanceField();
};
// Static fields.
class StaticField : public Field {
public:
void SetBoolean(bool z) {
CHECK_EQ(GetType(), 'Z');
value_.z = z;
}
void SetByte(int8_t b) {
CHECK_EQ(GetType(), 'B');
value_.b = b;
}
void SetChar(uint16_t c) {
CHECK_EQ(GetType(), 'C');
value_.c = c;
}
void SetShort(uint16_t s) {
CHECK_EQ(GetType(), 'S');
value_.s = s;
}
void SetInt(int32_t i) {
CHECK_EQ(GetType(), 'I');
value_.i = i;
}
int64_t GetLong() {
CHECK_EQ(GetType(), 'J');
return value_.j;
}
void SetLong(int64_t j) {
CHECK_EQ(GetType(), 'J');
value_.j = j;
}
void SetFloat(float f) {
CHECK_EQ(GetType(), 'F');
value_.f = f;
}
void SetDouble(double d) {
CHECK_EQ(GetType(), 'D');
value_.d = d;
}
Object* GetObject() {
return value_.l;
}
const Object* GetObject() const {
return value_.l;
}
void SetObject(Object* l) {
CHECK(GetType() == 'L' || GetType() == '[');
value_.l = l;
// TODO: write barrier
}
private:
JValue value_;
StaticField();
};
class Method : public AccessibleObject {
public:
// Returns the method name, e.g. "<init>" or "eatLunch"
const String* GetName() const {
return java_name_;
}
const String* GetDescriptor() const {
return descriptor_;
}
Class* GetDeclaringClass() const {
return declaring_class_;
}
static MemberOffset ClassOffset() {
return MemberOffset(OFFSETOF_MEMBER(Method, klass_));
}
// 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();
public: // TODO: private
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
Class* java_declaring_class_;
ObjectArray<Class>* java_exception_types_;
Object* java_formal_type_parameters_;
Object* java_generic_exception_types_;
Object* java_generic_parameter_types_;
Object* java_generic_return_type_;
Class* java_return_type_;
String* java_name_;
ObjectArray<Class>* java_parameter_types_;
uint32_t java_generic_types_are_initialized_;
uint32_t java_slot_;
bool IsReturnAReference() const {
return (shorty_[0] == 'L') || (shorty_[0] == '[');
}
bool IsReturnAFloatOrDouble() const {
return (shorty_[0] == 'F') || (shorty_[0] == 'D');
}
bool IsReturnAFloat() const {
return shorty_[0] == 'F';
}
bool IsReturnADouble() const {
return shorty_[0] == 'D';
}
bool IsReturnALong() const {
return shorty_[0] == 'J';
}
bool IsReturnVoid() const {
return shorty_[0] == 'V';
}
// The number of arguments that should be supplied to this method
size_t NumArgs() const {
return (IsStatic() ? 0 : 1) + shorty_.length() - 1;
}
// The number of reference arguments to this method including implicit this
// pointer
size_t NumReferenceArgs() const;
// The number of long or double arguments
size_t NumLongOrDoubleArgs() const;
// The number of reference arguments to this method before the given
// parameter index
size_t NumReferenceArgsBefore(unsigned int param) const;
// Is the given method parameter a reference?
bool IsParamAReference(unsigned int param) const;
// Is the given method parameter a long or double?
bool IsParamALongOrDouble(unsigned int param) const;
// Size in bytes of the given parameter
size_t ParamSize(unsigned int param) const;
// Size in bytes of the return value
size_t ReturnSize() const;
void SetCode(const void* code) {
code_ = code;
}
const void* GetCode() const {
return code_;
}
void RegisterNative(const void* native_method) {
native_method_ = native_method;
}
static MemberOffset NativeMethodOffset() {
return MemberOffset(OFFSETOF_MEMBER(Method, native_method_));
}
bool HasSameNameAndDescriptor(const Method* that) const;
public: // TODO: private/const
// the class we are a part of
Class* declaring_class_;
// 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_;
// The method descriptor. This represents the parameters a method
// takes and value it returns. This string is a list of the type
// descriptors for the parameters enclosed in parenthesis followed
// by the return type descriptor. For example, for the method
//
// Object mymethod(int i, double d, Thread t)
//
// the method descriptor would be
//
// (IDLjava/lang/Thread;)Ljava/lang/Object;
String* descriptor_;
// 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_;
private:
Method();
// Compiled code associated with this method
const void* code_;
// Any native method registered with this method
const void* native_method_;
};
class Array : public Object {
public:
static Array* Alloc(Class* array_class,
size_t component_count,
size_t component_size) {
size_t size = sizeof(Array) + component_count * component_size;
Array* array = down_cast<Array*>(Heap::AllocObject(array_class, size));
if (array != NULL) {
array->SetLength(component_count);
}
return array;
}
uint32_t GetLength() const {
return length_;
}
void SetLength(uint32_t length) {
length_ = length;
}
const void* GetData() const {
return &elements_;
}
void* GetData() {
return &elements_;
}
private:
// The number of array elements.
uint32_t length_;
// Location of first element.
uint32_t elements_[0];
Array();
};
template<class T>
class ObjectArray : public Array {
public:
static ObjectArray<T>* Alloc(Class* object_array_class,
size_t length) {
return down_cast<ObjectArray<T>*>(Array::Alloc(object_array_class,
length,
sizeof(uint32_t)));
}
T* Get(uint32_t i) const {
CHECK_LT(i, GetLength());
Object* const * data = reinterpret_cast<Object* const *>(GetData());
return down_cast<T*>(data[i]);
}
void Set(uint32_t i, T* object) {
CHECK_LT(i, GetLength());
T** data = reinterpret_cast<T**>(GetData());
data[i] = object;
}
static void Copy(ObjectArray<T>* src, int src_pos, ObjectArray<T>* dst, int dst_pos, size_t length) {
for (size_t i = 0; i < length; i++) {
dst->Set(dst_pos + i, src->Get(src_pos + i));
}
}
ObjectArray<T>* CopyOf(size_t new_length) {
ObjectArray<T>* new_array = Alloc(klass_, new_length);
Copy(this, 0, new_array, 0, std::min(GetLength(), new_length));
return new_array;
}
private:
ObjectArray();
};
// ClassLoader objects.
class ClassLoader : public Object {
public:
std::vector<const DexFile*>& GetClassPath() {
return class_path_;
}
void SetClassPath(std::vector<const DexFile*>& class_path) {
DCHECK_EQ(0U, class_path_.size());
class_path_ = class_path;
}
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
Object* packages_;
ClassLoader* parent_;
// TODO remove once we can create a real PathClassLoader
std::vector<const DexFile*> class_path_;
ClassLoader();
};
class BaseDexClassLoader : public ClassLoader {
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
String* original_path_;
Object* path_list_;
BaseDexClassLoader();
};
class PathClassLoader : public BaseDexClassLoader {
private:
PathClassLoader();
};
// Class objects.
class Class : public Object {
public:
// Class Status
//
// kStatusNotReady: If a Class cannot be found in the class table by
// FindClass, it allocates an new one with AllocClass in the
// kStatusNotReady and calls LoadClass. Note if it does find a
// class, it may not be kStatusResolved and it will try to push it
// forward toward kStatusResolved.
//
// kStatusIdx: LoadClass populates with Class with information from
// the DexFile, moving the status to kStatusIdx, indicating that the
// Class values in super_class_ and interfaces_ have not been
// populated based on super_class_idx_ and interfaces_idx_. The new
// Class can then be inserted into the classes table.
//
// kStatusLoaded: After taking a lock on Class, the ClassLinker will
// attempt to move a kStatusIdx class forward to kStatusLoaded by
// using ResolveClass to initialize the super_class_ and interfaces_.
//
// kStatusResolved: Still holding the lock on Class, the ClassLinker
// will use LinkClass to link all members, creating Field and Method
// objects, setting up the vtable, etc. On success, the class is
// marked kStatusResolved.
enum Status {
kStatusError = -1,
kStatusNotReady = 0,
kStatusIdx = 1, // loaded, DEX idx in super_class_idx_ and interfaces_idx_
kStatusLoaded = 2, // DEX idx values resolved
kStatusResolved = 3, // part of linking
kStatusVerifying = 4, // in the process of being verified
kStatusVerified = 5, // logically part of linking; done pre-init
kStatusInitializing = 6, // class init in progress
kStatusInitialized = 7, // ready to go
};
enum PrimitiveType {
kPrimNot = -1
};
Class* GetSuperClass() const {
return super_class_;
}
uint32_t GetSuperClassIdx() const {
return super_class_idx_;
}
bool HasSuperClass() const {
return super_class_ != NULL;
}
ClassLoader* GetClassLoader() const {
return class_loader_;
}
DexCache* GetDexCache() const {
return dex_cache_;
}
Class* GetComponentType() const {
return component_type_;
}
const StringPiece& GetDescriptor() const {
DCHECK_NE(0, descriptor_.size());
return descriptor_;
}
Status GetStatus() const {
return status_;
}
void SetStatus(Status new_status) {
// TODO: validate transition
status_ = new_status;
}
// Returns true if the class has failed to link.
bool IsErroneous() const {
return GetStatus() == kStatusError;
}
// Returns true if the class has been verified.
bool IsVerified() const {
return GetStatus() >= kStatusVerified;
}
// Returns true if the class has been linked.
bool IsLinked() const {
return GetStatus() >= kStatusResolved;
}
bool IsLoaded() const {
return GetStatus() >= kStatusLoaded;
}
// Returns true if this class is in the same packages as that class.
bool IsInSamePackage(const Class* that) const;
static bool IsInSamePackage(const StringPiece& descriptor1,
const StringPiece& descriptor2);
// Returns true if this class represents an array class.
bool IsArray() const {
return GetDescriptor()[0] == '['; // TODO: avoid parsing the descriptor
}
// Returns true if the class is an interface.
bool IsInterface() const {
return (access_flags_ & kAccInterface) != 0;
}
// Returns true if the class is declared public.
bool IsPublic() const {
return (access_flags_ & kAccPublic) != 0;
}
// Returns true if the class is declared final.
bool IsFinal() const {
return (access_flags_ & kAccFinal) != 0;
}
// Returns true if the class is abstract.
bool IsAbstract() const {
return (access_flags_ & kAccAbstract) != 0;
}
// Returns true if the class is an annotation.
bool IsAnnotation() const {
return (access_flags_ & kAccAnnotation) != 0;
}
// Returns true if the class is a primitive type.
bool IsPrimitive() const {
return primitive_type_ != kPrimNot;
}
// Returns true if the class is synthetic.
bool IsSynthetic() const {
return (access_flags_ & kAccSynthetic) != 0;
}
// Returns true if this class can access that class.
bool CanAccess(const Class* that) const {
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(StaticField) * num_sfields;
// }
// Returns the number of static, private, and constructor methods.
size_t NumDirectMethods() const {
return (direct_methods_ != NULL) ? direct_methods_->GetLength() : 0;
}
Method* GetDirectMethod(uint32_t i) const {
DCHECK_NE(NumDirectMethods(), 0U);
return direct_methods_->Get(i);
}
void SetDirectMethod(uint32_t i, Method* f) { // TODO: uint16_t
DCHECK_NE(NumDirectMethods(), 0U);
direct_methods_->Set(i, f);
}
Method* FindDeclaredDirectMethod(const StringPiece& name,
const StringPiece& descriptor);
Method* FindDirectMethod(const StringPiece& name,
const StringPiece& descriptor);
// Returns the number of non-inherited virtual methods.
size_t NumVirtualMethods() const {
return (virtual_methods_ != NULL) ? virtual_methods_->GetLength() : 0;
}
Method* GetVirtualMethod(uint32_t i) const {
DCHECK_NE(NumVirtualMethods(), 0U);
return virtual_methods_->Get(i);
}
void SetVirtualMethod(uint32_t i, Method* f) { // TODO: uint16_t
DCHECK_NE(NumVirtualMethods(), 0U);
virtual_methods_->Set(i, f);
}
Method* FindDeclaredVirtualMethod(const StringPiece& name,
const StringPiece& descriptor);
Method* FindVirtualMethod(const StringPiece& name,
const StringPiece& descriptor);
size_t NumInstanceFields() const {
return (ifields_ != NULL) ? ifields_->GetLength() : 0;
}
// Returns the number of instance fields containing reference types.
size_t NumReferenceInstanceFields() const {
return num_reference_instance_fields_;
}
InstanceField* GetInstanceField(uint32_t i) { // TODO: uint16_t
DCHECK_NE(NumInstanceFields(), 0U);
return ifields_->Get(i);
}
void SetInstanceField(uint32_t i, InstanceField* f) { // TODO: uint16_t
DCHECK_NE(NumInstanceFields(), 0U);
ifields_->Set(i, f);
}
size_t NumStaticFields() const {
return (sfields_ != NULL) ? sfields_->GetLength() : 0;
}
StaticField* GetStaticField(uint32_t i) const { // TODO: uint16_t
DCHECK_NE(NumStaticFields(), 0U);
return sfields_->Get(i);
}
void SetStaticField(uint32_t i, StaticField* f) { // TODO: uint16_t
DCHECK_NE(NumStaticFields(), 0U);
sfields_->Set(i, f);
}
uint32_t GetReferenceOffsets() const {
return reference_offsets_;
}
void SetReferenceOffsets(uint32_t new_reference_offsets) {
reference_offsets_ = new_reference_offsets;
}
size_t NumInterfaces() const {
return (interfaces_ != NULL) ? interfaces_->GetLength() : 0;
}
Class* GetInterface(uint32_t i) const {
DCHECK_NE(NumInterfaces(), 0U);
return interfaces_->Get(i);
}
void SetInterface(uint32_t i, Class* f) { // TODO: uint16_t
DCHECK_NE(NumInterfaces(), 0U);
interfaces_->Set(i, f);
}
public: // TODO: private
// leave space for instance data; we could access fields directly if
// we freeze the definition of java/lang/Class
#define CLASS_FIELD_SLOTS 1
// Class.#0 name
uint32_t instance_data_[CLASS_FIELD_SLOTS];
#undef CLASS_FIELD_SLOTS
// UTF-8 descriptor for the class from constant pool
// ("Ljava/lang/Class;"), or on heap if generated ("[C")
StringPiece descriptor_;
// Proxy classes have their descriptor allocated on the native heap.
// When this field is non-NULL it must be explicitly freed.
std::string* descriptor_alloc_;
// access flags; low 16 bits are defined by VM spec
uint32_t access_flags_; // TODO: make an instance field?
// DexCache of resolved constant pool entries
// (will be NULL for VM-generated, e.g. arrays and primitive classes)
DexCache* dex_cache_;
// state of class initialization
Status status_;
// if class verify fails, we must return same error on subsequent tries
Class* verify_error_class_;
// threadId, used to check for recursive <clinit> invocation
uint32_t clinit_thread_id_;
// Total object size; used when allocating storage on gc heap. (For
// interfaces and abstract classes this will be zero.)
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* component_type_; // TODO: make an instance field
// For array classes, the number of array dimensions, e.g. int[][]
// is 2. Otherwise 0.
int32_t array_rank_;
// primitive type index, or PRIM_NOT (-1); set for generated prim classes
PrimitiveType primitive_type_;
// The superclass, or NULL if this is java.lang.Object or a
// primitive type.
Class* super_class_; // TODO: make an instance field
uint32_t super_class_idx_;
// defining class loader, or NULL for the "bootstrap" system loader
ClassLoader* class_loader_; // TODO: make an instance field
// initiating class loader list
// NOTE: for classes with low serialNumber, these are unused, and the
// values are kept in a table in gDvm.
// InitiatingLoaderList initiating_loader_list_;
// array of interfaces this class implements directly
ObjectArray<Class>* interfaces_;
uint32_t* interfaces_idx_;
// static, private, and <init> methods
ObjectArray<Method>* direct_methods_;
// virtual methods defined in this class; invoked through vtable
ObjectArray<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.
ObjectArray<Method>* vtable_;
// Interface table (iftable), one entry per interface supported by
// this class. That means one entry for each interface we support
// directly, indirectly via superclass, or indirectly via
// superinterface. This will be null if neither we nor our
// superclass implement any interfaces.
//
// Why we need this: given "class Foo implements Face", declare
// "Face faceObj = new Foo()". Invoke faceObj.blah(), where "blah"
// is part of the Face interface. We can't easily use a single
// vtable.
//
// For every interface a concrete class implements, we create a list
// of virtualMethod indices for the methods in the interface.
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.
size_t ifvi_pool_count_;
uint32_t* ifvi_pool_;
// instance fields
//
// These describe the layout of the contents of a
// DataObject-compatible Object. Note that only the fields directly
// declared by this class are listed in ifields; fields declared by
// a superclass are listed in the superclass's Class.ifields.
//
// All instance fields that refer to objects are guaranteed to be at
// the beginning of the field list. num_reference_instance_fields_
// specifies the number of reference fields.
ObjectArray<InstanceField>* ifields_;
// number of fields that are object refs
size_t num_reference_instance_fields_;
// Bitmap of offsets of ifields.
uint32_t reference_offsets_;
// source file name, if known. Otherwise, NULL.
const char* source_file_;
// Static fields
ObjectArray<StaticField>* sfields_;
private:
Class();
};
std::ostream& operator<<(std::ostream& os, const Class::Status& rhs);
inline Object* Object::Alloc(Class* klass) {
DCHECK(klass != NULL);
return Heap::AllocObject(klass, klass->object_size_);
}
class DataObject : public Object {
public:
uint32_t fields_[0];
private:
DataObject();
};
class CharArray : public Array {
public:
static CharArray* Alloc(Class* char_array_class, size_t length) {
return down_cast<CharArray*>(Array::Alloc(char_array_class,
length,
sizeof(uint16_t)));
}
uint16_t* GetChars() {
return reinterpret_cast<uint16_t*>(GetData());
}
const uint16_t* GetChars() const {
return reinterpret_cast<const uint16_t*>(GetData());
}
uint16_t GetChar(uint32_t i) const {
CHECK_LT(i, GetLength());
return GetChars()[i];
}
void SetChar(uint32_t i, uint16_t ch) {
CHECK_LT(i, GetLength());
GetChars()[i] = ch;
}
private:
CharArray();
};
class String : public Object {
public:
const CharArray* GetCharArray() const {
return array_;
}
int32_t GetHashCode() const {
return hash_code_;
}
int32_t GetOffset() const {
DCHECK_LE(0, offset_);
return offset_;
}
int32_t GetLength() const {
DCHECK_LE(0, count_);
return count_;
}
uint16_t CharAt(int32_t index) const {
return GetCharArray()->GetChar(index + GetOffset());
}
static String* AllocFromUtf16(int32_t utf16_length,
uint16_t* utf16_data_in,
int32_t hash_code) {
String* string = Alloc(GetJavaLangString(), GetCharArrayClass(), utf16_length);
uint16_t* utf16_data_out = string->array_->GetChars();
// TODO use 16-bit wide memset variant
for (int i = 0; i < utf16_length; i++ ) {
utf16_data_out[i] = utf16_data_in[i];
}
string->hash_code_ = hash_code;
return string;
}
static String* AllocFromModifiedUtf8(Class* java_lang_String,
Class* char_array,
int32_t utf16_length,
const char* utf8_data_in) {
String* string = Alloc(java_lang_String, char_array, utf16_length);
uint16_t* utf16_data_out = string->array_->GetChars();
ConvertModifiedUtf8ToUtf16(utf16_data_out, utf8_data_in);
string->hash_code_ = ComputeUtf16Hash(utf16_data_out, utf16_length);
return string;
}
// Creates a String of the given ASCII characters. It is an error to call this
// using non-ASCII characters as this function assumes one char per byte.
static String* AllocFromAscii(const char* ascii_data_in) {
return AllocFromModifiedUtf8(GetJavaLangString(),
GetCharArrayClass(),
strlen(ascii_data_in),
ascii_data_in);
}
static String* AllocFromModifiedUtf8(int32_t utf16_length,
const char* utf8_data_in) {
return AllocFromModifiedUtf8(GetJavaLangString(), GetCharArrayClass(),
utf16_length, utf8_data_in);
}
static void InitClasses(Class* java_lang_String, Class* char_array);
static String* Alloc(Class* java_lang_String,
Class* char_array,
int32_t utf16_length) {
String* string = down_cast<String*>(Object::Alloc(java_lang_String));
CharArray* array = CharArray::Alloc(char_array, utf16_length);
string->array_ = array;
string->count_ = utf16_length;
return string;
}
// Convert Modified UTF-8 to UTF-16
// http://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8
static void ConvertModifiedUtf8ToUtf16(uint16_t* utf16_data_out, const char* utf8_data_in) {
while (*utf8_data_in != '\0') {
*utf16_data_out++ = GetUtf16FromUtf8(&utf8_data_in);
}
}
// Retrieve the next UTF-16 character from a UTF-8 string.
//
// Advances "*pUtf8Ptr" to the start of the next character.
//
// WARNING: If a string is corrupted by dropping a '\0' in the middle
// of a 3-byte sequence, you can end up overrunning the buffer with
// reads (and possibly with the writes if the length was computed and
// cached before the damage). For performance reasons, this function
// assumes that the string being parsed is known to be valid (e.g., by
// already being verified). Most strings we process here are coming
// out of dex files or other internal translations, so the only real
// risk comes from the JNI NewStringUTF call.
static uint16_t GetUtf16FromUtf8(const char** utf8_data_in) {
uint8_t one = *(*utf8_data_in)++;
if ((one & 0x80) == 0) {
// one-byte encoding
return one;
}
// two- or three-byte encoding
uint8_t two = *(*utf8_data_in)++;
if ((one & 0x20) == 0) {
// two-byte encoding
return ((one & 0x1f) << 6) |
(two & 0x3f);
}
// three-byte encoding
uint8_t three = *(*utf8_data_in)++;
return ((one & 0x0f) << 12) |
((two & 0x3f) << 6) |
(three & 0x3f);
}
// Like "strlen", but for strings encoded with "modified" UTF-8.
//
// The value returned is the number of characters, which may or may not
// be the same as the number of bytes.
//
// (If this needs optimizing, try: mask against 0xa0, shift right 5,
// get increment {1-3} from table of 8 values.)
static size_t ModifiedUtf8Len(const char* utf8) {
size_t len = 0;
int ic;
while ((ic = *utf8++) != '\0') {
len++;
if ((ic & 0x80) == 0) {
// one-byte encoding
continue;
}
// two- or three-byte encoding
utf8++;
if ((ic & 0x20) == 0) {
// two-byte encoding
continue;
}
// three-byte encoding
utf8++;
}
return len;
}
// The java/lang/String.computeHashCode() algorithm
static int32_t ComputeUtf16Hash(const uint16_t* string_data, size_t string_length) {
int32_t hash = 0;
while (string_length--) {
hash = hash * 31 + *string_data++;
}
return hash;
}
bool Equals(const char* modified_utf8) const {
for (int32_t i = 0; i < GetLength(); ++i) {
uint16_t ch = GetUtf16FromUtf8(&modified_utf8);
if (ch == '\0' || ch != CharAt(i)) {
return false;
}
}
return *modified_utf8 == '\0';
}
bool Equals(const StringPiece& modified_utf8) const {
// TODO: do not assume C-string representation.
return Equals(modified_utf8.data());
}
bool Equals(const String* that) const {
// TODO short circuit on hash_code_
if (this->GetLength() != that->GetLength()) {
return false;
}
for (int32_t i = 0; i < that->GetLength(); ++i) {
if (this->CharAt(i) != that->CharAt(i)) {
return false;
}
}
return true;
}
bool Equals(const uint16_t* that_chars, int32_t that_offset, int32_t that_length) const {
if (this->GetLength() != that_length) {
return false;
}
for (int32_t i = 0; i < that_length; ++i) {
if (this->CharAt(i) != that_chars[that_offset + i]) {
return false;
}
}
return true;
}
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
CharArray* array_;
int32_t hash_code_;
int32_t offset_;
int32_t count_;
static Class* GetJavaLangString() {
DCHECK(java_lang_String_ != NULL);
return java_lang_String_;
}
static Class* GetCharArrayClass() {
DCHECK(char_array_ != NULL);
return char_array_;
}
static Class* java_lang_String_;
static Class* char_array_;
DISALLOW_IMPLICIT_CONSTRUCTORS(String);
};
class InterfaceEntry {
public:
Class* GetClass() const {
return klass_;
};
void SetClass(Class* klass) {
klass_ = klass;
};
private:
// Points to the interface class.
Class* klass_;
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
#endif // ART_SRC_OBJECT_H_