blob: e0a13ca6fe5c0a1d364e96c1167e81c184b7d028 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ART_SRC_OBJECT_H_
#define ART_SRC_OBJECT_H_
#include <iosfwd>
#include <vector>
#include "UniquePtr.h"
#include "atomic.h"
#include "casts.h"
#include "constants.h"
#include "globals.h"
#include "heap.h"
#include "logging.h"
#include "macros.h"
#include "offsets.h"
#include "runtime.h"
#include "stringpiece.h"
#include "thread.h"
#include "utf.h"
namespace art {
class Array;
class Class;
class ClassLoader;
class CodeAndDirectMethods;
class DexCache;
class Field;
class InterfaceEntry;
class Monitor;
class Method;
class Object;
class StaticStorageBase;
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)
static const uint32_t kAccWritable = 0x80000000; // method (Dalvik only)
static const uint32_t kAccClassFlagsMask = (kAccPublic
| kAccFinal
| kAccInterface
| kAccAbstract
| kAccSynthetic
| kAccAnnotation
| kAccEnum);
static const uint32_t kAccInnerClassFlagsMask = (kAccClassFlagsMask
| kAccPrivate
| kAccProtected
| kAccStatic);
static const uint32_t kAccFieldFlagsMask = (kAccPublic
| kAccPrivate
| kAccProtected
| kAccStatic
| kAccFinal
| kAccVolatile
| kAccTransient
| kAccSynthetic
| kAccEnum);
static const uint32_t kAccMethodFlagsMask = (kAccPublic
| kAccPrivate
| kAccProtected
| kAccStatic
| kAccFinal
| kAccSynchronized
| kAccBridge
| kAccVarargs
| kAccNative
| kAccAbstract
| kAccStrict
| kAccSynthetic
| kAccConstructor
| kAccDeclaredSynchronized);
// if only kAccClassIsReference is set, we have a soft reference
static const uint32_t kAccClassIsReference = 0x8000000; // class is a soft/weak/phantom ref
static const uint32_t kAccClassIsWeakReference = 0x4000000; // class is a weak reference
static const uint32_t kAccClassIsFinalizerReference = 0x2000000; // class is a finalizer reference
static const uint32_t kAccClassIsPhantomReference = 0x1000000; // class is a phantom reference
static const uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
| kAccClassIsWeakReference
| kAccClassIsFinalizerReference
| kAccClassIsPhantomReference);
/*
* 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_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_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) \
MemberOffset((static_cast<int>(rshift) * CLASS_OFFSET_ALIGNMENT))
#define OFFSET_OF_OBJECT_MEMBER(type, field) \
MemberOffset(OFFSETOF_MEMBER(type, field))
// Classes shared with the managed side of the world need to be packed
// so that they don't have extra platform specific padding.
#define MANAGED PACKED
// C++ mirror of java.lang.Object
class MANAGED Object {
public:
static bool InstanceOf(const Object* object, const Class* klass) {
if (object == NULL) {
return false;
}
return object->InstanceOf(klass);
}
static MemberOffset ClassOffset() {
return OFFSET_OF_OBJECT_MEMBER(Object, klass_);
}
Class* GetClass() const {
return GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Object, klass_), false);
}
void SetClass(Class* new_klass);
bool InstanceOf(const Class* klass) const;
size_t SizeOf() const;
Object* Clone();
static MemberOffset MonitorOffset() {
return OFFSET_OF_OBJECT_MEMBER(Object, monitor_);
}
volatile int32_t* GetRawLockWordAddress() {
byte* raw_addr = reinterpret_cast<byte*>(this) + OFFSET_OF_OBJECT_MEMBER(Object, monitor_).Int32Value();
int32_t* word_addr = reinterpret_cast<int32_t*>(raw_addr);
return const_cast<volatile int32_t*>(word_addr);
}
uint32_t GetLockOwner();
void MonitorEnter(Thread* thread);
void MonitorExit(Thread* thread);
void Notify();
void NotifyAll();
void Wait(int64_t timeout);
void Wait(int64_t timeout, int32_t nanos);
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 IsClassClass() const;
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 IsArrayInstance() const;
Array* AsArray() {
DCHECK(IsArrayInstance());
return down_cast<Array*>(this);
}
const Array* AsArray() const {
DCHECK(IsArrayInstance());
return down_cast<const Array*>(this);
}
bool IsString() const;
String* AsString() {
DCHECK(IsString());
return down_cast<String*>(this);
}
bool IsMethod() const;
Method* AsMethod() {
DCHECK(IsMethod());
return down_cast<Method*>(this);
}
const Method* AsMethod() const {
DCHECK(IsMethod());
return down_cast<const Method*>(this);
}
bool IsField() const;
Field* AsField() {
DCHECK(IsField());
return down_cast<Field*>(this);
}
const Field* AsField() const {
DCHECK(IsField());
return down_cast<const Field*>(this);
}
bool IsReferenceInstance() const;
bool IsWeakReferenceInstance() const;
bool IsSoftReferenceInstance() const;
bool IsFinalizerReferenceInstance() const;
bool IsPhantomReferenceInstance() const;
// Accessors for Java type fields
template<class T>
T GetFieldObject(MemberOffset field_offset, bool is_volatile) const {
DCHECK(Thread::Current() == NULL || Thread::Current()->CanAccessDirectReferences());
T result = reinterpret_cast<T>(GetField32(field_offset, is_volatile));
Heap::VerifyObject(result);
return result;
}
void SetFieldObject(MemberOffset field_offset, const Object* new_value, bool is_volatile, bool this_is_valid = true) {
Heap::VerifyObject(new_value);
SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile, this_is_valid);
if (new_value != NULL) {
Heap::WriteBarrier(this);
}
}
uint32_t GetField32(MemberOffset field_offset, bool is_volatile) const {
Heap::VerifyObject(this);
const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset.Int32Value();
const int32_t* word_addr = reinterpret_cast<const int32_t*>(raw_addr);
if (is_volatile) {
return android_atomic_acquire_load(word_addr);
} else {
return *word_addr;
}
}
void SetField32(MemberOffset field_offset, uint32_t new_value, bool is_volatile, bool this_is_valid = true) {
if (this_is_valid) {
Heap::VerifyObject(this);
}
byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
uint32_t* word_addr = reinterpret_cast<uint32_t*>(raw_addr);
if (is_volatile) {
/*
* TODO: add an android_atomic_synchronization_store() function and
* use it in the 32-bit volatile set handlers. On some platforms we
* can use a fast atomic instruction and avoid the barriers.
*/
ANDROID_MEMBAR_STORE();
*word_addr = new_value;
ANDROID_MEMBAR_FULL();
} else {
*word_addr = new_value;
}
}
uint64_t GetField64(MemberOffset field_offset, bool is_volatile) const {
Heap::VerifyObject(this);
const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset.Int32Value();
const int64_t* addr = reinterpret_cast<const int64_t*>(raw_addr);
if (is_volatile) {
uint64_t result = QuasiAtomicRead64(addr);
ANDROID_MEMBAR_FULL();
return result;
} else {
return *addr;
}
}
void SetField64(MemberOffset field_offset, uint64_t new_value, bool is_volatile) {
Heap::VerifyObject(this);
byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
int64_t* addr = reinterpret_cast<int64_t*>(raw_addr);
if (is_volatile) {
ANDROID_MEMBAR_STORE();
QuasiAtomicSwap64(new_value, addr);
// Post-store barrier not required due to use of atomic op or mutex.
} else {
*addr = new_value;
}
}
protected:
// Accessors for non-Java type fields
template<class T>
T GetFieldPtr(MemberOffset field_offset, bool is_volatile) const {
return reinterpret_cast<T>(GetField32(field_offset, is_volatile));
}
template<typename T>
void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile) {
SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile);
}
private:
Class* klass_;
uint32_t monitor_;
friend class ImageWriter; // for abusing monitor_ directly
friend struct ObjectOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
};
// C++ mirror of java.lang.reflect.AccessibleObject
class MANAGED AccessibleObject : public Object {
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
uint32_t java_flag_; // can accessibility checks be bypassed
friend struct AccessibleObjectOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(AccessibleObject);
};
// C++ mirror of java.lang.reflect.Field
class MANAGED Field : public AccessibleObject {
public:
Class* GetDeclaringClass() const;
void SetDeclaringClass(Class *new_declaring_class);
const String* GetName() const;
void SetName(String* new_name);
uint32_t GetAccessFlags() const;
void SetAccessFlags(uint32_t new_access_flags) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_), new_access_flags,
false);
}
bool IsStatic() const {
return (GetAccessFlags() & kAccStatic) != 0;
}
bool IsFinal() const {
return (access_flags_ & kAccFinal) != 0;
}
uint32_t GetTypeIdx() const;
void SetTypeIdx(uint32_t type_idx);
// Gets type using type index and resolved types in the dex cache, may be null
// if type isn't yet resolved
Class* GetTypeDuringLinking() const;
// Performs full resolution, may return null and set exceptions if type cannot
// be resolved
Class* GetType() const;
// Offset to field within an Object
MemberOffset GetOffset() const;
static MemberOffset OffsetOffset() {
return MemberOffset(OFFSETOF_MEMBER(Field, offset_));
}
static Field* FindInstanceFieldFromCode(uint32_t field_idx, const Method* referrer);
static Field* FindStaticFieldFromCode(uint32_t field_idx, const Method* referrer);
static Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, bool is_static);
MemberOffset GetOffsetDuringLinking() const;
void SetOffset(MemberOffset num_bytes);
// field access, null object for static fields
bool GetBoolean(const Object* object) const;
void SetBoolean(Object* object, bool z) const;
int8_t GetByte(const Object* object) const;
void SetByte(Object* object, int8_t b) const;
uint16_t GetChar(const Object* object) const;
void SetChar(Object* object, uint16_t c) const;
uint16_t GetShort(const Object* object) const;
void SetShort(Object* object, uint16_t s) const;
int32_t GetInt(const Object* object) const;
void SetInt(Object* object, int32_t i) const;
int64_t GetLong(const Object* object) const;
void SetLong(Object* object, int64_t j) const;
float GetFloat(const Object* object) const;
void SetFloat(Object* object, float f) const;
double GetDouble(const Object* object) const;
void SetDouble(Object* object, double d) const;
Object* GetObject(const Object* object) const;
void SetObject(Object* object, const Object* l) const;
// Slow path routines for static field access when field was unresolved at
// compile time
static uint32_t Get32StaticFromCode(uint32_t field_idx,
const Method* referrer);
static void Set32StaticFromCode(uint32_t field_idx, const Method* referrer,
uint32_t new_value);
static uint64_t Get64StaticFromCode(uint32_t field_idx,
const Method* referrer);
static void Set64StaticFromCode(uint32_t field_idx, const Method* referrer,
uint64_t new_value);
static Object* GetObjStaticFromCode(uint32_t field_idx,
const Method* referrer);
static void SetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
Object* new_value);
static Class* GetJavaLangReflectField() {
DCHECK(java_lang_reflect_Field_ != NULL);
return java_lang_reflect_Field_;
}
static void SetClass(Class* java_lang_reflect_Field);
static void ResetClass();
bool IsVolatile() const {
return (GetAccessFlags() & kAccVolatile) != 0;
}
private:
// private implementation of field access using raw data
uint32_t Get32(const Object* object) const;
void Set32(Object* object, uint32_t new_value) const;
uint64_t Get64(const Object* object) const;
void Set64(Object* object, uint64_t new_value) const;
Object* GetObj(const Object* object) const;
void SetObj(Object* object, const Object* new_value) const;
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
// The class in which this field is declared.
Class* declaring_class_;
Object* generic_type_;
const String* name_;
// Type of the field
Class* type_;
uint32_t generic_types_are_initialized_;
uint32_t access_flags_;
// Offset of field within an instance or in the Class' static fields
uint32_t offset_;
// Dex cache index of resolved type
uint32_t type_idx_;
int32_t slot_;
static Class* java_lang_reflect_Field_;
friend struct FieldOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Field);
};
// C++ mirror of java.lang.reflect.Method
class MANAGED Method : public AccessibleObject {
public:
// An function that invokes a method with an array of its arguments.
typedef void InvokeStub(const Method* method,
Object* obj,
Thread* thread,
byte* args,
JValue* result);
Class* GetDeclaringClass() const;
void SetDeclaringClass(Class *new_declaring_class);
static MemberOffset DeclaringClassOffset() {
return MemberOffset(OFFSETOF_MEMBER(Method, declaring_class_));
}
// Returns the method name, e.g. "<init>" or "eatLunch"
const String* GetName() const;
void SetName(String* new_name);
ByteArray* GetRegisterMapData() const;
void SetRegisterMapData(ByteArray* data);
ByteArray* GetRegisterMapHeader() const;
void SetRegisterMapHeader(ByteArray* header);
String* GetShorty() const;
void SetShorty(String* new_shorty);
const String* GetSignature() const;
void SetSignature(String* new_signature);
bool HasSameNameAndDescriptor(const Method* that) const;
uint32_t GetAccessFlags() const;
void SetAccessFlags(uint32_t new_access_flags) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), new_access_flags,
false);
}
// Returns true if the method is declared public.
bool IsPublic() const {
return (GetAccessFlags() & kAccPublic) != 0;
}
// Returns true if the method is declared private.
bool IsPrivate() const {
return (GetAccessFlags() & kAccPrivate) != 0;
}
// Returns true if the method is declared static.
bool IsStatic() const {
return (GetAccessFlags() & kAccStatic) != 0;
}
// Returns true if the method is a constructor.
bool IsConstructor() const {
return (access_flags_ & kAccConstructor) != 0;
}
// Returns true if the method is static, private, or a constructor.
bool IsDirect() const {
return IsStatic() || IsPrivate() || IsConstructor();
}
// Returns true if the method is declared synchronized.
bool IsSynchronized() const {
uint32_t synchonized = kAccSynchronized | kAccDeclaredSynchronized;
return (GetAccessFlags() & synchonized) != 0;
}
// Returns true if the method is declared final.
bool IsFinal() const {
return (GetAccessFlags() & kAccFinal) != 0;
}
// Returns true if the method is declared native.
bool IsNative() const {
return (GetAccessFlags() & kAccNative) != 0;
}
// Returns true if the method is declared abstract.
bool IsAbstract() const {
return (GetAccessFlags() & kAccAbstract) != 0;
}
bool IsSynthetic() const {
return (GetAccessFlags() & kAccSynthetic) != 0;
}
uint16_t GetMethodIndex() const;
size_t GetVtableIndex() const {
return GetMethodIndex();
}
void SetMethodIndex(uint16_t new_method_index) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_index_),
new_method_index, false);
}
static MemberOffset MethodIndexOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, method_index_);
}
uint32_t GetCodeItemOffset() const {
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, code_item_offset_), false);
}
void SetCodeItemOffset(uint32_t new_code_off) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, code_item_offset_),
new_code_off, false);
}
// Number of 32bit registers that would be required to hold all the arguments
static size_t NumArgRegisters(const StringPiece& shorty);
// Number of argument bytes required for densely packing the
// arguments into an array of arguments.
size_t NumArgArrayBytes() const;
uint16_t NumRegisters() const;
void SetNumRegisters(uint16_t new_num_registers) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_),
new_num_registers, false);
}
uint16_t NumIns() const;
void SetNumIns(uint16_t new_num_ins) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_),
new_num_ins, false);
}
uint16_t NumOuts() const;
void SetNumOuts(uint16_t new_num_outs) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_),
new_num_outs, false);
}
uint32_t GetProtoIdx() const;
void SetProtoIdx(uint32_t new_proto_idx) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, proto_idx_), new_proto_idx, false);
}
ObjectArray<String>* GetDexCacheStrings() const;
void SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings);
static MemberOffset DexCacheStringsOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_strings_);
}
static MemberOffset DexCacheResolvedTypesOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_types_);
}
static MemberOffset DexCacheResolvedFieldsOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_fields_);
}
static MemberOffset DexCacheInitializedStaticStorageOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method,
dex_cache_initialized_static_storage_);
}
ObjectArray<Class>* GetDexCacheResolvedTypes() const;
void SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_types);
ObjectArray<Method>* GetDexCacheResolvedMethods() const;
void SetDexCacheResolvedMethods(ObjectArray<Method>* new_dex_cache_methods);
ObjectArray<Field>* GetDexCacheResolvedFields() const;
void SetDexCacheResolvedFields(ObjectArray<Field>* new_dex_cache_fields);
CodeAndDirectMethods* GetDexCacheCodeAndDirectMethods() const;
void SetDexCacheCodeAndDirectMethods(CodeAndDirectMethods* new_value);
ObjectArray<StaticStorageBase>* GetDexCacheInitializedStaticStorage() const;
void SetDexCacheInitializedStaticStorage(ObjectArray<StaticStorageBase>* new_value);
void SetReturnTypeIdx(uint32_t new_return_type_idx);
Class* GetReturnType() const;
bool IsReturnAReference() const;
bool IsReturnAFloat() const;
bool IsReturnADouble() const;
bool IsReturnAFloatOrDouble() const {
return IsReturnAFloat() || IsReturnADouble();
}
bool IsReturnALong() const;
bool IsReturnVoid() const;
// "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;
// 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;
// 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 Invoke(Thread* self, Object* receiver, byte* args, JValue* result) const;
const ByteArray* GetCodeArray() const {
return GetFieldPtr<const ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, code_array_), false);
}
const void* GetCode() const {
return GetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), false);
}
void SetCode(ByteArray* code_array, InstructionSet instruction_set,
IntArray* mapping_table = NULL);
static MemberOffset GetCodeOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, code_);
}
// Is the given PC within the code array?
bool IsWithinCode(uintptr_t pc) const;
IntArray* GetMappingTable() const {
return GetFieldObject<IntArray*>(
OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_), false);
}
size_t GetFrameSizeInBytes() const {
DCHECK(sizeof(size_t) == sizeof(uint32_t));
size_t result = GetField32(
OFFSET_OF_OBJECT_MEMBER(Method, frame_size_in_bytes_), false);
DCHECK_LE(static_cast<size_t>(kStackAlignment), result);
return result;
}
void SetFrameSizeInBytes(size_t new_frame_size_in_bytes) {
DCHECK(sizeof(size_t) == sizeof(uint32_t));
DCHECK_LE(static_cast<size_t>(kStackAlignment), new_frame_size_in_bytes);
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, frame_size_in_bytes_),
new_frame_size_in_bytes, false);
}
size_t GetReturnPcOffsetInBytes() const {
DCHECK(sizeof(size_t) == sizeof(uint32_t));
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Method, return_pc_offset_in_bytes_), false);
}
void SetReturnPcOffsetInBytes(size_t return_pc_offset_in_bytes) {
DCHECK(sizeof(size_t) == sizeof(uint32_t));
DCHECK_LT(return_pc_offset_in_bytes, GetFrameSizeInBytes());
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, return_pc_offset_in_bytes_),
return_pc_offset_in_bytes, false);
}
bool IsRegistered();
void RegisterNative(const void* native_method);
void UnregisterNative();
static MemberOffset NativeMethodOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, native_method_);
}
const void* GetNativeMethod() const {
return reinterpret_cast<const void*>(GetField32(NativeMethodOffset(), false));
}
ByteArray* GetInvokeStubArray() const {
ByteArray* result = GetFieldPtr<ByteArray*>(
OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_array_), false);
// TODO: DCHECK(result != NULL); should be ahead of time compiled
return result;
}
// Native to managed invocation stub entry point
InvokeStub* GetInvokeStub() const {
InvokeStub* result = GetFieldPtr<InvokeStub*>(
OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_), false);
// TODO: DCHECK(result != NULL); should be ahead of time compiled
return result;
}
static MemberOffset GetInvokeStubOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_);
}
static MemberOffset GetDexCacheCodeAndDirectMethodsOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_code_and_direct_methods_);
}
static MemberOffset GetDexCacheResolvedMethodsOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_resolved_methods_);
}
static MemberOffset GetMethodIndexOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, method_index_);
}
void SetInvokeStub(const ByteArray* invoke_stub_array);
uint32_t GetCoreSpillMask() const {
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, core_spill_mask_), false);
}
void SetCoreSpillMask(uint32_t core_spill_mask) {
// Computed during compilation
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, core_spill_mask_),
core_spill_mask, false);
}
uint32_t GetFpSpillMask() const {
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, fp_spill_mask_), false);
}
void SetFpSpillMask(uint32_t fp_spill_mask) {
// Computed during compilation
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, fp_spill_mask_),
fp_spill_mask, false);
}
// Is this a hand crafted method used for something like describing callee saves?
bool IsPhony() const {
bool result =
NULL == GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_), false);
// Check that if we do think it is phony it looks like the callee save method
DCHECK(!result || GetCoreSpillMask() != 0);
return result;
}
// Converts a native PC to a dex PC. TODO: this is a no-op
// until we associate a PC mapping table with each method.
uint32_t ToDexPC(const uintptr_t pc) const;
// Converts a dex PC to a native PC. TODO: this is a no-op
// until we associate a PC mapping table with each method.
uintptr_t ToNativePC(const uint32_t dex_pc) const;
// Find the catch block for the given exception type and dex_pc
uint32_t FindCatchBlock(Class* exception_type, uint32_t dex_pc) const;
static Class* GetJavaLangReflectMethod() {
DCHECK(java_lang_reflect_Method_ != NULL);
return java_lang_reflect_Method_;
}
static void SetClass(Class* java_lang_reflect_Method);
static void ResetClass();
private:
uint32_t GetReturnTypeIdx() const;
// 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_;
String* name_;
ObjectArray<Class>* java_parameter_types_;
Class* java_return_type_; // Unused by ART
// Storage for code_
const ByteArray* code_array_;
// short cuts to declaring_class_->dex_cache_ member for fast compiled code access
CodeAndDirectMethods* dex_cache_code_and_direct_methods_;
// short cuts to declaring_class_->dex_cache_ member for fast compiled code access
ObjectArray<StaticStorageBase>* dex_cache_initialized_static_storage_;
// short cuts to declaring_class_->dex_cache_ member for fast compiled code access
ObjectArray<Field>* dex_cache_resolved_fields_;
// short cuts to declaring_class_->dex_cache_ member for fast compiled code access
ObjectArray<Method>* dex_cache_resolved_methods_;
// short cuts to declaring_class_->dex_cache_ member for fast compiled code access
ObjectArray<Class>* dex_cache_resolved_types_;
// short cuts to declaring_class_->dex_cache_ member for fast compiled code access
ObjectArray<String>* dex_cache_strings_;
// Storage for invoke_stub_
const ByteArray* invoke_stub_array_;
// Storage for mapping_table_
IntArray* mapping_table_;
// Byte arrays that hold data for the register maps
const ByteArray* register_map_data_;
const ByteArray* register_map_header_;
// The short-form method descriptor string.
String* shorty_;
// 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* signature_;
uint32_t java_generic_types_are_initialized_;
// Access flags; low 16 bits are defined by spec.
uint32_t access_flags_;
// Compiled code associated with this method for callers from managed code.
// May be compiled managed code or a bridge for invoking a native method.
const void* code_;
// Offset to the CodeItem.
uint32_t code_item_offset_;
// Architecture-dependent register spill mask
uint32_t core_spill_mask_;
// Architecture-dependent register spill mask
uint32_t fp_spill_mask_;
// Total size in bytes of the frame
size_t frame_size_in_bytes_;
// Native invocation stub entry point for calling from native to managed code.
const InvokeStub* invoke_stub_;
// Index of the return type
uint32_t java_return_type_idx_;
// For concrete virtual methods, this is the offset of the method
// in Class::vtable_.
//
// For abstract methods in an interface class, this is the offset
// of the method in "iftable_->Get(n)->GetMethodArray()".
uint32_t method_index_;
// The target native method registered with this method
const void* native_method_;
// 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.
uint32_t num_ins_;
uint32_t num_outs_;
uint32_t num_registers_; // ins + locals
// Method prototype descriptor string (return and argument types).
uint32_t proto_idx_;
// Offset of return PC within frame for compiled code (in bytes)
size_t return_pc_offset_in_bytes_;
uint32_t java_slot_;
static Class* java_lang_reflect_Method_;
friend class ImageWriter; // for relocating code_ and invoke_stub_
friend struct MethodOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Method);
};
class MANAGED Array : public Object {
public:
static size_t SizeOf(size_t component_count,
size_t component_size) {
return sizeof(Array) + component_count * component_size;
}
// Given the context of a calling Method, use its DexCache to
// resolve a type to an array Class. If it cannot be resolved, throw
// an error. If it can, use it to create an array.
static Array* AllocFromCode(uint32_t type_idx, Method* method, int32_t component_count);
// A convenience for code that doesn't know the component size,
// and doesn't want to have to work it out itself.
static Array* Alloc(Class* array_class, int32_t component_count);
static Array* Alloc(Class* array_class, int32_t component_count, size_t component_size);
size_t SizeOf() const;
int32_t GetLength() const {
return GetField32(OFFSET_OF_OBJECT_MEMBER(Array, length_), false);
}
void SetLength(int32_t length) {
CHECK_GE(length, 0);
SetField32(OFFSET_OF_OBJECT_MEMBER(Array, length_), length, false);
}
static MemberOffset LengthOffset() {
return OFFSET_OF_OBJECT_MEMBER(Array, length_);
}
static MemberOffset DataOffset() {
return OFFSET_OF_OBJECT_MEMBER(Array, first_element_);
}
void* GetRawData() {
return reinterpret_cast<void*>(first_element_);
}
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_;
// Marker for the data (used by generated code)
uint32_t first_element_[0];
DISALLOW_IMPLICIT_CONSTRUCTORS(Array);
};
template<class T>
class MANAGED ObjectArray : public Array {
public:
static ObjectArray<T>* Alloc(Class* object_array_class, int32_t length);
T* Get(int32_t i) const;
void Set(int32_t i, T* object);
// Set element without bound and element type checks, to be used in limited
// circumstances, such as during boot image writing
void SetWithoutChecks(int32_t i, T* object);
static void Copy(const ObjectArray<T>* src, int src_pos,
ObjectArray<T>* dst, int dst_pos,
size_t length);
ObjectArray<T>* CopyOf(int32_t new_length);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ObjectArray);
};
template<class T>
ObjectArray<T>* ObjectArray<T>::Alloc(Class* object_array_class, int32_t length) {
return Array::Alloc(object_array_class, length, sizeof(uint32_t))->AsObjectArray<T>();
}
template<class T>
T* ObjectArray<T>::Get(int32_t i) const {
if (!IsValidIndex(i)) {
return NULL;
}
MemberOffset data_offset(DataOffset().Int32Value() + i * sizeof(Object*));
return GetFieldObject<T*>(data_offset, false);
}
template<class T>
ObjectArray<T>* ObjectArray<T>::CopyOf(int32_t new_length) {
ObjectArray<T>* new_array = Alloc(GetClass(), new_length);
Copy(this, 0, new_array, 0, std::min(GetLength(), new_length));
return new_array;
}
// Type for the InitializedStaticStorage table. Currently the Class
// provides the static storage. However, this might change to an Array
// to improve image sharing, so we use this type to avoid assumptions
// on the current storage.
class MANAGED StaticStorageBase : public Object {};
// C++ mirror of java.lang.Class
class MANAGED Class : public StaticStorageBase {
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_type_idx_ and
// interfaces_type_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
// shows linking is complete and fields of the Class populated by making
// it kStatusResolved. Java allows circularities of the form where a super
// class has a field that is of the type of the sub class. We need to be able
// to fully resolve super classes while resolving types for fields.
enum Status {
kStatusError = -1,
kStatusNotReady = 0,
kStatusIdx = 1, // loaded, DEX idx in super_class_type_idx_ and interfaces_type_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 = 0,
kPrimBoolean,
kPrimByte,
kPrimChar,
kPrimShort,
kPrimInt,
kPrimLong,
kPrimFloat,
kPrimDouble,
kPrimVoid,
};
Status GetStatus() const {
CHECK(sizeof(Status) == sizeof(uint32_t));
return static_cast<Status>(
GetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), false));
}
void SetStatus(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 loaded.
bool IsIdxLoaded() const {
return GetStatus() >= kStatusIdx;
}
// Returns true if the class has been loaded.
bool IsLoaded() const {
return GetStatus() >= kStatusLoaded;
}
// Returns true if the class has been linked.
bool IsResolved() const {
return GetStatus() >= kStatusResolved;
}
// Returns true if the class has been verified.
bool IsVerified() const {
return GetStatus() >= kStatusVerified;
}
// Returns true if the class is initialized.
bool IsInitialized() const {
return GetStatus() == kStatusInitialized;
}
uint32_t GetAccessFlags() const;
void SetAccessFlags(uint32_t new_access_flags) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags,
false);
}
// Returns true if the class is an interface.
bool IsInterface() const {
return (GetAccessFlags() & kAccInterface) != 0;
}
// Returns true if the class is declared public.
bool IsPublic() const {
return (GetAccessFlags() & kAccPublic) != 0;
}
// Returns true if the class is declared final.
bool IsFinal() const {
return (GetAccessFlags() & kAccFinal) != 0;
}
// Returns true if the class is abstract.
bool IsAbstract() const {
return (GetAccessFlags() & kAccAbstract) != 0;
}
// Returns true if the class is an annotation.
bool IsAnnotation() const {
return (GetAccessFlags() & kAccAnnotation) != 0;
}
// Returns true if the class is synthetic.
bool IsSynthetic() const {
return (GetAccessFlags() & kAccSynthetic) != 0;
}
bool IsReferenceClass() const {
return (GetAccessFlags() & kAccClassIsReference) != 0;
}
bool IsWeakReferenceClass() const {
return (GetAccessFlags() & kAccClassIsWeakReference) != 0;
}
bool IsSoftReferenceClass() const {
return (GetAccessFlags() & ~kAccReferenceFlagsMask) == kAccClassIsReference;
}
bool IsFinalizerReferenceClass() const {
return (GetAccessFlags() & kAccClassIsFinalizerReference) != 0;
}
bool IsPhantomReferenceClass() const {
return (GetAccessFlags() & kAccClassIsPhantomReference) != 0;
}
PrimitiveType GetPrimitiveType() const {
CHECK(sizeof(PrimitiveType) == sizeof(int32_t));
return static_cast<PrimitiveType>(
GetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), false));
}
void SetPrimitiveType(PrimitiveType new_type) {
CHECK(sizeof(PrimitiveType) == sizeof(int32_t));
SetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), new_type,
false);
}
// Returns true if the class is a primitive type.
bool IsPrimitive() const {
return GetPrimitiveType() != kPrimNot;
}
bool IsPrimitiveBoolean() const {
return GetPrimitiveType() == kPrimBoolean;
}
bool IsPrimitiveByte() const {
return GetPrimitiveType() == kPrimByte;
}
bool IsPrimitiveChar() const {
return GetPrimitiveType() == kPrimChar;
}
bool IsPrimitiveShort() const {
return GetPrimitiveType() == kPrimShort;
}
bool IsPrimitiveInt() const {
return GetPrimitiveType() == kPrimInt;
}
bool IsPrimitiveLong() const {
return GetPrimitiveType() == kPrimLong;
}
bool IsPrimitiveFloat() const {
return GetPrimitiveType() == kPrimFloat;
}
bool IsPrimitiveDouble() const {
return GetPrimitiveType() == kPrimDouble;
}
bool IsPrimitiveVoid() const {
return GetPrimitiveType() == kPrimVoid;
}
size_t PrimitiveSize() const;
bool IsArrayClass() const {
return GetComponentType() != NULL;
}
Class* GetComponentType() const {
return GetFieldObject<Class*>(
OFFSET_OF_OBJECT_MEMBER(Class, component_type_), false);
}
void SetComponentType(Class* new_component_type) {
DCHECK(GetComponentType() == NULL);
DCHECK(new_component_type != NULL);
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, component_type_),
new_component_type, false);
}
size_t GetComponentSize() const {
return GetTypeSize(GetComponentType()->GetDescriptor());
}
bool IsObjectClass() const {
return !IsPrimitive() && GetSuperClass() == NULL;
}
// Tests whether a possibly null 'element' can be
// assigned into an array of type 'array_class'.
static void CanPutArrayElementFromCode(const Object* element, const Class* array_class);
// Given the context of a calling Method, use its DexCache to
// resolve a type to a Class. If it cannot be resolved, throw an
// error. If it can, use it to create an instance.
static Object* AllocObjectFromCode(uint32_t type_idx, Method* method);
// Creates a raw object instance but does not invoke the default constructor.
Object* AllocObject();
static size_t GetTypeSize(const String* descriptor);
const String* GetDescriptor() const {
const String* result = GetFieldObject<const String*>(
OFFSET_OF_OBJECT_MEMBER(Class, descriptor_), false);
// DCHECK(result != NULL); // may be NULL prior to class linker initialization
// DCHECK_NE(0, result->GetLength()); // TODO: keep?
return result;
}
void SetDescriptor(String* new_descriptor);
bool IsVariableSize() const {
// Classes and arrays vary in size, and so the object_size_ field cannot
// be used to get their instance size
return IsClassClass() || IsArrayClass();
}
size_t SizeOf() const {
CHECK(sizeof(size_t) == sizeof(int32_t));
return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), false);
}
size_t GetClassSize() const {
CHECK(sizeof(size_t) == sizeof(uint32_t));
return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), false);
}
void SetClassSize(size_t new_class_size) {
DCHECK(new_class_size >= GetClassSize())
<< " class=" << PrettyTypeOf(this)
<< " new_class_size=" << new_class_size
<< " GetClassSize=" << GetClassSize();
SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false);
}
size_t GetObjectSize() const {
CHECK(!IsVariableSize());
CHECK(sizeof(size_t) == sizeof(int32_t));
size_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), false);
CHECK_GE(result, sizeof(Object));
return result;
}
void SetObjectSize(size_t new_object_size) {
DCHECK(!IsVariableSize());
CHECK(sizeof(size_t) == sizeof(int32_t));
return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_),
new_object_size, false);
}
// Returns true if this class is in the same packages as that class.
bool IsInSamePackage(const Class* that) const;
static bool IsInSamePackage(const String* descriptor1,
const String* descriptor2);
// Returns true if this class can access that class.
bool CanAccess(const Class* that) const {
return that->IsPublic() || this->IsInSamePackage(that);
}
bool IsAssignableFrom(const Class* src) const {
DCHECK(src != NULL);
if (this == src) {
// Can always assign to things of the same type
return true;
} else if (IsObjectClass()) {
// Can assign any reference to java.lang.Object
return !src->IsPrimitive();
} else if (IsInterface()) {
return src->Implements(this);
} else if (src->IsArrayClass()) {
return IsAssignableFromArray(src);
} else {
return src->IsSubClass(this);
}
}
Class* GetSuperClass() const {
// Can only get super class for loaded classes (hack for when runtime is
// initializing)
DCHECK(IsLoaded() || !Runtime::Current()->IsStarted());
return GetFieldObject<Class*>(
OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false);
}
static MemberOffset SuperClassOffset() {
return MemberOffset(OFFSETOF_MEMBER(Class, super_class_));
}
void SetSuperClass(Class *new_super_class) {
// super class is assigned once, except during class linker initialization
Class* old_super_class = GetFieldObject<Class*>(
OFFSET_OF_OBJECT_MEMBER(Class, super_class_), false);
DCHECK(old_super_class == NULL || old_super_class == new_super_class);
DCHECK(new_super_class != NULL);
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, super_class_),
new_super_class, false);
}
bool HasSuperClass() const {
return GetSuperClass() != NULL;
}
uint32_t GetSuperClassTypeIdx() const {
DCHECK(IsIdxLoaded() || IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_),
false);
}
void SetSuperClassTypeIdx(int32_t new_super_class_idx) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_),
new_super_class_idx, false);
}
const ClassLoader* GetClassLoader() const;
void SetClassLoader(const ClassLoader* new_cl);
static MemberOffset DexCacheOffset() {
return MemberOffset(OFFSETOF_MEMBER(Class, dex_cache_));
}
enum {
kDumpClassFullDetail = 1,
kDumpClassClassLoader = (1 << 1),
kDumpClassInitialized = (1 << 2),
};
void DumpClass(std::ostream& os, int flags);
DexCache* GetDexCache() const;
void SetDexCache(DexCache* new_dex_cache);
ObjectArray<Method>* GetDirectMethods() const {
DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false);
}
void SetDirectMethods(ObjectArray<Method>* new_direct_methods) {
DCHECK(NULL == GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false));
DCHECK_NE(0, new_direct_methods->GetLength());
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_),
new_direct_methods, false);
}
Method* GetDirectMethod(int32_t i) const {
return GetDirectMethods()->Get(i);
}
void SetDirectMethod(uint32_t i, Method* f) { // TODO: uint16_t
ObjectArray<Method>* direct_methods =
GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false);
direct_methods->Set(i, f);
}
// Returns the number of static, private, and constructor methods.
size_t NumDirectMethods() const {
return (GetDirectMethods() != NULL) ? GetDirectMethods()->GetLength() : 0;
}
ObjectArray<Method>* GetVirtualMethods() const {
DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), false);
}
void SetVirtualMethods(ObjectArray<Method>* new_virtual_methods) {
// TODO: we reassign virtual methods to grow the table for miranda
// methods.. they should really just be assigned once
DCHECK_NE(0, new_virtual_methods->GetLength());
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_),
new_virtual_methods, false);
}
// Returns the number of non-inherited virtual methods.
size_t NumVirtualMethods() const {
return (GetVirtualMethods() != NULL) ? GetVirtualMethods()->GetLength() : 0;
}
Method* GetVirtualMethod(uint32_t i) const {
DCHECK(IsResolved() || IsErroneous());
return GetVirtualMethods()->Get(i);
}
Method* GetVirtualMethodDuringLinking(uint32_t i) const {
DCHECK(IsLoaded() || IsErroneous());
return GetVirtualMethods()->Get(i);
}
void SetVirtualMethod(uint32_t i, Method* f) { // TODO: uint16_t
ObjectArray<Method>* virtual_methods =
GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), false);
virtual_methods->Set(i, f);
}
ObjectArray<Method>* GetVTable() const {
DCHECK(IsResolved() || IsErroneous());
return GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false);
}
ObjectArray<Method>* GetVTableDuringLinking() const {
DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false);
}
void SetVTable(ObjectArray<Method>* new_vtable) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false);
}
static MemberOffset VTableOffset() {
return OFFSET_OF_OBJECT_MEMBER(Class, vtable_);
}
// Given a method implemented by this class but potentially from a
// super class, return the specific implementation
// method for this class.
Method* FindVirtualMethodForVirtual(Method* method) {
DCHECK(!method->GetDeclaringClass()->IsInterface());
// The argument method may from a super class.
// Use the index to a potentially overridden one for this instance's class.
return GetVTable()->Get(method->GetMethodIndex());
}
// Given a method implemented by this class, but potentially from a
// super class or interface, return the specific implementation
// method for this class.
Method* FindVirtualMethodForInterface(Method* method);
Method* FindInterfaceMethod(const StringPiece& name,
const StringPiece& descriptor);
Method* FindVirtualMethodForVirtualOrInterface(Method* method) {
if (method->GetDeclaringClass()->IsInterface()) {
return FindVirtualMethodForInterface(method);
}
return FindVirtualMethodForVirtual(method);
}
Method* FindDeclaredVirtualMethod(const StringPiece& name,
const StringPiece& signature);
Method* FindVirtualMethod(const StringPiece& name,
const StringPiece& descriptor);
Method* FindDeclaredDirectMethod(const StringPiece& name,
const StringPiece& signature);
Method* FindDirectMethod(const StringPiece& name,
const StringPiece& signature);
size_t NumInterfaces() const {
CHECK(IsIdxLoaded() || IsErroneous()); // used during loading
ObjectArray<Class>* interfaces = GetFieldObject<ObjectArray<Class>*>(
OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
return (interfaces != NULL) ? interfaces->GetLength() : 0;
}
IntArray* GetInterfacesTypeIdx() const {
CHECK(IsIdxLoaded() || IsErroneous());
return GetFieldObject<IntArray*>(
OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_), false);
}
void SetInterfacesTypeIdx(IntArray* new_interfaces_idx);
ObjectArray<Class>* GetInterfaces() const {
CHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Class>*>(
OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
}
void SetInterfaces(ObjectArray<Class>* new_interfaces) {
DCHECK(NULL == GetFieldObject<Object*>(
OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false));
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_),
new_interfaces, false);
}
void SetInterface(uint32_t i, Class* f) { // TODO: uint16_t
DCHECK_NE(NumInterfaces(), 0U);
ObjectArray<Class>* interfaces =
GetFieldObject<ObjectArray<Class>*>(
OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
interfaces->Set(i, f);
}
Class* GetInterface(uint32_t i) const {
DCHECK_NE(NumInterfaces(), 0U);
return GetInterfaces()->Get(i);
}
int32_t GetIfTableCount() const {
ObjectArray<InterfaceEntry>* iftable = GetIfTable();
if (iftable == NULL) {
return 0;
}
return iftable->GetLength();
}
ObjectArray<InterfaceEntry>* GetIfTable() const {
DCHECK(IsResolved() || IsErroneous());
return GetFieldObject<ObjectArray<InterfaceEntry>*>(
OFFSET_OF_OBJECT_MEMBER(Class, iftable_), false);
}
void SetIfTable(ObjectArray<InterfaceEntry>* new_iftable) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), new_iftable, false);
}
// Get instance fields
ObjectArray<Field>* GetIFields() const {
DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Field>*>(
OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
}
void SetIFields(ObjectArray<Field>* new_ifields) {
DCHECK(NULL == GetFieldObject<ObjectArray<Field>*>(
OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false));
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, ifields_),
new_ifields, false);
}
size_t NumInstanceFields() const {
return (GetIFields() != NULL) ? GetIFields()->GetLength() : 0;
}
Field* GetInstanceField(uint32_t i) const { // TODO: uint16_t
DCHECK_NE(NumInstanceFields(), 0U);
return GetIFields()->Get(i);
}
void SetInstanceField(uint32_t i, Field* f) { // TODO: uint16_t
ObjectArray<Field>* ifields= GetFieldObject<ObjectArray<Field>*>(
OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
ifields->Set(i, f);
}
// Returns the number of instance fields containing reference types.
size_t NumReferenceInstanceFields() const {
DCHECK(IsResolved() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
}
size_t NumReferenceInstanceFieldsDuringLinking() const {
DCHECK(IsLoaded() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
}
void SetNumReferenceInstanceFields(size_t new_num) {
DCHECK(sizeof(size_t) == sizeof(int32_t));
SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_),
new_num, false);
}
uint32_t GetReferenceInstanceOffsets() const {
DCHECK(IsResolved() || IsErroneous());
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_), false);
}
void SetReferenceInstanceOffsets(uint32_t new_reference_offsets);
// Beginning of static field data
static MemberOffset FieldsOffset() {
return OFFSET_OF_OBJECT_MEMBER(Class, fields_);
}
// Returns the number of static fields containing reference types.
size_t NumReferenceStaticFields() const {
DCHECK(IsResolved() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
}
size_t NumReferenceStaticFieldsDuringLinking() const {
DCHECK(IsLoaded() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
}
void SetNumReferenceStaticFields(size_t new_num) {
DCHECK(sizeof(size_t) == sizeof(int32_t));
SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_),
new_num, false);
}
ObjectArray<Field>* GetSFields() const {
DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Field>*>(
OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);
}
void SetSFields(ObjectArray<Field>* new_sfields) {
DCHECK(NULL == GetFieldObject<ObjectArray<Field>*>(
OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false));
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, sfields_),
new_sfields, false);
}
size_t NumStaticFields() const {
return (GetSFields() != NULL) ? GetSFields()->GetLength() : 0;
}
Field* GetStaticField(uint32_t i) const { // TODO: uint16_t
return GetSFields()->Get(i);
}
void SetStaticField(uint32_t i, Field* f) { // TODO: uint16_t
ObjectArray<Field>* sfields= GetFieldObject<ObjectArray<Field>*>(
OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);
sfields->Set(i, f);
}
uint32_t GetReferenceStaticOffsets() const {
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, reference_static_offsets_), false);
}
void SetReferenceStaticOffsets(uint32_t new_reference_offsets);
// Finds the given instance field in this class or a superclass.
Field* FindInstanceField(const StringPiece& name, Class* type);
Field* FindDeclaredInstanceField(const StringPiece& name, Class* type);
// Finds the given static field in this class or a superclass.
Field* FindStaticField(const StringPiece& name, Class* type);
Field* FindDeclaredStaticField(const StringPiece& name, Class* type);
pid_t GetClinitThreadId() const {
DCHECK(IsIdxLoaded() || IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), false);
}
void SetClinitThreadId(pid_t new_clinit_thread_id) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_),
new_clinit_thread_id, false);
}
Class* GetVerifyErrorClass() const {
// DCHECK(IsErroneous());
return GetFieldObject<Class*>(
OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false);
}
void SetVerifyErrorClass(Class* klass) {
klass->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_),
klass, false);
}
String* GetSourceFile() const;
void SetSourceFile(String* new_source_file);
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;
// descriptor for the class such as "java.lang.Class" or "[C"
String* name_; // TODO initialize
// defining class loader, or NULL for the "bootstrap" system loader
const ClassLoader* class_loader_;
// For array classes, the component class object for instanceof/checkcast
// (for String[][][], this will be String[][]). NULL for non-array classes.
Class* component_type_;
// descriptor for the class such as "Ljava/lang/Class;" or "[C"
String* descriptor_;
// DexCache of resolved constant pool entries
// (will be NULL for VM-generated, e.g. arrays and primitive classes)
DexCache* dex_cache_;
// static, private, and <init> methods
ObjectArray<Method>* direct_methods_;
// instance fields
//
// These describe the layout of the contents of an 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_;
// 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 an array
// of the concrete vtable_ methods for the methods in the interface.
ObjectArray<InterfaceEntry>* iftable_;
// array of interfaces this class implements directly
// see also interfaces_type_idx_
ObjectArray<Class>* interfaces_;
// array of type_idx's for interfaces this class implements directly
// see also interfaces_
IntArray* interfaces_type_idx_;
// Static fields
ObjectArray<Field>* sfields_;
// source file name, if known. Otherwise, NULL.
String* source_file_;
// The superclass, or NULL if this is java.lang.Object or a
// primitive type.
// see also super_class_type_idx_;
Class* super_class_;
// 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_;
// 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_;
// access flags; low 16 bits are defined by VM spec
uint32_t access_flags_;
// Total size of the Class instance; used when allocating storage on gc heap.
// See also object_size_.
size_t class_size_;
// tid used to check for recursive <clinit> invocation
pid_t clinit_thread_id_;
// number of instance fields that are object refs
size_t num_reference_instance_fields_;
// number of static fields that are object refs
size_t num_reference_static_fields_;
// Total object size; used when allocating storage on gc heap.
// (For interfaces and abstract classes this will be zero.)
// See also class_size_.
size_t object_size_;
// primitive type index, or kPrimNot (0); set for generated prim classes
PrimitiveType primitive_type_;
// Bitmap of offsets of ifields.
uint32_t reference_instance_offsets_;
// Bitmap of offsets of sfields.
uint32_t reference_static_offsets_;
// state of class initialization
Status status_;
// Set in LoadClass, used to LinkClass
// see also super_class_
uint32_t super_class_type_idx_;
// TODO: ?
// 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_;
// Location of first static field.
uint32_t fields_[0];
friend struct ClassOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Class);
};
std::ostream& operator<<(std::ostream& os, const Class::Status& rhs);
inline void Object::SetClass(Class* new_klass) {
// new_klass may be NULL prior to class linker initialization
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Object, klass_), new_klass, false, false);
}
inline bool Object::InstanceOf(const Class* klass) const {
DCHECK(klass != NULL);
DCHECK(GetClass() != NULL);
return klass->IsAssignableFrom(GetClass());
}
inline bool Object::IsClass() const {
Class* java_lang_Class = GetClass()->GetClass();
return GetClass() == java_lang_Class;
}
inline bool Object::IsClassClass() const {
Class* java_lang_Class = GetClass()->GetClass();
return this == java_lang_Class;
}
inline bool Object::IsObjectArray() const {
return IsArrayInstance() && !GetClass()->GetComponentType()->IsPrimitive();
}
inline bool Object::IsArrayInstance() const {
return GetClass()->IsArrayClass();
}
inline bool Object::IsField() const {
Class* java_lang_Class = klass_->klass_;
Class* java_lang_reflect_Field =
java_lang_Class->GetInstanceField(0)->GetClass();
return GetClass() == java_lang_reflect_Field;
}
inline bool Object::IsMethod() const {
Class* java_lang_Class = GetClass()->GetClass();
Class* java_lang_reflect_Method =
java_lang_Class->GetDirectMethod(0)->GetClass();
return GetClass() == java_lang_reflect_Method;
}
inline bool Object::IsReferenceInstance() const {
return GetClass()->IsReferenceClass();
}
inline bool Object::IsWeakReferenceInstance() const {
return GetClass()->IsWeakReferenceClass();
}
inline bool Object::IsSoftReferenceInstance() const {
return GetClass()->IsSoftReferenceClass();
}
inline bool Object::IsFinalizerReferenceInstance() const {
return GetClass()->IsFinalizerReferenceClass();
}
inline bool Object::IsPhantomReferenceInstance() const {
return GetClass()->IsPhantomReferenceClass();
}
inline size_t Object::SizeOf() const {
size_t result;
if (IsArrayInstance()) {
result = AsArray()->SizeOf();
} else if (IsClass()) {
result = AsClass()->SizeOf();
} else {
result = GetClass()->GetObjectSize();
}
DCHECK(!IsField() || result == sizeof(Field));
DCHECK(!IsMethod() || result == sizeof(Method));
return result;
}
inline void Field::SetOffset(MemberOffset num_bytes) {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
Class* type = GetTypeDuringLinking();
if (type != NULL && (type->IsPrimitiveDouble() || type->IsPrimitiveLong())) {
DCHECK(IsAligned(num_bytes.Uint32Value(), 8));
}
SetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_),
num_bytes.Uint32Value(), false);
}
inline Class* Field::GetDeclaringClass() const {
Class* result = GetFieldObject<Class*>(
OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_), false);
DCHECK(result != NULL);
DCHECK(result->IsLoaded() || result->IsErroneous());
return result;
}
inline void Field::SetDeclaringClass(Class *new_declaring_class) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_),
new_declaring_class, false);
}
inline Class* Method::GetDeclaringClass() const {
Class* result =
GetFieldObject<Class*>(
OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_), false);
DCHECK(result != NULL);
DCHECK(result->IsLoaded() || result->IsErroneous());
return result;
}
inline void Method::SetDeclaringClass(Class *new_declaring_class) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_),
new_declaring_class, false);
}
inline uint32_t Method::GetReturnTypeIdx() const {
DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, java_return_type_idx_),
false);
}
inline bool Method::IsReturnAReference() const {
return !GetReturnType()->IsPrimitive();
}
inline bool Method::IsReturnAFloat() const {
return GetReturnType()->IsPrimitiveFloat();
}
inline bool Method::IsReturnADouble() const {
return GetReturnType()->IsPrimitiveDouble();
}
inline bool Method::IsReturnALong() const {
return GetReturnType()->IsPrimitiveLong();
}
inline bool Method::IsReturnVoid() const {
return GetReturnType()->IsPrimitiveVoid();
}
inline size_t Array::SizeOf() const {
return SizeOf(GetLength(), GetClass()->GetComponentSize());
}
template<class T>
void ObjectArray<T>::Set(int32_t i, T* object) {
if (IsValidIndex(i)) {
if (object != NULL) {
Class* element_class = GetClass()->GetComponentType();
DCHECK(!element_class->IsPrimitive());
// TODO: ArrayStoreException
CHECK(object->InstanceOf(element_class));
}
MemberOffset data_offset(DataOffset().Int32Value() + i * sizeof(Object*));
SetFieldObject(data_offset, object, false);
}
}
template<class T>
void ObjectArray<T>::SetWithoutChecks(int32_t i, T* object) {
DCHECK(IsValidIndex(i));
MemberOffset data_offset(DataOffset().Int32Value() + i * sizeof(Object*));
SetFieldObject(data_offset, object, false);
}
template<class T>
void ObjectArray<T>::Copy(const ObjectArray<T>* src, int src_pos,
ObjectArray<T>* dst, int dst_pos,
size_t length) {
if (src->IsValidIndex(src_pos) &&
src->IsValidIndex(src_pos+length-1) &&
dst->IsValidIndex(dst_pos) &&
dst->IsValidIndex(dst_pos+length-1)) {
MemberOffset src_offset(DataOffset().Int32Value() +
src_pos * sizeof(Object*));
MemberOffset dst_offset(DataOffset().Int32Value() +
dst_pos * sizeof(Object*));
Class* array_class = dst->GetClass();
if (array_class == src->GetClass()) {
// No need for array store checks if arrays are of the same type
for (size_t i=0; i < length; i++) {
Object* object = src->GetFieldObject<Object*>(src_offset, false);
dst->SetFieldObject(dst_offset, object, false);
src_offset = MemberOffset(src_offset.Uint32Value() + sizeof(Object*));
dst_offset = MemberOffset(dst_offset.Uint32Value() + sizeof(Object*));
}
} else {
Class* element_class = array_class->GetComponentType();
CHECK(!element_class->IsPrimitive());
for (size_t i=0; i < length; i++) {
Object* object = src->GetFieldObject<Object*>(src_offset, false);
// TODO: ArrayStoreException
CHECK(object == NULL || object->InstanceOf(element_class));
dst->SetFieldObject(dst_offset, object, false);
src_offset = MemberOffset(src_offset.Uint32Value() + sizeof(Object*));
dst_offset = MemberOffset(dst_offset.Uint32Value() + sizeof(Object*));
}
}
Heap::WriteBarrier(dst);
}
}
class MANAGED ClassClass : public Class {
private:
int32_t padding_;
int64_t serialVersionUID_;
friend struct ClassClassOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass);
};
class MANAGED StringClass : public Class {
private:
CharArray* ASCII_;
Object* CASE_INSENSITIVE_ORDER_;
uint32_t REPLACEMENT_CHAR_;
int64_t serialVersionUID_;
friend struct StringClassOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass);
};
class MANAGED FieldClass : public Class {
private:
Object* ORDER_BY_NAME_AND_DECLARING_CLASS_;
uint32_t TYPE_BOOLEAN_;
uint32_t TYPE_BYTE_;
uint32_t TYPE_CHAR_;
uint32_t TYPE_DOUBLE_;
uint32_t TYPE_FLOAT_;
uint32_t TYPE_INTEGER_;
uint32_t TYPE_LONG_;
uint32_t TYPE_SHORT_;
friend struct FieldClassOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(FieldClass);
};
class MANAGED MethodClass : public Class {
private:
Object* ORDER_BY_SIGNATURE_;
friend struct MethodClassOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(MethodClass);
};
template<class T>
class MANAGED 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);
CHECK(array_class != NULL);
array_class_ = array_class;
}
static void ResetArrayClass() {
CHECK(array_class_ != NULL);
array_class_ = NULL;
}
private:
// Location of first element.
T elements_[0];
static Class* array_class_;
DISALLOW_IMPLICIT_CONSTRUCTORS(PrimitiveArray);
};
inline void Class::SetInterfacesTypeIdx(IntArray* new_interfaces_idx) {
DCHECK(NULL == GetFieldObject<IntArray*>(
OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_), false));
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_),
new_interfaces_idx, false);
}
// C++ mirror of java.lang.String
class MANAGED String : public Object {
public:
const CharArray* GetCharArray() const {
const CharArray* result = GetFieldObject<const CharArray*>(
OFFSET_OF_OBJECT_MEMBER(String, array_), false);
DCHECK(result != NULL);
return result;
}
int32_t GetOffset() const {
int32_t result = GetField32(
OFFSET_OF_OBJECT_MEMBER(String, offset_), false);
DCHECK_LE(0, result);
return result;
}
int32_t GetLength() const;
int32_t GetHashCode() const;
void ComputeHashCode() {
SetHashCode(ComputeUtf16Hash(GetCharArray(), GetOffset(), GetLength()));
}
int32_t GetUtfLength() const {
return CountUtf8Bytes(GetCharArray()->GetData(), GetLength());
}
uint16_t CharAt(int32_t index) const;
String* Intern();
static String* AllocFromUtf16(int32_t utf16_length,
const uint16_t* utf16_data_in,
int32_t hash_code = 0);
static String* AllocFromModifiedUtf8(const char* utf);
static String* AllocFromModifiedUtf8(int32_t utf16_length,
const char* utf8_data_in);
static String* Alloc(Class* java_lang_String, int32_t utf16_length);
static String* Alloc(Class* java_lang_String, CharArray* array);
bool Equals(const char* modified_utf8) const;
// TODO: do we need this overload? give it a more intention-revealing name.
bool Equals(const StringPiece& modified_utf8) const;
bool Equals(const String* that) const;
// TODO: do we need this overload? give it a more intention-revealing name.
bool Equals(const uint16_t* that_chars, int32_t that_offset,
int32_t that_length) const;
// Create a modified UTF-8 encoded std::string from a java/lang/String object.
std::string ToModifiedUtf8() const;
static Class* GetJavaLangString() {
DCHECK(java_lang_String_ != NULL);
return java_lang_String_;
}
static void SetClass(Class* java_lang_String);
static void ResetClass();
private:
void SetHashCode(int32_t new_hash_code) {
DCHECK_EQ(0u,
GetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_), false));
SetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_),
new_hash_code, false);
}
void SetCount(int32_t new_count) {
DCHECK_LE(0, new_count);
SetField32(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count, false);
}
void SetOffset(int32_t new_offset) {
DCHECK_LE(0, new_offset);
DCHECK_GE(GetLength(), new_offset);
SetField32(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset, false);
}
void SetArray(CharArray* new_array) {
DCHECK(new_array != NULL);
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(String, array_), new_array, false);
}
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
CharArray* array_;
int32_t count_;
uint32_t hash_code_;
int32_t offset_;
static Class* java_lang_String_;
friend struct StringOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(String);
};
inline const String* Field::GetName() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
String* result =
GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Field, name_), false);
DCHECK(result != NULL);
return result;
}
inline void Field::SetName(String* new_name) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Field, name_),
new_name, false);
}
inline uint32_t Field::GetAccessFlags() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_), false);
}
inline uint32_t Field::GetTypeIdx() const {
DCHECK(GetDeclaringClass()->IsIdxLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, type_idx_), false);
}
inline MemberOffset Field::GetOffset() const {
DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
return MemberOffset(
GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
}
inline MemberOffset Field::GetOffsetDuringLinking() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return MemberOffset(
GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
}
inline const String* Method::GetName() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
const String* result =
GetFieldObject<const String*>(
OFFSET_OF_OBJECT_MEMBER(Method, name_), false);
DCHECK(result != NULL);
return result;
}
inline void Method::SetName(String* new_name) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, name_),
new_name, false);
}
inline ByteArray* Method::GetRegisterMapData() const {
return GetFieldObject<ByteArray*>(
OFFSET_OF_OBJECT_MEMBER(Method, register_map_data_), false);
}
inline void Method::SetRegisterMapData(ByteArray* data) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, register_map_data_),
data, false);
}
inline ByteArray* Method::GetRegisterMapHeader() const {
return GetFieldObject<ByteArray*>(
OFFSET_OF_OBJECT_MEMBER(Method, register_map_header_), false);
}
inline void Method::SetRegisterMapHeader(ByteArray* header) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, register_map_header_),
header, false);
}
inline String* Method::GetShorty() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetFieldObject<String*>(
OFFSET_OF_OBJECT_MEMBER(Method, shorty_), false);
}
inline void Method::SetShorty(String* new_shorty) {
DCHECK(NULL == GetFieldObject<String*>(
OFFSET_OF_OBJECT_MEMBER(Method, shorty_), false));
DCHECK_LE(1, new_shorty->GetLength());
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, shorty_), new_shorty, false);
}
inline const String* Method::GetSignature() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
const String* result =
GetFieldObject<const String*>(
OFFSET_OF_OBJECT_MEMBER(Method, signature_), false);
DCHECK(result != NULL);
return result;
}
inline void Method::SetSignature(String* new_signature) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, signature_),
new_signature, false);
}
inline uint32_t Class::GetAccessFlags() const {
// Check class is loaded or this is java.lang.String that has a
// circularity issue during loading the names of its members
DCHECK(IsLoaded() || IsErroneous() ||
this == String::GetJavaLangString() ||
this == Field::GetJavaLangReflectField() ||
this == Method::GetJavaLangReflectMethod()) << PrettyClass(this);
return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false);
}
inline void Class::SetDescriptor(String* new_descriptor) {
DCHECK(GetDescriptor() == NULL);
DCHECK(new_descriptor != NULL);
DCHECK_NE(0, new_descriptor->GetLength());
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, descriptor_),
new_descriptor, false);
}
inline String* Class::GetSourceFile() const {
DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Class, source_file_), false);
}
inline void Class::SetSourceFile(String* new_source_file) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, source_file_), new_source_file, false);
}
inline uint32_t Method::GetAccessFlags() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), false);
}
inline uint16_t Method::GetMethodIndex() const {
DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_index_), false);
}
inline uint16_t Method::NumRegisters() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_), false);
}
inline uint16_t Method::NumIns() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_), false);
}
inline uint16_t Method::NumOuts() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_), false);
}
inline uint32_t Method::GetProtoIdx() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, proto_idx_), false);
}
// C++ mirror of java.lang.Throwable
class MANAGED Throwable : public Object {
public:
void SetDetailMessage(String* new_detail_message) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_),
new_detail_message, false);
}
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
Throwable* cause_;
String* detail_message_;
Object* stack_state_; // Note this is Java volatile:
Object* stack_trace_;
Object* suppressed_exceptions_;
friend struct ThrowableOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(Throwable);
};
// C++ mirror of java.lang.StackTraceElement
class MANAGED StackTraceElement : public Object {
public:
const String* GetDeclaringClass() const {
return GetFieldObject<const String*>(
OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_), false);
}
const String* GetMethodName() const {
return GetFieldObject<const String*>(
OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_), false);
}
const String* GetFileName() const {
return GetFieldObject<const String*>(
OFFSET_OF_OBJECT_MEMBER(StackTraceElement, file_name_), false);
}
int32_t GetLineNumber() const {
return GetField32(
OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_), false);
}
static StackTraceElement* Alloc(const String* declaring_class,
const String* method_name,
const String* file_name,
int32_t line_number);
static void SetClass(Class* java_lang_StackTraceElement);
static void ResetClass();
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
const String* declaring_class_;
const String* file_name_;
const String* method_name_;
int32_t line_number_;
static Class* GetStackTraceElement() {
DCHECK(java_lang_StackTraceElement_ != NULL);
return java_lang_StackTraceElement_;
}
static Class* java_lang_StackTraceElement_;
friend struct StackTraceElementOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(StackTraceElement);
};
class MANAGED InterfaceEntry : public ObjectArray<Object> {
public:
Class* GetInterface() const {
Class* interface = Get(kInterface)->AsClass();
DCHECK(interface != NULL);
return interface;
}
void SetInterface(Class* interface) {
DCHECK(interface != NULL);
DCHECK(interface->IsInterface());
DCHECK(Get(kInterface) == NULL);
Set(kInterface, interface);
}
size_t GetMethodArrayCount() const {
ObjectArray<Method>* method_array = down_cast<ObjectArray<Method>*>(Get(kMethodArray));
if (method_array == 0) {
return 0;
}
return method_array->GetLength();
}
ObjectArray<Method>* GetMethodArray() const {
ObjectArray<Method>* method_array = down_cast<ObjectArray<Method>*>(Get(kMethodArray));
DCHECK(method_array != NULL);
return method_array;
}
void SetMethodArray(ObjectArray<Method>* new_ma) {
DCHECK(new_ma != NULL);
DCHECK(Get(kMethodArray) == NULL);
Set(kMethodArray, new_ma);
}
static size_t LengthAsArray() {
return kMax;
}
private:
enum ArrayIndex {
// Points to the interface class.
kInterface = 0,
// Method pointers into the vtable, allow fast map from interface
// method index to concrete instance method.
kMethodArray = 1,
kMax = 2,
};
DISALLOW_IMPLICIT_CONSTRUCTORS(InterfaceEntry);
};
} // namespace art
#endif // ART_SRC_OBJECT_H_