| /* |
| * 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. |
| */ |
| |
| /* |
| * Helper functions to access data fields in Objects. |
| */ |
| #ifndef DALVIK_OO_OBJECTINLINES_H_ |
| #define DALVIK_OO_OBJECTINLINES_H_ |
| |
| /* |
| * Store a single value in the array, and if the value isn't null, |
| * note in the write barrier. |
| */ |
| INLINE void dvmSetObjectArrayElement(const ArrayObject* obj, int index, |
| Object* val) { |
| ((Object **)(void *)(obj)->contents)[index] = val; |
| if (val != NULL) { |
| dvmWriteBarrierArray(obj, index, index + 1); |
| } |
| } |
| |
| |
| /* |
| * 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. |
| * |
| * Setting Object types to non-null values includes a call to the |
| * write barrier. |
| */ |
| #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 bool dvmGetFieldBooleanVolatile(const Object* obj, int offset) { |
| s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i; |
| return (bool)android_atomic_acquire_load(ptr); |
| } |
| INLINE s1 dvmGetFieldByteVolatile(const Object* obj, int offset) { |
| s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i; |
| return (s1)android_atomic_acquire_load(ptr); |
| } |
| INLINE s2 dvmGetFieldShortVolatile(const Object* obj, int offset) { |
| s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i; |
| return (s2)android_atomic_acquire_load(ptr); |
| } |
| INLINE u2 dvmGetFieldCharVolatile(const Object* obj, int offset) { |
| s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i; |
| return (u2)android_atomic_acquire_load(ptr); |
| } |
| INLINE s4 dvmGetFieldIntVolatile(const Object* obj, int offset) { |
| s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i; |
| return android_atomic_acquire_load(ptr); |
| } |
| INLINE float dvmGetFieldFloatVolatile(const Object* obj, int offset) { |
| union { s4 ival; float fval; } alias; |
| s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i; |
| alias.ival = android_atomic_acquire_load(ptr); |
| return alias.fval; |
| } |
| INLINE s8 dvmGetFieldLongVolatile(const Object* obj, int offset) { |
| const s8* addr = (const s8*)BYTE_OFFSET(obj, offset); |
| s8 val = dvmQuasiAtomicRead64(addr); |
| ANDROID_MEMBAR_FULL(); |
| return val; |
| } |
| INLINE double dvmGetFieldDoubleVolatile(const Object* obj, int offset) { |
| union { s8 lval; double dval; } alias; |
| const s8* addr = (const s8*)BYTE_OFFSET(obj, offset); |
| alias.lval = dvmQuasiAtomicRead64(addr); |
| ANDROID_MEMBAR_FULL(); |
| return alias.dval; |
| } |
| INLINE Object* dvmGetFieldObjectVolatile(const Object* obj, int offset) { |
| Object** ptr = &((JValue*)BYTE_OFFSET(obj, offset))->l; |
| return (Object*)android_atomic_acquire_load((int32_t*)ptr); |
| } |
| |
| 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 dvmSetFieldFloat(Object* obj, int offset, float val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->f = val; |
| } |
| INLINE void dvmSetFieldLong(Object* obj, int offset, s8 val) { |
| ((JValue*)BYTE_OFFSET(obj, offset))->j = 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* lhs = (JValue*)BYTE_OFFSET(obj, offset); |
| lhs->l = val; |
| if (val != NULL) { |
| dvmWriteBarrierField(obj, &lhs->l); |
| } |
| } |
| INLINE void dvmSetFieldIntVolatile(Object* obj, int offset, s4 val) { |
| s4* ptr = &((JValue*)BYTE_OFFSET(obj, offset))->i; |
| /* |
| * 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(); |
| *ptr = val; |
| ANDROID_MEMBAR_FULL(); |
| } |
| INLINE void dvmSetFieldBooleanVolatile(Object* obj, int offset, bool val) { |
| dvmSetFieldIntVolatile(obj, offset, val); |
| } |
| INLINE void dvmSetFieldByteVolatile(Object* obj, int offset, s1 val) { |
| dvmSetFieldIntVolatile(obj, offset, val); |
| } |
| INLINE void dvmSetFieldShortVolatile(Object* obj, int offset, s2 val) { |
| dvmSetFieldIntVolatile(obj, offset, val); |
| } |
| INLINE void dvmSetFieldCharVolatile(Object* obj, int offset, u2 val) { |
| dvmSetFieldIntVolatile(obj, offset, val); |
| } |
| INLINE void dvmSetFieldFloatVolatile(Object* obj, int offset, float val) { |
| union { s4 ival; float fval; } alias; |
| alias.fval = val; |
| dvmSetFieldIntVolatile(obj, offset, alias.ival); |
| } |
| INLINE void dvmSetFieldLongVolatile(Object* obj, int offset, s8 val) { |
| s8* addr = (s8*)BYTE_OFFSET(obj, offset); |
| dvmQuasiAtomicSwap64Sync(val, addr); |
| } |
| INLINE void dvmSetFieldDoubleVolatile(Object* obj, int offset, double val) { |
| union { s8 lval; double dval; } alias; |
| alias.dval = val; |
| dvmSetFieldLongVolatile(obj, offset, alias.lval); |
| } |
| INLINE void dvmSetFieldObjectVolatile(Object* obj, int offset, Object* val) { |
| Object** ptr = &((JValue*)BYTE_OFFSET(obj, offset))->l; |
| ANDROID_MEMBAR_STORE(); |
| *ptr = val; |
| ANDROID_MEMBAR_FULL(); |
| if (val != NULL) { |
| dvmWriteBarrierField(obj, ptr); |
| } |
| } |
| |
| /* |
| * 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 float dvmGetStaticFieldFloat(const StaticField* sfield) { |
| return sfield->value.f; |
| } |
| INLINE s8 dvmGetStaticFieldLong(const StaticField* sfield) { |
| return sfield->value.j; |
| } |
| INLINE double dvmGetStaticFieldDouble(const StaticField* sfield) { |
| return sfield->value.d; |
| } |
| INLINE Object* dvmGetStaticFieldObject(const StaticField* sfield) { |
| return sfield->value.l; |
| } |
| INLINE bool dvmGetStaticFieldBooleanVolatile(const StaticField* sfield) { |
| const s4* ptr = &(sfield->value.i); |
| return (bool)android_atomic_acquire_load((s4*)ptr); |
| } |
| INLINE s1 dvmGetStaticFieldByteVolatile(const StaticField* sfield) { |
| const s4* ptr = &(sfield->value.i); |
| return (s1)android_atomic_acquire_load((s4*)ptr); |
| } |
| INLINE s2 dvmGetStaticFieldShortVolatile(const StaticField* sfield) { |
| const s4* ptr = &(sfield->value.i); |
| return (s2)android_atomic_acquire_load((s4*)ptr); |
| } |
| INLINE u2 dvmGetStaticFieldCharVolatile(const StaticField* sfield) { |
| const s4* ptr = &(sfield->value.i); |
| return (u2)android_atomic_acquire_load((s4*)ptr); |
| } |
| INLINE s4 dvmGetStaticFieldIntVolatile(const StaticField* sfield) { |
| const s4* ptr = &(sfield->value.i); |
| return android_atomic_acquire_load((s4*)ptr); |
| } |
| INLINE float dvmGetStaticFieldFloatVolatile(const StaticField* sfield) { |
| union { s4 ival; float fval; } alias; |
| const s4* ptr = &(sfield->value.i); |
| alias.ival = android_atomic_acquire_load((s4*)ptr); |
| return alias.fval; |
| } |
| INLINE s8 dvmGetStaticFieldLongVolatile(const StaticField* sfield) { |
| const s8* addr = &sfield->value.j; |
| s8 val = dvmQuasiAtomicRead64(addr); |
| ANDROID_MEMBAR_FULL(); |
| return val; |
| } |
| INLINE double dvmGetStaticFieldDoubleVolatile(const StaticField* sfield) { |
| union { s8 lval; double dval; } alias; |
| const s8* addr = &sfield->value.j; |
| alias.lval = dvmQuasiAtomicRead64(addr); |
| ANDROID_MEMBAR_FULL(); |
| return alias.dval; |
| } |
| INLINE Object* dvmGetStaticFieldObjectVolatile(const StaticField* sfield) { |
| Object* const* ptr = &(sfield->value.l); |
| return (Object*)android_atomic_acquire_load((int32_t*)ptr); |
| } |
| |
| 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 dvmSetStaticFieldFloat(StaticField* sfield, float val) { |
| sfield->value.f = val; |
| } |
| INLINE void dvmSetStaticFieldLong(StaticField* sfield, s8 val) { |
| sfield->value.j = val; |
| } |
| INLINE void dvmSetStaticFieldDouble(StaticField* sfield, double val) { |
| sfield->value.d = val; |
| } |
| INLINE void dvmSetStaticFieldObject(StaticField* sfield, Object* val) { |
| sfield->value.l = val; |
| if (val != NULL) { |
| dvmWriteBarrierField(sfield->clazz, &sfield->value.l); |
| } |
| } |
| INLINE void dvmSetStaticFieldIntVolatile(StaticField* sfield, s4 val) { |
| s4* ptr = &sfield->value.i; |
| ANDROID_MEMBAR_STORE(); |
| *ptr = val; |
| ANDROID_MEMBAR_FULL(); |
| } |
| INLINE void dvmSetStaticFieldBooleanVolatile(StaticField* sfield, bool val) { |
| dvmSetStaticFieldIntVolatile(sfield, val); |
| } |
| INLINE void dvmSetStaticFieldByteVolatile(StaticField* sfield, s1 val) { |
| dvmSetStaticFieldIntVolatile(sfield, val); |
| } |
| INLINE void dvmSetStaticFieldShortVolatile(StaticField* sfield, s2 val) { |
| dvmSetStaticFieldIntVolatile(sfield, val); |
| } |
| INLINE void dvmSetStaticFieldCharVolatile(StaticField* sfield, u2 val) { |
| dvmSetStaticFieldIntVolatile(sfield, val); |
| } |
| INLINE void dvmSetStaticFieldFloatVolatile(StaticField* sfield, float val) { |
| union { s4 ival; float fval; } alias; |
| alias.fval = val; |
| dvmSetStaticFieldIntVolatile(sfield, alias.ival); |
| } |
| INLINE void dvmSetStaticFieldLongVolatile(StaticField* sfield, s8 val) { |
| s8* addr = &sfield->value.j; |
| dvmQuasiAtomicSwap64Sync(val, addr); |
| } |
| INLINE void dvmSetStaticFieldDoubleVolatile(StaticField* sfield, double val) { |
| union { s8 lval; double dval; } alias; |
| alias.dval = val; |
| dvmSetStaticFieldLongVolatile(sfield, alias.lval); |
| } |
| INLINE void dvmSetStaticFieldObjectVolatile(StaticField* sfield, Object* val) { |
| Object** ptr = &(sfield->value.l); |
| ANDROID_MEMBAR_STORE(); |
| *ptr = val; |
| ANDROID_MEMBAR_FULL(); |
| if (val != NULL) { |
| dvmWriteBarrierField(sfield->clazz, &sfield->value.l); |
| } |
| } |
| |
| #endif // DALVIK_OO_OBJECTINLINES_H_ |