// 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 ObjectArray; template class PrimitiveArray; typedef PrimitiveArray BooleanArray; typedef PrimitiveArray ByteArray; typedef PrimitiveArray CharArray; typedef PrimitiveArray DoubleArray; typedef PrimitiveArray FloatArray; typedef PrimitiveArray IntArray; typedef PrimitiveArray LongArray; typedef PrimitiveArray 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(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(this); Object* other = that->GetFieldObject(field_offset); return const_cast(other); } Object* GetFieldObject(size_t field_offset) { byte* raw_addr = reinterpret_cast(this) + field_offset; return *reinterpret_cast(raw_addr); } void SetFieldObject(size_t offset, Object* new_value) { byte* raw_addr = reinterpret_cast(this) + offset; *reinterpret_cast(raw_addr) = new_value; // TODO: write barrier } bool IsClass() const; Class* AsClass() { DCHECK(IsClass()); return down_cast(this); } const Class* AsClass() const { DCHECK(IsClass()); return down_cast(this); } bool IsObjectArray() const; template ObjectArray* AsObjectArray() { DCHECK(IsObjectArray()); return down_cast*>(this); } template const ObjectArray* AsObjectArray() const { DCHECK(IsObjectArray()); return down_cast*>(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(this); } const Array* AsArray() const { DCHECK(IsArray()); return down_cast(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. "" 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* 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* 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 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 ObjectArray : public Array { public: static ObjectArray* Alloc(Class* object_array_class, size_t length) { return Array::Alloc(object_array_class, length, sizeof(uint32_t))->AsObjectArray(); } T* const * GetData() const { return reinterpret_cast(&elements_); } T** GetData() { return reinterpret_cast(&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* src, int src_pos, ObjectArray* 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* CopyOf(int32_t new_length) { ObjectArray* 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& GetClassPath() { return class_path_; } void SetClassPath(std::vector& 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 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 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* interfaces_; uint32_t* interfaces_idx_; // static, private, and methods ObjectArray* direct_methods_; // virtual methods defined in this class; invoked through vtable ObjectArray* 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* 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* 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* 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* 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 PrimitiveArray : public Array { public: static PrimitiveArray* Alloc(size_t length); const T* GetData() const { return reinterpret_cast(&elements_); } T* GetData() { return reinterpret_cast(&elements_); } T Get(int32_t i) const { if (!IsValidIndex(i)) { return T(); } 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; } else { 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(Class* java_lang_String, int32_t utf16_length, const char* utf8_data_in) { String* string = Alloc(java_lang_String, utf16_length); uint16_t* utf16_data_out = string->array_->GetData(); ConvertModifiedUtf8ToUtf16(utf16_data_out, utf8_data_in); string->ComputeHashCode(); return string; } // Creates a String of the given ASCII characters. It is an error to call this // using non-ASCII characters as this function assumes one char per byte. static String* AllocFromAscii(const char* ascii_data_in) { return AllocFromModifiedUtf8(GetJavaLangString(), strlen(ascii_data_in), ascii_data_in); } static String* AllocFromModifiedUtf8(int32_t utf16_length, const char* utf8_data_in) { return AllocFromModifiedUtf8(GetJavaLangString(), utf16_length, utf8_data_in); } static void InitClasses(Class* java_lang_String); static String* Alloc(Class* java_lang_String, int32_t utf16_length) { String* string = down_cast(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_