blob: 2384fde10a7e219921436242b452432e21c94648 [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 "dex_file.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 Field;
class InterfaceEntry;
class Monitor;
class Method;
class Object;
class String;
template<class T> class ObjectArray;
template<class T> class PrimitiveArray;
typedef PrimitiveArray<uint8_t> BooleanArray;
typedef PrimitiveArray<int8_t> ByteArray;
typedef PrimitiveArray<uint16_t> CharArray;
typedef PrimitiveArray<double> DoubleArray;
typedef PrimitiveArray<float> FloatArray;
typedef PrimitiveArray<int32_t> IntArray;
typedef PrimitiveArray<int64_t> LongArray;
typedef PrimitiveArray<int16_t> ShortArray;
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 bool InstanceOf(const Object* object, const Class* klass) {
if (object == NULL) {
return false;
}
return object->InstanceOf(klass);
}
Class* GetClass() const {
DCHECK(klass_ != NULL);
return klass_;
}
bool InstanceOf(const Class* klass) const;
size_t SizeOf() const;
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 {
Object* that = const_cast<Object*>(this);
Object* other = that->GetFieldObject(field_offset);
return const_cast<const Object*>(other);
}
Object* GetFieldObject(size_t field_offset) {
byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset;
return *reinterpret_cast<Object**>(raw_addr);
}
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;
Class* AsClass() {
DCHECK(IsClass());
return down_cast<Class*>(this);
}
const Class* AsClass() const {
DCHECK(IsClass());
return down_cast<const Class*>(this);
}
bool IsObjectArray() const;
template<class T>
ObjectArray<T>* AsObjectArray() {
DCHECK(IsObjectArray());
return down_cast<ObjectArray<T>*>(this);
}
template<class T>
const ObjectArray<T>* AsObjectArray() const {
DCHECK(IsObjectArray());
return down_cast<const ObjectArray<T>*>(this);
}
bool IsReference() const {
UNIMPLEMENTED(FATAL);
return true;
}
bool IsWeakReference() const {
UNIMPLEMENTED(FATAL);
return true;
}
bool IsSoftReference() const {
UNIMPLEMENTED(FATAL);
return true;
}
bool IsFinalizerReference() const {
UNIMPLEMENTED(FATAL);
return true;
}
bool IsPhantomReference() const {
UNIMPLEMENTED(FATAL);
return true;
}
bool IsArray() const;
Array* AsArray() {
DCHECK(IsArray());
return down_cast<Array*>(this);
}
const Array* AsArray() const {
DCHECK(IsArray());
return down_cast<const Array*>(this);
}
public:
Class* klass_;
Monitor* monitor_;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(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 name_;
}
bool IsStatic() const {
return (access_flags_ & kAccStatic) != 0;
}
char GetType() const { // TODO: return type
return GetDescriptor()[0];
}
const StringPiece& GetDescriptor() const {
DCHECK_NE(0, descriptor_.size());
return descriptor_;
}
uint32_t GetOffset() const {
return offset_;
}
void SetOffset(size_t num_bytes) {
offset_ = num_bytes;
}
// static field access
bool GetBoolean();
void SetBoolean(bool z);
int8_t GetByte();
void SetByte(int8_t b);
uint16_t GetChar();
void SetChar(uint16_t c);
uint16_t GetShort();
void SetShort(uint16_t s);
int32_t GetInt();
void SetInt(int32_t i);
int64_t GetLong();
void SetLong(int64_t j);
float GetFloat();
void SetFloat(float f);
double GetDouble();
void SetDouble(double d);
Object* GetObject();
const Object* GetObject() const;
void SetObject(Object* l);
public: // TODO: private
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
// The class in which this field is declared.
Class* declaring_class_;
Object* generic_type_;
uint32_t generic_types_are_initialized_;
String* name_;
uint32_t offset_;
Class* type_;
// e.g. "I", "[C", "Landroid/os/Debug;"
StringPiece descriptor_;
uint32_t access_flags_;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Field);
};
class Method : public AccessibleObject {
public:
// An function that invokes a method with an array of its arguments.
typedef void InvokeStub(Method* method,
Object* obj,
Thread* thread,
byte* args,
JValue* result);
// Returns the method name, e.g. "<init>" or "eatLunch"
const String* GetName() const {
return 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();
// Number of argument bytes required for densely packing the
// arguments into an array of arguments.
size_t NumArgArrayBytes();
public: // TODO: private
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
// the class we are a part of
Class* 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* name_;
ObjectArray<Class>* java_parameter_types_;
uint32_t java_generic_types_are_initialized_;
uint32_t java_slot_;
const StringPiece& GetShorty() const {
return shorty_;
}
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';
}
// "Args" may refer to any of the 3 levels of "Args."
// To avoid confusion, our code will denote which "Args" clearly:
// 1. UserArgs: Args that a user see.
// 2. Args: Logical JVM-level Args. E.g., the first in Args will be the
// receiver.
// 3. CConvArgs: Calling Convention Args, which is physical-level Args.
// E.g., the first in Args is Method* for both static and non-static
// methods. And CConvArgs doesn't deal with the receiver because
// receiver is hardwired in an implicit register, so CConvArgs doesn't
// need to deal with it.
//
// The number of Args that should be supplied to this method
size_t NumArgs() const {
// "1 +" because the first in Args is the receiver.
// "- 1" because we don't count the return type.
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;
const void* GetCode() const {
return code_;
}
void SetCode(const void* code) {
code_ = code;
}
static size_t GetCodeOffset() {
return OFFSETOF_MEMBER(Method, code_);
}
void RegisterNative(const void* native_method) {
native_method_ = native_method;
}
static MemberOffset NativeMethodOffset() {
return MemberOffset(OFFSETOF_MEMBER(Method, native_method_));
}
InvokeStub* GetInvokeStub() const {
return invoke_stub_;
}
void SetInvokeStub(const InvokeStub* invoke_stub) {
invoke_stub_ = invoke_stub;
}
static size_t GetInvokeStubOffset() {
return OFFSETOF_MEMBER(Method, invoke_stub_);
}
bool HasSameNameAndDescriptor(const Method* that) const;
public: // TODO: private/const
// 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_;
// 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_;
// Offset to the CodeItem.
uint32_t code_off_;
// The short-form method descriptor string.
StringPiece shorty_;
private:
// Compiled code associated with this method
const void* code_;
// Any native method registered with this method
const void* native_method_;
// Native invocation stub entry point.
const InvokeStub* invoke_stub_;
DISALLOW_IMPLICIT_CONSTRUCTORS(Method);
};
class Array : public Object {
public:
static size_t Size(size_t component_count,
size_t component_size) {
return sizeof(Array) + component_count * component_size;
}
static Array* Alloc(Class* array_class,
size_t component_count,
size_t component_size) {
size_t size = Size(component_count, component_size);
Array* array = Heap::AllocObject(array_class, size)->AsArray();
if (array != NULL) {
array->SetLength(component_count);
}
return array;
}
size_t SizeOf() const;
int32_t GetLength() const {
return length_;
}
void SetLength(uint32_t length) {
length_ = length;
}
protected:
bool IsValidIndex(int32_t index) const {
if (index < 0 || index >= length_) {
Thread* self = Thread::Current();
self->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
"length=%i; index=%i", length_, index);
return false;
}
return true;
}
private:
// The number of array elements.
int32_t length_;
// Padding to ensure the first member defined by a subclass begins on a 8-byte boundary
int32_t padding_;
DISALLOW_IMPLICIT_CONSTRUCTORS(Array);
};
template<class T>
class ObjectArray : public Array {
public:
static ObjectArray<T>* Alloc(Class* object_array_class,
size_t length) {
return Array::Alloc(object_array_class, length, sizeof(uint32_t))->AsObjectArray<T>();
}
T* const * GetData() const {
return reinterpret_cast<T* const *>(&elements_);
}
T** GetData() {
return reinterpret_cast<T**>(&elements_);
}
T* Get(int32_t i) const {
if (!IsValidIndex(i)) {
return NULL;
}
return GetData()[i];
}
void Set(int32_t i, T* object) {
if (IsValidIndex(i)) {
// TODO: ArrayStoreException
GetData()[i] = object; // TODO: write barrier
}
}
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(int32_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:
// Location of first element.
T* elements_[0];
DISALLOW_IMPLICIT_CONSTRUCTORS(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_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ClassLoader);
};
class BaseDexClassLoader : public ClassLoader {
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
String* original_path_;
Object* path_list_;
DISALLOW_IMPLICIT_CONSTRUCTORS(BaseDexClassLoader);
};
class PathClassLoader : public BaseDexClassLoader {
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(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
};
Object* NewInstance() {
return Heap::AllocObject(this, this->object_size_);
}
Class* GetSuperClass() const {
return super_class_;
}
uint32_t GetSuperClassIdx() const {
return super_class_idx_;
}
bool HasSuperClass() const {
return super_class_ != NULL;
}
bool IsAssignableFrom(const Class* klass) const {
DCHECK(klass != NULL);
if (this == klass) {
return true;
}
if (IsInterface()) {
return klass->Implements(this);
}
if (klass->IsArray()) {
return IsAssignableFromArray(klass);
}
return klass->IsSubClass(this);
}
ClassLoader* GetClassLoader() const {
return class_loader_;
}
DexCache* GetDexCache() const {
return dex_cache_;
}
Class* GetComponentType() const {
return component_type_;
}
static size_t GetTypeSize(const StringPiece& descriptor) {
switch (descriptor[0]) {
case 'B': return 1; // byte
case 'C': return 2; // char
case 'D': return 8; // double
case 'F': return 4; // float
case 'I': return 4; // int
case 'J': return 8; // long
case 'S': return 2; // short
case 'Z': return 1; // boolean
case 'L': return sizeof(Object*);
case '[': return sizeof(Array*);
default:
LOG(ERROR) << "Unknown type " << descriptor;
return 0;
}
}
size_t GetComponentSize() const {
return GetTypeSize(component_type_->descriptor_);
}
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;
}
// Returns true if the class has been loaded.
bool IsLoaded() const {
return GetStatus() >= kStatusLoaded;
}
// Returns true if the class is initialized.
bool IsInitialized() const {
return GetStatus() == kStatusInitialized;
}
// 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 number of static, private, and constructor methods.
size_t NumDirectMethods() const {
return (direct_methods_ != NULL) ? direct_methods_->GetLength() : 0;
}
Method* GetDirectMethod(int32_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_;
}
Field* GetInstanceField(uint32_t i) const { // TODO: uint16_t
DCHECK_NE(NumInstanceFields(), 0U);
return ifields_->Get(i);
}
void SetInstanceField(uint32_t i, Field* f) { // TODO: uint16_t
DCHECK_NE(NumInstanceFields(), 0U);
ifields_->Set(i, f);
}
size_t NumStaticFields() const {
return (sfields_ != NULL) ? sfields_->GetLength() : 0;
}
Field* GetStaticField(uint32_t i) const { // TODO: uint16_t
DCHECK_NE(NumStaticFields(), 0U);
return sfields_->Get(i);
}
void SetStaticField(uint32_t i, Field* 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);
}
void SetVerifyErrorClass(Class* klass) {
// Note SetFieldObject is used rather than verify_error_class_ directly for the barrier
size_t field_offset = OFFSETOF_MEMBER(Class, verify_error_class_);
klass->SetFieldObject(field_offset, klass);
}
private:
bool Implements(const Class* klass) const;
bool IsArrayAssignableFromArray(const Class* klass) const;
bool IsAssignableFromArray(const Class* klass) const;
bool IsSubClass(const Class* klass) const;
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.
// Update with SetVerifyErrorClass to ensure a write barrier is used.
const 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<Field>* 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<Field>* sfields_;
// static field storage
//
// Each static field is stored in one of three arrays:
// o references are stored in static_references_
// o doubles and longs are stored in static_64bit_primitives_
// o everything else is in static_32bit_primitives_
// Static fields select their array using their type and their index using the
// Field->slot_ member. Storing static fields in arrays avoids the need for a
// special case in the GC.
ObjectArray<Object>* static_references_;
IntArray* static_32bit_primitives_;
LongArray* static_64bit_primitives_;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Class);
};
std::ostream& operator<<(std::ostream& os, const Class::Status& rhs);
inline bool Object::InstanceOf(const Class* klass) const {
DCHECK(klass != NULL);
DCHECK(klass_ != NULL);
return klass->IsAssignableFrom(klass_);
}
inline bool Object::IsClass() const {
return klass_ == klass_->klass_;
}
inline bool Object::IsObjectArray() const {
return IsArray() && !klass_->component_type_->IsPrimitive();
}
inline bool Object::IsArray() const {
return klass_->IsArray();
}
inline size_t Object::SizeOf() const {
if (IsArray()) {
return AsArray()->SizeOf();
}
return klass_->object_size_;
}
inline size_t Array::SizeOf() const {
return Size(GetLength(), klass_->GetComponentSize());
}
class DataObject : public Object {
public:
uint32_t fields_[0];
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DataObject);
};
template<class T>
class PrimitiveArray : public Array {
public:
typedef T ElementType;
static PrimitiveArray<T>* Alloc(size_t length);
const T* GetData() const {
return reinterpret_cast<const T*>(&elements_);
}
T* GetData() {
return reinterpret_cast<T*>(&elements_);
}
T Get(int32_t i) const {
if (!IsValidIndex(i)) {
return T(0);
}
return GetData()[i];
}
void Set(int32_t i, T value) {
// TODO: ArrayStoreException
if (IsValidIndex(i)) {
GetData()[i] = value;
}
}
static void SetArrayClass(Class* array_class) {
CHECK(array_class != NULL);
array_class_ = array_class;
}
private:
// Location of first element.
T elements_[0];
static Class* array_class_;
DISALLOW_IMPLICIT_CONSTRUCTORS(PrimitiveArray);
};
class String : public Object {
public:
const CharArray* GetCharArray() const {
DCHECK(array_ != NULL);
return array_;
}
uint32_t GetHashCode() const {
return hash_code_;
}
uint32_t GetOffset() const {
return offset_;
}
uint32_t GetLength() const {
return count_;
}
// TODO: do we need this? Equals is the only caller, and could
// bounds check itself.
uint16_t CharAt(int32_t index) const {
if (index < 0 || index >= count_) {
Thread* self = Thread::Current();
self->ThrowNewException("Ljava/lang/StringIndexOutOfBoundsException;",
"length=%i; index=%i", count_, index);
return 0;
}
return GetCharArray()->Get(index + GetOffset());
}
static String* AllocFromUtf16(int32_t utf16_length,
uint16_t* utf16_data_in,
int32_t hash_code) {
String* string = Alloc(GetJavaLangString(),
utf16_length);
// TODO: use 16-bit wide memset variant
for (int i = 0; i < utf16_length; i++ ) {
string->array_->Set(i, utf16_data_in[i]);
}
string->ComputeHashCode();
return string;
}
static String* AllocFromModifiedUtf8(const char* utf) {
size_t char_count = ModifiedUtf8Len(utf);
return AllocFromModifiedUtf8(char_count, utf);
}
static String* AllocFromModifiedUtf8(int32_t utf16_length,
const char* utf8_data_in) {
String* string = Alloc(GetJavaLangString(), utf16_length);
uint16_t* utf16_data_out = string->array_->GetData();
ConvertModifiedUtf8ToUtf16(utf16_data_out, utf8_data_in);
string->ComputeHashCode();
return string;
}
static void InitClasses(Class* java_lang_String);
static String* Alloc(Class* java_lang_String,
int32_t utf16_length) {
String* string = down_cast<String*>(java_lang_String->NewInstance());
CharArray* array = CharArray::Alloc(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;
}
void ComputeHashCode() {
hash_code_ = ComputeUtf16Hash(array_->GetData(), count_);
}
// TODO: do we need this overload? give it a more intention-revealing name.
bool Equals(const char* modified_utf8) const {
for (uint32_t i = 0; i < GetLength(); ++i) {
uint16_t ch = GetUtf16FromUtf8(&modified_utf8);
if (ch == '\0' || ch != CharAt(i)) {
return false;
}
}
return *modified_utf8 == '\0';
}
// TODO: do we need this overload? give it a more intention-revealing name.
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 (uint32_t i = 0; i < that->GetLength(); ++i) {
if (this->CharAt(i) != that->CharAt(i)) {
return false;
}
}
return true;
}
// TODO: do we need this overload? give it a more intention-revealing name.
bool Equals(const uint16_t* that_chars, uint32_t that_offset, uint32_t that_length) const {
if (this->GetLength() != that_length) {
return false;
}
for (uint32_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_;
uint32_t hash_code_;
int32_t offset_;
int32_t count_;
static Class* GetJavaLangString() {
DCHECK(java_lang_String_ != NULL);
return java_lang_String_;
}
static Class* java_lang_String_;
DISALLOW_IMPLICIT_CONSTRUCTORS(String);
};
class InterfaceEntry {
public:
InterfaceEntry() : klass_(NULL), method_index_array_(NULL) {
}
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_;
private:
DISALLOW_COPY_AND_ASSIGN(InterfaceEntry);
};
} // namespace art
#endif // ART_SRC_OBJECT_H_