| /* |
| * Copyright (C) 2008 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. |
| */ |
| |
| /* |
| * Declaration of the fundamental Object type and refinements thereof, plus |
| * some functions for manipulating them. |
| */ |
| #ifndef _DALVIK_OO_OBJECT |
| #define _DALVIK_OO_OBJECT |
| |
| #include <stddef.h> |
| |
| /* fwd decl */ |
| struct DataObject; |
| struct InitiatingLoaderList; |
| struct ClassObject; |
| struct StringObject; |
| struct ArrayObject; |
| struct Method; |
| struct ExceptionEntry; |
| struct LineNumEntry; |
| struct StaticField; |
| struct InstField; |
| struct Field; |
| struct RegisterMap; |
| typedef struct DataObject DataObject; |
| typedef struct InitiatingLoaderList InitiatingLoaderList; |
| typedef struct ClassObject ClassObject; |
| typedef struct StringObject StringObject; |
| typedef struct ArrayObject ArrayObject; |
| typedef struct Method Method; |
| typedef struct ExceptionEntry ExceptionEntry; |
| typedef struct LineNumEntry LineNumEntry; |
| typedef struct StaticField StaticField; |
| typedef struct InstField InstField; |
| typedef struct Field Field; |
| typedef struct RegisterMap RegisterMap; |
| |
| /* |
| * Native function pointer type. |
| * |
| * "args[0]" holds the "this" pointer for virtual methods. |
| * |
| * The "Bridge" form is a super-set of the "Native" form; in many places |
| * they are used interchangeably. Currently, all functions have all |
| * arguments passed in, but some functions only care about the first two. |
| * Passing extra arguments to a C function is (mostly) harmless. |
| */ |
| typedef void (*DalvikBridgeFunc)(const u4* args, JValue* pResult, |
| const Method* method, struct Thread* self); |
| typedef void (*DalvikNativeFunc)(const u4* args, JValue* pResult); |
| |
| |
| /* vm-internal access flags and related definitions */ |
| typedef enum AccessFlags { |
| ACC_MIRANDA = 0x8000, // method (internal to VM) |
| JAVA_FLAGS_MASK = 0xffff, // bits set from Java sources (low 16) |
| } AccessFlags; |
| |
| /* Use the top 16 bits of the access flags field for |
| * other class flags. Code should use the *CLASS_FLAG*() |
| * macros to set/get these flags. |
| */ |
| typedef enum ClassFlags { |
| CLASS_ISFINALIZABLE = (1<<31), // class/ancestor overrides finalize() |
| CLASS_ISARRAY = (1<<30), // class is a "[*" |
| CLASS_ISOBJECTARRAY = (1<<29), // class is a "[L*" or "[[*" |
| CLASS_ISREFERENCE = (1<<28), // class is a soft/weak/phantom ref |
| // only ISREFERENCE is set --> soft |
| CLASS_ISWEAKREFERENCE = (1<<27), // class is a weak reference |
| CLASS_ISPHANTOMREFERENCE = (1<<26), // class is a phantom reference |
| |
| CLASS_MULTIPLE_DEFS = (1<<25), // DEX verifier: defs in multiple DEXs |
| |
| /* unlike the others, these can be present in the optimized DEX file */ |
| CLASS_ISOPTIMIZED = (1<<17), // class may contain opt instrs |
| CLASS_ISPREVERIFIED = (1<<16), // class has been pre-verified |
| } ClassFlags; |
| |
| /* bits we can reasonably expect to see set in a DEX access flags field */ |
| #define EXPECTED_FILE_FLAGS \ |
| (ACC_CLASS_MASK | CLASS_ISPREVERIFIED | CLASS_ISOPTIMIZED) |
| |
| /* |
| * Get/set class flags. |
| */ |
| #define SET_CLASS_FLAG(clazz, flag) \ |
| do { (clazz)->accessFlags |= (flag); } while (0) |
| |
| #define CLEAR_CLASS_FLAG(clazz, flag) \ |
| do { (clazz)->accessFlags &= ~(flag); } while (0) |
| |
| #define IS_CLASS_FLAG_SET(clazz, flag) \ |
| (((clazz)->accessFlags & (flag)) != 0) |
| |
| #define GET_CLASS_FLAG_GROUP(clazz, flags) \ |
| ((u4)((clazz)->accessFlags & (flags))) |
| |
| /* |
| * Use the top 16 bits of the access flags field for other method flags. |
| * Code should use the *METHOD_FLAG*() macros to set/get these flags. |
| */ |
| typedef enum MethodFlags { |
| METHOD_ISWRITABLE = (1<<31), // the method's code is writable |
| } MethodFlags; |
| |
| /* |
| * Get/set method flags. |
| */ |
| #define SET_METHOD_FLAG(method, flag) \ |
| do { (method)->accessFlags |= (flag); } while (0) |
| |
| #define CLEAR_METHOD_FLAG(method, flag) \ |
| do { (method)->accessFlags &= ~(flag); } while (0) |
| |
| #define IS_METHOD_FLAG_SET(method, flag) \ |
| (((method)->accessFlags & (flag)) != 0) |
| |
| #define GET_METHOD_FLAG_GROUP(method, flags) \ |
| ((u4)((method)->accessFlags & (flags))) |
| |
| /* current state of the class, increasing as we progress */ |
| typedef enum ClassStatus { |
| CLASS_ERROR = -1, |
| |
| CLASS_NOTREADY = 0, |
| CLASS_LOADED = 1, |
| CLASS_PREPARED = 2, /* part of linking */ |
| CLASS_RESOLVED = 3, /* part of linking */ |
| CLASS_VERIFYING = 4, /* in the process of being verified */ |
| CLASS_VERIFIED = 5, /* logically part of linking; done pre-init */ |
| CLASS_INITIALIZING = 6, /* class init in progress */ |
| CLASS_INITIALIZED = 7, /* ready to go */ |
| } ClassStatus; |
| |
| |
| /* |
| * Primitive type identifiers. We use these values as indexes into an |
| * array of synthesized classes, so these start at zero and count up. |
| * The order is arbitrary (mimics table in doc for newarray opcode), |
| * but can't be changed without shuffling some reflection tables. |
| * |
| * PRIM_VOID can't be used as an array type, but we include it here for |
| * other uses (e.g. Void.TYPE). |
| */ |
| typedef enum PrimitiveType { |
| PRIM_NOT = -1, /* value is not a primitive type */ |
| PRIM_BOOLEAN = 0, |
| PRIM_CHAR = 1, |
| PRIM_FLOAT = 2, |
| PRIM_DOUBLE = 3, |
| PRIM_BYTE = 4, |
| PRIM_SHORT = 5, |
| PRIM_INT = 6, |
| PRIM_LONG = 7, |
| PRIM_VOID = 8, |
| |
| PRIM_MAX |
| } PrimitiveType; |
| #define PRIM_TYPE_TO_LETTER "ZCFDBSIJV" /* must match order in enum */ |
| |
| /* |
| * Definitions for packing refOffsets in ClassObject. |
| */ |
| /* |
| * A magic value for refOffsets. Ignore the bits and walk the super |
| * chain when this is the value. |
| * [This is an unlikely "natural" value, since it would be 30 non-ref instance |
| * fields followed by 2 ref instance fields.] |
| */ |
| #define CLASS_WALK_SUPER ((unsigned int)(3)) |
| #define CLASS_SMALLEST_OFFSET (sizeof(struct Object)) |
| #define CLASS_BITS_PER_WORD (sizeof(unsigned long int) * 8) |
| #define CLASS_OFFSET_ALIGNMENT 4 |
| #define CLASS_HIGH_BIT ((unsigned int)1 << (CLASS_BITS_PER_WORD - 1)) |
| /* |
| * Return a single bit, or zero if the encoding can't encode the offset. |
| */ |
| #define CLASS_BIT_FROM_OFFSET(byteOffset) \ |
| (CLASS_HIGH_BIT >> \ |
| (((unsigned int)(byteOffset) - CLASS_SMALLEST_OFFSET) / \ |
| CLASS_OFFSET_ALIGNMENT)) |
| /* |
| * Return an offset, given a bit number as returned from CLZ. |
| */ |
| #define CLASS_OFFSET_FROM_CLZ(rshift) \ |
| (((int)(rshift) * CLASS_OFFSET_ALIGNMENT) + CLASS_SMALLEST_OFFSET) |
| |
| |
| /* |
| * Used for iftable in ClassObject. |
| */ |
| typedef struct InterfaceEntry { |
| /* pointer to interface class */ |
| ClassObject* clazz; |
| |
| /* |
| * Index into array of vtable offsets. This points into the ifviPool, |
| * which holds the vtables for all interfaces declared by this class. |
| */ |
| int* methodIndexArray; |
| } InterfaceEntry; |
| |
| |
| |
| /* |
| * There are three types of objects: |
| * Class objects - an instance of java.lang.Class |
| * Array objects - an object created with a "new array" instruction |
| * Data objects - an object that is neither of the above |
| * |
| * We also define String objects. At present they're equivalent to |
| * DataObject, but that may change. (Either way, they make some of the |
| * code more obvious.) |
| * |
| * All objects have an Object header followed by type-specific data. |
| */ |
| typedef struct Object { |
| /* ptr to class object */ |
| ClassObject* clazz; |
| |
| /* thin lock or "fat" monitor */ |
| Lock lock; |
| } Object; |
| |
| /* |
| * Properly initialize an Object. |
| * void DVM_OBJECT_INIT(Object *obj, ClassObject *clazz_) |
| */ |
| #define DVM_OBJECT_INIT(obj, clazz_) \ |
| do { (obj)->clazz = (clazz_); DVM_LOCK_INIT(&(obj)->lock); } while (0) |
| |
| /* |
| * Data objects have an Object header followed by their instance data. |
| */ |
| struct DataObject { |
| Object obj; /* MUST be first item */ |
| |
| /* variable #of u4 slots; u8 uses 2 slots */ |
| u4 instanceData[1]; |
| }; |
| |
| /* |
| * Strings are used frequently enough that we may want to give them their |
| * own unique type. |
| * |
| * Using a dedicated type object to access the instance data provides a |
| * performance advantage but makes the java/lang/String.java implementation |
| * fragile. |
| * |
| * Currently this is just equal to DataObject, and we pull the fields out |
| * like we do for any other object. |
| */ |
| struct StringObject { |
| Object obj; /* MUST be first item */ |
| |
| /* variable #of u4 slots; u8 uses 2 slots */ |
| u4 instanceData[1]; |
| }; |
| |
| |
| /* |
| * Array objects have these additional fields. |
| * |
| * We don't currently store the size of each element. Usually it's implied |
| * by the instruction. If necessary, the width can be derived from |
| * the first char of obj->clazz->name. |
| */ |
| struct ArrayObject { |
| Object obj; /* MUST be first item */ |
| |
| /* number of elements; immutable after init */ |
| u4 length; |
| |
| /* |
| * Array contents; actual size is (length * sizeof(type)). This is |
| * declared as u8 so that the compiler inserts any necessary padding |
| * (e.g. for EABI); the actual allocation may be smaller than 8 bytes. |
| */ |
| u8 contents[1]; |
| }; |
| |
| /* |
| * For classes created early and thus probably in the zygote, the |
| * InitiatingLoaderList is kept in gDvm. Later classes use the structure in |
| * Object Class. This helps keep zygote pages shared. |
| */ |
| struct InitiatingLoaderList { |
| /* a list of initiating loader Objects; grown and initialized on demand */ |
| Object** initiatingLoaders; |
| /* count of loaders in the above list */ |
| int initiatingLoaderCount; |
| }; |
| |
| /* |
| * This defines the amount of space we leave for field slots in the |
| * java.lang.Class definition. If we alter the class to have more than |
| * this many fields, the VM will abort at startup. |
| */ |
| #define CLASS_FIELD_SLOTS 4 |
| |
| /* |
| * Class objects have many additional fields. This is used for both |
| * classes and interfaces, including synthesized classes (arrays and |
| * primitive types). |
| * |
| * Class objects are unusual in that they have some fields allocated with |
| * the system malloc (or LinearAlloc), rather than on the GC heap. This is |
| * handy during initialization, but does require special handling when |
| * discarding java.lang.Class objects. |
| * |
| * The separation of methods (direct vs. virtual) and fields (class vs. |
| * instance) used in Dalvik works out pretty well. The only time it's |
| * annoying is when enumerating or searching for things with reflection. |
| */ |
| struct ClassObject { |
| Object obj; /* MUST be first item */ |
| |
| /* leave space for instance data; we could access fields directly if we |
| freeze the definition of java/lang/Class */ |
| u4 instanceData[CLASS_FIELD_SLOTS]; |
| |
| /* UTF-8 descriptor for the class; from constant pool, or on heap |
| if generated ("[C") */ |
| const char* descriptor; |
| char* descriptorAlloc; |
| |
| /* access flags; low 16 bits are defined by VM spec */ |
| u4 accessFlags; |
| |
| /* VM-unique class serial number, nonzero, set very early */ |
| u4 serialNumber; |
| |
| /* DexFile from which we came; needed to resolve constant pool entries */ |
| /* (will be NULL for VM-generated, e.g. arrays and primitive classes) */ |
| DvmDex* pDvmDex; |
| |
| /* state of class initialization */ |
| ClassStatus status; |
| |
| /* if class verify fails, we must return same error on subsequent tries */ |
| ClassObject* verifyErrorClass; |
| |
| /* threadId, used to check for recursive <clinit> invocation */ |
| u4 initThreadId; |
| |
| /* |
| * Total object size; used when allocating storage on gc heap. (For |
| * interfaces and abstract classes this will be zero.) |
| */ |
| size_t objectSize; |
| |
| /* arrays only: class object for base element, for instanceof/checkcast |
| (for String[][][], this will be String) */ |
| ClassObject* elementClass; |
| |
| /* class object representing an array of this class; set on first use */ |
| ClassObject* arrayClass; |
| |
| /* arrays only: number of dimensions, e.g. int[][] is 2 */ |
| int arrayDim; |
| |
| /* primitive type index, or PRIM_NOT (-1); set for generated prim classes */ |
| PrimitiveType primitiveType; |
| |
| /* superclass, or NULL if this is java.lang.Object */ |
| ClassObject* super; |
| |
| /* defining class loader, or NULL for the "bootstrap" system loader */ |
| Object* classLoader; |
| |
| /* initiating class loader list */ |
| /* NOTE: for classes with low serialNumber, these are unused, and the |
| values are kept in a table in gDvm. */ |
| InitiatingLoaderList initiatingLoaderList; |
| |
| /* array of interfaces this class implements directly */ |
| int interfaceCount; |
| ClassObject** interfaces; |
| |
| /* static, private, and <init> methods */ |
| int directMethodCount; |
| Method* directMethods; |
| |
| /* virtual methods defined in this class; invoked through vtable */ |
| int virtualMethodCount; |
| Method* virtualMethods; |
| |
| /* |
| * 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. |
| */ |
| int vtableCount; |
| Method** vtable; |
| |
| /* |
| * Interface table (iftable), one entry per interface supported by |
| * this class. That means one entry for each interface we support |
| * directly, indirectly via superclass, or indirectly via |
| * superinterface. This will be null if neither we nor our superclass |
| * implement any interfaces. |
| * |
| * Why we need this: given "class Foo implements Face", declare |
| * "Face faceObj = new Foo()". Invoke faceObj.blah(), where "blah" is |
| * part of the Face interface. We can't easily use a single vtable. |
| * |
| * For every interface a concrete class implements, we create a list of |
| * virtualMethod indices for the methods in the interface. |
| */ |
| int iftableCount; |
| InterfaceEntry* iftable; |
| |
| /* |
| * The interface vtable indices for iftable get stored here. By placing |
| * them all in a single pool for each class that implements interfaces, |
| * we decrease the number of allocations. |
| */ |
| int ifviPoolCount; |
| int* ifviPool; |
| |
| /* static fields */ |
| int sfieldCount; |
| StaticField* sfields; |
| |
| /* instance fields |
| * |
| * These describe the layout of the contents of a DataObject-compatible |
| * Object. Note that only the fields directly defined by this class |
| * are listed in ifields; fields defined by a superclass are listed |
| * in the superclass's ClassObject.ifields. |
| * |
| * All instance fields that refer to objects are guaranteed to be |
| * at the beginning of the field list. ifieldRefCount specifies |
| * the number of reference fields. |
| */ |
| int ifieldCount; |
| int ifieldRefCount; // number of fields that are object refs |
| InstField* ifields; |
| |
| /* bitmap of offsets of ifields */ |
| u4 refOffsets; |
| |
| /* source file name, if known */ |
| const char* sourceFile; |
| }; |
| |
| /* |
| * A method. We create one of these for every method in every class |
| * we load, so try to keep the size to a minimum. |
| * |
| * Much of this comes from and could be accessed in the data held in shared |
| * memory. We hold it all together here for speed. Everything but the |
| * pointers could be held in a shared table generated by the optimizer; |
| * if we're willing to convert them to offsets and take the performance |
| * hit (e.g. "meth->insns" becomes "baseAddr + meth->insnsOffset") we |
| * could move everything but "nativeFunc". |
| */ |
| struct Method { |
| /* the class we are a part of */ |
| ClassObject* clazz; |
| |
| /* access flags; low 16 bits are defined by spec (could be u2?) */ |
| u4 accessFlags; |
| |
| /* |
| * 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". |
| */ |
| u2 methodIndex; |
| |
| /* |
| * 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. |
| */ |
| u2 registersSize; /* ins + locals */ |
| u2 outsSize; |
| u2 insSize; |
| |
| /* method name, e.g. "<init>" or "eatLunch" */ |
| const char* name; |
| |
| /* |
| * Method prototype descriptor string (return and argument types). |
| * |
| * TODO: This currently must specify the DexFile as well as the proto_ids |
| * index, because generated Proxy classes don't have a DexFile. We can |
| * remove the DexFile* and reduce the size of this struct if we generate |
| * a DEX for proxies. |
| */ |
| DexProto prototype; |
| |
| /* short-form method descriptor string */ |
| const char* shorty; |
| |
| /* |
| * The remaining items are not used for abstract or native methods. |
| * (JNI is currently hijacking "insns" as a function pointer, set |
| * after the first call. For internal-native this stays null.) |
| */ |
| |
| /* the actual code */ |
| const u2* insns; /* instructions, in memory-mapped .dex */ |
| |
| /* cached JNI argument and return-type hints */ |
| int jniArgInfo; |
| |
| /* |
| * Native method ptr; could be actual function or a JNI bridge. We |
| * don't currently discriminate between DalvikBridgeFunc and |
| * DalvikNativeFunc; the former takes an argument superset (i.e. two |
| * extra args) which will be ignored. If necessary we can use |
| * insns==NULL to detect JNI bridge vs. internal native. |
| */ |
| DalvikBridgeFunc nativeFunc; |
| |
| /* |
| * Register map data, if available. This will point into the DEX file |
| * if the data was computed during pre-verification, or into the |
| * linear alloc area if not. |
| */ |
| const RegisterMap* registerMap; |
| |
| #ifdef WITH_PROFILER |
| bool inProfile; |
| #endif |
| #ifdef WITH_DEBUGGER |
| short debugBreakpointCount; |
| #endif |
| }; |
| |
| /* |
| * Generic field header. We pass this around when we want a generic Field |
| * pointer (e.g. for reflection stuff). Testing the accessFlags for |
| * ACC_STATIC allows a proper up-cast. |
| */ |
| struct Field { |
| ClassObject* clazz; /* class in which the field is declared */ |
| const char* name; |
| const char* signature; /* e.g. "I", "[C", "Landroid/os/Debug;" */ |
| u4 accessFlags; |
| #ifdef PROFILE_FIELD_ACCESS |
| u4 gets; |
| u4 puts; |
| #endif |
| }; |
| |
| /* |
| * Static field. |
| */ |
| struct StaticField { |
| Field field; /* MUST be first item */ |
| JValue value; /* initially set from DEX for primitives */ |
| }; |
| |
| /* |
| * Instance field. |
| */ |
| struct InstField { |
| Field field; /* MUST be first item */ |
| |
| /* |
| * This field indicates the byte offset from the beginning of the |
| * (Object *) to the actual instance data; e.g., byteOffset==0 is |
| * the same as the object pointer (bug!), and byteOffset==4 is 4 |
| * bytes farther. |
| */ |
| int byteOffset; |
| }; |
| |
| |
| /* |
| * Find a method within a class. The superclass is not searched. |
| */ |
| Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz, |
| const char* methodName, const char* signature); |
| Method* dvmFindVirtualMethodByDescriptor(const ClassObject* clazz, |
| const char* methodName, const char* signature); |
| Method* dvmFindVirtualMethodByName(const ClassObject* clazz, |
| const char* methodName); |
| Method* dvmFindDirectMethod(const ClassObject* clazz, const char* methodName, |
| const DexProto* proto); |
| Method* dvmFindVirtualMethod(const ClassObject* clazz, const char* methodName, |
| const DexProto* proto); |
| |
| |
| /* |
| * Find a method within a class hierarchy. |
| */ |
| Method* dvmFindDirectMethodHierByDescriptor(const ClassObject* clazz, |
| const char* methodName, const char* descriptor); |
| Method* dvmFindVirtualMethodHierByDescriptor(const ClassObject* clazz, |
| const char* methodName, const char* signature); |
| Method* dvmFindDirectMethodHier(const ClassObject* clazz, |
| const char* methodName, const DexProto* proto); |
| Method* dvmFindVirtualMethodHier(const ClassObject* clazz, |
| const char* methodName, const DexProto* proto); |
| Method* dvmFindMethodHier(const ClassObject* clazz, const char* methodName, |
| const DexProto* proto); |
| |
| /* |
| * Find the implementation of "meth" in "clazz". |
| * |
| * Returns NULL and throws an exception if not found. |
| */ |
| const Method* dvmGetVirtualizedMethod(const ClassObject* clazz, |
| const Method* meth); |
| |
| /* |
| * Get the source file associated with a method. |
| */ |
| const char* dvmGetMethodSourceFile(const Method* meth); |
| |
| /* |
| * Find a field within a class. The superclass is not searched. |
| */ |
| InstField* dvmFindInstanceField(const ClassObject* clazz, |
| const char* fieldName, const char* signature); |
| StaticField* dvmFindStaticField(const ClassObject* clazz, |
| const char* fieldName, const char* signature); |
| |
| /* |
| * Find a field in a class/interface hierarchy. |
| */ |
| InstField* dvmFindInstanceFieldHier(const ClassObject* clazz, |
| const char* fieldName, const char* signature); |
| StaticField* dvmFindStaticFieldHier(const ClassObject* clazz, |
| const char* fieldName, const char* signature); |
| Field* dvmFindFieldHier(const ClassObject* clazz, const char* fieldName, |
| const char* signature); |
| |
| /* |
| * Find a field and return the byte offset from the object pointer. Only |
| * searches the specified class, not the superclass. |
| * |
| * Returns -1 on failure. |
| */ |
| INLINE int dvmFindFieldOffset(const ClassObject* clazz, |
| const char* fieldName, const char* signature) |
| { |
| InstField* pField = dvmFindInstanceField(clazz, fieldName, signature); |
| if (pField == NULL) |
| return -1; |
| else |
| return pField->byteOffset; |
| } |
| |
| /* |
| * Field access functions. Pass in the word offset from Field->byteOffset. |
| * |
| * We guarantee that long/double field data is 64-bit aligned, so it's safe |
| * to access them with ldrd/strd on ARM. |
| * |
| * The VM treats all fields as 32 or 64 bits, so the field set functions |
| * write 32 bits even if the underlying type is smaller. |
| */ |
| #define BYTE_OFFSET(_ptr, _offset) ((void*) (((u1*)(_ptr)) + (_offset))) |
| |
| INLINE JValue* dvmFieldPtr(const Object* obj, int offset) { |
| return ((JValue*)BYTE_OFFSET(obj, offset)); |
| } |
| |
| INLINE bool dvmGetFieldBoolean(const Object* obj, int offset) { |
| return ((JValue*)BYTE_OFFSET(obj, offset))->z; |
| } |
| INLINE s1 dvmGetFieldByte(const Object* obj, int offset) { |
| return ((JValue*)BYTE_OFFSET(obj, offset))->b; |
| } |
| INLINE s2 dvmGetFieldShort(const Object* obj, int offset) { |
| return ((JValue*)BYTE_OFFSET(obj, offset))->s; |
| } |
| INLINE u2 dvmGetFieldChar(const Object* obj, int offset) { |
| return ((JValue*)BYTE_OFFSET(obj, offset))->c; |
| } |
| INLINE s4 dvmGetFieldInt(const Object* obj, int offset) { |
| return ((JValue*)BYTE_OFFSET(obj, offset))->i; |
| } |
| INLINE s8 dvmGetFieldLong(const Object* obj, int offset) { |
| return ((JValue*)BYTE_OFFSET(obj, offset))->j; |
| } |
| INLINE float dvmGetFieldFloat(const Object* obj, int offset) { |
| return ((JValue*)BYTE_OFFSET(obj, offset))->f; |
| } |
| INLINE double dvmGetFieldDouble(const Object* obj, int offset) { |
| return ((JValue*)BYTE_OFFSET(obj, offset))->d; |
| } |
| INLINE Object* dvmGetFieldObject(const Object* obj, int offset) { |
| return ((JValue*)BYTE_OFFSET(obj, offset))->l; |
| } |
| |
| INLINE void dvmSetFieldBoolean(Object* obj, int offset, bool val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->i = val; |
| } |
| INLINE void dvmSetFieldByte(Object* obj, int offset, s1 val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->i = val; |
| } |
| INLINE void dvmSetFieldShort(Object* obj, int offset, s2 val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->i = val; |
| } |
| INLINE void dvmSetFieldChar(Object* obj, int offset, u2 val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->i = val; |
| } |
| INLINE void dvmSetFieldInt(Object* obj, int offset, s4 val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->i = val; |
| } |
| INLINE void dvmSetFieldLong(Object* obj, int offset, s8 val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->j = val; |
| } |
| INLINE void dvmSetFieldFloat(Object* obj, int offset, float val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->f = val; |
| } |
| INLINE void dvmSetFieldDouble(Object* obj, int offset, double val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->d = val; |
| } |
| INLINE void dvmSetFieldObject(Object* obj, int offset, Object* val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->l = val; |
| } |
| |
| /* |
| * Static field access functions. |
| */ |
| INLINE JValue* dvmStaticFieldPtr(const StaticField* sfield) { |
| return (JValue*)&sfield->value; |
| } |
| |
| INLINE bool dvmGetStaticFieldBoolean(const StaticField* sfield) { |
| return sfield->value.z; |
| } |
| INLINE s1 dvmGetStaticFieldByte(const StaticField* sfield) { |
| return sfield->value.b; |
| } |
| INLINE s2 dvmGetStaticFieldShort(const StaticField* sfield) { |
| return sfield->value.s; |
| } |
| INLINE u2 dvmGetStaticFieldChar(const StaticField* sfield) { |
| return sfield->value.c; |
| } |
| INLINE s4 dvmGetStaticFieldInt(const StaticField* sfield) { |
| return sfield->value.i; |
| } |
| INLINE s8 dvmGetStaticFieldLong(const StaticField* sfield) { |
| return sfield->value.j; |
| } |
| INLINE float dvmGetStaticFieldFloat(const StaticField* sfield) { |
| return sfield->value.f; |
| } |
| INLINE double dvmGetStaticFieldDouble(const StaticField* sfield) { |
| return sfield->value.d; |
| } |
| INLINE Object* dvmGetStaticFieldObject(const StaticField* sfield) { |
| return sfield->value.l; |
| } |
| |
| INLINE void dvmSetStaticFieldBoolean(StaticField* sfield, bool val) { |
| sfield->value.i = val; |
| } |
| INLINE void dvmSetStaticFieldByte(StaticField* sfield, s1 val) { |
| sfield->value.i = val; |
| } |
| INLINE void dvmSetStaticFieldShort(StaticField* sfield, s2 val) { |
| sfield->value.i = val; |
| } |
| INLINE void dvmSetStaticFieldChar(StaticField* sfield, u2 val) { |
| sfield->value.i = val; |
| } |
| INLINE void dvmSetStaticFieldInt(StaticField* sfield, s4 val) { |
| sfield->value.i = val; |
| } |
| INLINE void dvmSetStaticFieldLong(StaticField* sfield, s8 val) { |
| sfield->value.j = val; |
| } |
| INLINE void dvmSetStaticFieldFloat(StaticField* sfield, float val) { |
| sfield->value.f = val; |
| } |
| INLINE void dvmSetStaticFieldDouble(StaticField* sfield, double val) { |
| sfield->value.d = val; |
| } |
| INLINE void dvmSetStaticFieldObject(StaticField* sfield, Object* val) { |
| sfield->value.l = val; |
| } |
| |
| /* |
| * Helpers. |
| */ |
| INLINE bool dvmIsPublicMethod(const Method* method) { |
| return (method->accessFlags & ACC_PUBLIC) != 0; |
| } |
| INLINE bool dvmIsPrivateMethod(const Method* method) { |
| return (method->accessFlags & ACC_PRIVATE) != 0; |
| } |
| INLINE bool dvmIsStaticMethod(const Method* method) { |
| return (method->accessFlags & ACC_STATIC) != 0; |
| } |
| INLINE bool dvmIsSynchronizedMethod(const Method* method) { |
| return (method->accessFlags & ACC_SYNCHRONIZED) != 0; |
| } |
| INLINE bool dvmIsDeclaredSynchronizedMethod(const Method* method) { |
| return (method->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0; |
| } |
| INLINE bool dvmIsFinalMethod(const Method* method) { |
| return (method->accessFlags & ACC_FINAL) != 0; |
| } |
| INLINE bool dvmIsNativeMethod(const Method* method) { |
| return (method->accessFlags & ACC_NATIVE) != 0; |
| } |
| INLINE bool dvmIsAbstractMethod(const Method* method) { |
| return (method->accessFlags & ACC_ABSTRACT) != 0; |
| } |
| INLINE bool dvmIsMirandaMethod(const Method* method) { |
| return (method->accessFlags & ACC_MIRANDA) != 0; |
| } |
| INLINE bool dvmIsConstructorMethod(const Method* method) { |
| return *method->name == '<'; |
| } |
| /* Dalvik puts private, static, and constructors into non-virtual table */ |
| INLINE bool dvmIsDirectMethod(const Method* method) { |
| return dvmIsPrivateMethod(method) || |
| dvmIsStaticMethod(method) || |
| dvmIsConstructorMethod(method); |
| } |
| /* Get whether the given method has associated bytecode. This is the |
| * case for methods which are neither native nor abstract. */ |
| INLINE bool dvmIsBytecodeMethod(const Method* method) { |
| return (method->accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0; |
| } |
| |
| INLINE bool dvmIsProtectedField(const Field* field) { |
| return (field->accessFlags & ACC_PROTECTED) != 0; |
| } |
| INLINE bool dvmIsStaticField(const Field* field) { |
| return (field->accessFlags & ACC_STATIC) != 0; |
| } |
| INLINE bool dvmIsFinalField(const Field* field) { |
| return (field->accessFlags & ACC_FINAL) != 0; |
| } |
| |
| INLINE bool dvmIsInterfaceClass(const ClassObject* clazz) { |
| return (clazz->accessFlags & ACC_INTERFACE) != 0; |
| } |
| INLINE bool dvmIsPublicClass(const ClassObject* clazz) { |
| return (clazz->accessFlags & ACC_PUBLIC) != 0; |
| } |
| INLINE bool dvmIsFinalClass(const ClassObject* clazz) { |
| return (clazz->accessFlags & ACC_FINAL) != 0; |
| } |
| INLINE bool dvmIsAbstractClass(const ClassObject* clazz) { |
| return (clazz->accessFlags & ACC_ABSTRACT) != 0; |
| } |
| INLINE bool dvmIsAnnotationClass(const ClassObject* clazz) { |
| return (clazz->accessFlags & ACC_ANNOTATION) != 0; |
| } |
| INLINE bool dvmIsPrimitiveClass(const ClassObject* clazz) { |
| return clazz->primitiveType != PRIM_NOT; |
| } |
| |
| /* linked, here meaning prepared and resolved */ |
| INLINE bool dvmIsClassLinked(const ClassObject* clazz) { |
| return clazz->status >= CLASS_RESOLVED; |
| } |
| /* has class been verified? */ |
| INLINE bool dvmIsClassVerified(const ClassObject* clazz) { |
| return clazz->status >= CLASS_VERIFIED; |
| } |
| |
| /* |
| * Get the associated code struct for a method. This returns NULL |
| * for non-bytecode methods. |
| */ |
| INLINE const DexCode* dvmGetMethodCode(const Method* meth) { |
| if (dvmIsBytecodeMethod(meth)) { |
| /* |
| * The insns field for a bytecode method actually points at |
| * &(DexCode.insns), so we can subtract back to get at the |
| * DexCode in front. |
| */ |
| return (const DexCode*) |
| (((const u1*) meth->insns) - offsetof(DexCode, insns)); |
| } else { |
| return NULL; |
| } |
| } |
| |
| /* |
| * Get the size of the insns associated with a method. This returns 0 |
| * for non-bytecode methods. |
| */ |
| INLINE u4 dvmGetMethodInsnsSize(const Method* meth) { |
| const DexCode* pCode = dvmGetMethodCode(meth); |
| return (pCode == NULL) ? 0 : pCode->insnsSize; |
| } |
| |
| /* debugging */ |
| void dvmDumpObject(const Object* obj); |
| |
| #endif /*_DALVIK_OO_OBJECT*/ |