2021-07-16 17:12:20 -05:00

741 lines
24 KiB
Java

/*
* @(#) $(JCGO)/goclsp/vm/java/lang/reflect/VMField.java --
* VM specific methods for Java "Field" implementation.
**
* Project: JCGO (http://www.ivmaisoft.com/jcgo/)
* Copyright (C) 2001-2012 Ivan Maidanski <ivmai@ivmaisoft.com>
* All rights reserved.
*/
/*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
**
* This software is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License (GPL) for more details.
**
* Linking this library statically or dynamically with other modules is
* making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
**
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under
* terms of your choice, provided that you also meet, for each linked
* independent module, the terms and conditions of the license of that
* module. An independent module is a module which is not derived from
* or based on this library. If you modify this library, you may extend
* this exception to your version of the library, but you are not
* obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
package java.lang.reflect;
final class VMField /* hard-coded class name */
{ /* VM class */ /* used by VM classes only */
private static final int TYPECODE_BOOLEAN = 1;
private static final int TYPECODE_BYTE = 2;
private static final int TYPECODE_CHAR = 3;
private static final int TYPECODE_SHORT = 4;
private static final int TYPECODE_INT = 5;
static
{
if (!"".equals("")) /* hack */
{
getStaticFieldClass0X(null); /* hack */
getSlotOfField0X(null); /* hack */
getFieldByName0X(void.class, "", "", 0); /* hack */
getFieldBySlot0X(void.class, 0); /* hack */
}
}
private VMField() {}
static final int getModifiersInternal(Field field)
{
return field.modifiers;
}
static final Class getType(Field field)
{
Class type = field.type;
if (type == null) /* hack */
throw new InternalError();
return type;
}
static final String getSignature(Field field)
{
return field.signature;
}
static final Object get(Field field, Object obj, Class caller)
throws IllegalAccessException
{
checkAllowGet(field, obj, caller);
Class type = getType(field);
int mods = getModifiersInternal(field);
if (type == double.class)
return new Double(getDouble0(fieldObjectOrClass(field, obj), field.slot,
mods));
if (type == float.class)
return new Float(getFloat0(fieldObjectOrClass(field, obj), field.slot,
mods));
if (type == long.class)
return new Long(getLong0(fieldObjectOrClass(field, obj), field.slot,
mods));
if (type == int.class)
return new Integer(getInt0(fieldObjectOrClass(field, obj), field.slot,
mods, TYPECODE_INT));
if (type == short.class)
return new Short((short) getInt0(fieldObjectOrClass(field, obj),
field.slot, mods, TYPECODE_SHORT));
if (type == char.class)
return new Character((char) getInt0(fieldObjectOrClass(field, obj),
field.slot, mods, TYPECODE_CHAR));
if (type == byte.class)
return new Byte((byte) getInt0(fieldObjectOrClass(field, obj), field.slot,
mods, TYPECODE_BYTE));
if (type == boolean.class)
return getInt0(fieldObjectOrClass(field, obj), field.slot, mods,
TYPECODE_BOOLEAN) != 0 ? Boolean.TRUE : Boolean.FALSE;
return get0(fieldObjectOrClass(field, obj), field.slot, mods);
}
static final boolean getBoolean(Field field, Object obj, Class caller)
throws IllegalAccessException
{
checkAllowGet(field, obj, caller);
if (getType(field) != boolean.class)
throw new IllegalArgumentException("field type mismatch");
return getInt0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field), TYPECODE_BOOLEAN) != 0;
}
static final byte getByte(Field field, Object obj, Class caller)
throws IllegalAccessException
{
checkAllowGet(field, obj, caller);
if (getType(field) != byte.class)
throw new IllegalArgumentException("field type mismatch");
return (byte) getInt0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field), TYPECODE_BYTE);
}
static final char getChar(Field field, Object obj, Class caller)
throws IllegalAccessException
{
checkAllowGet(field, obj, caller);
if (getType(field) != char.class)
throw new IllegalArgumentException("field type mismatch");
return (char) getInt0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field), TYPECODE_CHAR);
}
static final short getShort(Field field, Object obj, Class caller)
throws IllegalAccessException
{
checkAllowGet(field, obj, caller);
Class type = getType(field);
int typecode = TYPECODE_SHORT;
if (type != short.class)
{
if (type == byte.class)
typecode = TYPECODE_BYTE;
else throw new IllegalArgumentException("field type mismatch");
}
return (short) getInt0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field), typecode);
}
static final int getInt(Field field, Object obj, Class caller)
throws IllegalAccessException
{
checkAllowGet(field, obj, caller);
return getIntInner(field, obj);
}
static final long getLong(Field field, Object obj, Class caller)
throws IllegalAccessException
{
checkAllowGet(field, obj, caller);
if (getType(field) == long.class)
return getLong0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field));
return getIntInner(field, obj);
}
static final float getFloat(Field field, Object obj, Class caller)
throws IllegalAccessException
{
checkAllowGet(field, obj, caller);
Class type = getType(field);
if (type == float.class)
return getFloat0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field));
if (type == long.class)
return getLong0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field));
return getIntInner(field, obj);
}
static final double getDouble(Field field, Object obj, Class caller)
throws IllegalAccessException
{
checkAllowGet(field, obj, caller);
Class type = getType(field);
if (type == double.class)
return getDouble0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field));
if (type == float.class)
return getFloat0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field));
if (type == long.class)
return getLong0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field));
return getIntInner(field, obj);
}
static final void set(Field field, Object obj, Object value, Class caller)
throws IllegalAccessException
{
checkAllowWrite(field, obj, caller);
Class type = getType(field);
int mods = getModifiersInternal(field);
if (type == boolean.class)
{
if (!(value instanceof Boolean))
throw new IllegalArgumentException("field type mismatch");
int intValue = ((Boolean) value).booleanValue() ? 1 : 0;
setInt0(fieldObjectOrClass(field, obj), field.slot, mods, TYPECODE_BOOLEAN,
intValue);
}
else if (type == byte.class)
{
if (!(value instanceof Byte))
throw new IllegalArgumentException("field type mismatch");
int intValue = ((Byte) value).intValue();
setInt0(fieldObjectOrClass(field, obj), field.slot, mods, TYPECODE_BYTE,
intValue);
}
else if (type == char.class)
{
if (!(value instanceof Character))
throw new IllegalArgumentException("field type mismatch");
int intValue = ((Character) value).charValue();
setInt0(fieldObjectOrClass(field, obj), field.slot, mods, TYPECODE_CHAR,
intValue);
}
else if (type == short.class)
{
int intValue;
if (value instanceof Short)
intValue = ((Short) value).intValue();
else if (value instanceof Byte)
intValue = ((Byte) value).intValue();
else throw new IllegalArgumentException("field type mismatch");
setInt0(fieldObjectOrClass(field, obj), field.slot, mods,
TYPECODE_SHORT, intValue);
}
else if (type == int.class)
{
int intValue = unwrapIntValue(value);
setInt0(fieldObjectOrClass(field, obj), field.slot, mods, TYPECODE_INT,
intValue);
}
else if (type == long.class)
{
long longValue;
if (value instanceof Long)
longValue = ((Long) value).longValue();
else longValue = unwrapIntValue(value);
setLong0(fieldObjectOrClass(field, obj), longValue, field.slot, mods);
}
else if (type == float.class)
setFloat0(fieldObjectOrClass(field, obj), value instanceof Float ||
value instanceof Long ? ((Number) value).floatValue() :
unwrapIntValue(value), field.slot, mods);
else if (type == double.class)
setDouble0(fieldObjectOrClass(field, obj),
value instanceof Double || value instanceof Float ||
value instanceof Long ? ((Number) value).doubleValue() :
unwrapIntValue(value), field.slot, mods);
else
{
if (value != null && !type.isInstance(value))
throw new IllegalArgumentException(
"field reference type mismatch");
set0(fieldObjectOrClass(field, obj), value, field.slot, mods);
}
}
static final void setBoolean(Field field, Object obj, boolean value,
Class caller)
throws IllegalAccessException
{
checkAllowWrite(field, obj, caller);
if (getType(field) != boolean.class)
throw new IllegalArgumentException("field type mismatch");
setInt0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field), TYPECODE_BOOLEAN, value ? 1 : 0);
}
static final void setByte(Field field, Object obj, byte value, Class caller)
throws IllegalAccessException
{
checkAllowWrite(field, obj, caller);
Class type = getType(field);
if (type == byte.class)
setInt0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field), TYPECODE_BYTE, value);
else if (type == short.class)
setInt0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field), TYPECODE_SHORT, value);
else setIntInner(field, obj, value);
}
static final void setChar(Field field, Object obj, char value, Class caller)
throws IllegalAccessException
{
checkAllowWrite(field, obj, caller);
if (getType(field) == char.class)
setInt0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field), TYPECODE_CHAR, value);
else setIntInner(field, obj, value);
}
static final void setShort(Field field, Object obj, short value,
Class caller)
throws IllegalAccessException
{
checkAllowWrite(field, obj, caller);
if (getType(field) == short.class)
setInt0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field), TYPECODE_SHORT, value);
else setIntInner(field, obj, value);
}
static final void setInt(Field field, Object obj, int value, Class caller)
throws IllegalAccessException
{
checkAllowWrite(field, obj, caller);
setIntInner(field, obj, value);
}
static final void setLong(Field field, Object obj, long value, Class caller)
throws IllegalAccessException
{
checkAllowWrite(field, obj, caller);
Class type = getType(field);
int mods = getModifiersInternal(field);
if (type == long.class)
setLong0(fieldObjectOrClass(field, obj), value, field.slot, mods);
else if (type == float.class)
setFloat0(fieldObjectOrClass(field, obj), value, field.slot, mods);
else
{
if (type != double.class)
throw new IllegalArgumentException("field type mismatch");
setDouble0(fieldObjectOrClass(field, obj), value, field.slot, mods);
}
}
static final void setFloat(Field field, Object obj, float value,
Class caller)
throws IllegalAccessException
{
checkAllowWrite(field, obj, caller);
Class type = getType(field);
int mods = getModifiersInternal(field);
if (type == float.class)
setFloat0(fieldObjectOrClass(field, obj), value, field.slot, mods);
else
{
if (type != double.class)
throw new IllegalArgumentException("field type mismatch");
setDouble0(fieldObjectOrClass(field, obj), value, field.slot, mods);
}
}
static final void setDouble(Field field, Object obj, double value,
Class caller)
throws IllegalAccessException
{
checkAllowWrite(field, obj, caller);
if (getType(field) != double.class)
throw new IllegalArgumentException("field type mismatch");
setDouble0(fieldObjectOrClass(field, obj), value, field.slot,
getModifiersInternal(field));
}
static final Field createNonFinalAccessible(Field field)
{
field = new Field(field.getDeclaringClass(), field.getName(), field.slot,
getType(field), getModifiersInternal(field) & ~Modifier.FINAL,
getSignature(field));
field.setAccessible(true);
return field;
}
static final long objectFieldOffset(Field field)
{
Class aclass = null;
if ((getModifiersInternal(field) & Modifier.STATIC) != 0)
{
aclass = field.getDeclaringClass();
VMAccessorJavaLang.initializeVMClass(aclass);
}
return objectFieldOffset0(aclass, field.slot);
}
static final Field[] getDeclaredFields(Class klass, boolean publicOnly)
{
String[] names;
int count;
if (klass.isPrimitive() || klass.isArray() ||
(names = getFieldsName0(klass)) == null || (count = names.length) == 0)
return new Field[0];
short[] modifiers = getFieldsModifiers0(klass);
int mods;
int cnt = count;
if (modifiers == null && klass.isInterface())
{
publicOnly = false;
mods = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL;
}
else
{
mods = 0;
if (publicOnly)
{
cnt = 0;
if (modifiers != null)
for (int i = 0; i < count; i++)
if ((modifiers[i] & Modifier.PUBLIC) != 0)
cnt++;
}
}
Field[] fields = new Field[cnt];
if (cnt > 0)
{
int[] slots = getFieldsSlot0(klass);
Class[] types = getFieldsType0(klass);
byte[] dims = getFieldsDims0(klass);
String[] signatures = getFieldsSignature0(klass);
cnt = 0;
for (int i = 0; i < count; i++)
if (!publicOnly || (modifiers[i] & Modifier.PUBLIC) != 0)
fields[cnt++] = new Field(klass, names[i], slots != null ? slots[i] : i,
makeArrayClass(types, dims, i),
modifiers != null ? modifiers[i] & 0xffff : mods,
signatures != null ? signatures[i] : null);
}
return fields;
}
static final Field getDeclaredField(Class klass, String fieldName)
{ /* used by VM classes only */
String[] names;
if (!klass.isPrimitive() && !klass.isArray() &&
(names = getFieldsName0(klass)) != null)
{
short[] modifiers;
int[] slots;
String[] signatures;
int count = names.length;
for (int i = 0; i < count; i++)
if (fieldName.equals(names[i]))
return new Field(klass, fieldName,
(slots = getFieldsSlot0(klass)) != null ? slots[i] : i,
makeArrayClass(getFieldsType0(klass), getFieldsDims0(klass), i),
(modifiers = getFieldsModifiers0(klass)) != null ?
modifiers[i] & 0xffff : klass.isInterface() ?
Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL : 0,
(signatures = getFieldsSignature0(klass)) != null ?
signatures[i] : null);
}
return null;
}
static final Class getStaticFieldClass0X(Object fieldObj)
{ /* called from native code */
Field field = (Field) fieldObj;
return (getModifiersInternal(field) & Modifier.STATIC) != 0 ?
field.getDeclaringClass() : null;
}
static final int getSlotOfField0X(Object fieldObj)
throws ClassCastException
{ /* called from native code */
Field field = (Field) fieldObj;
VMAccessorJavaLang.initializeVMClass(field.getDeclaringClass());
return field.slot;
}
static final Object getFieldByName0X(Class klass, String name,
String typeSig, int isStatic)
{ /* called from native code */
Class type = null;
return !klass.isPrimitive() && !klass.isArray() && (typeSig == null ||
(type = VMAccessorJavaLang.classForSigVMClass(typeSig,
klass)) != null) ? getFieldByNameInner(klass, name, type,
isStatic != 0) : null;
}
static final Object getFieldBySlot0X(Class klass, long slot)
{ /* called from native code */
String[] names;
int intSlot = (int) slot;
int count;
if (intSlot >= 0 && !klass.isPrimitive() && !klass.isArray() &&
(long) intSlot == slot && (names = getFieldsName0(klass)) != null &&
(count = names.length) != 0)
{
int[] slots = getFieldsSlot0(klass);
for (int i = 0; i < count; i++)
if ((slots != null ? slots[i] : i) == intSlot)
{
Class[] types = getFieldsType0(klass);
byte[] dims = getFieldsDims0(klass);
short[] modifiers = getFieldsModifiers0(klass);
String[] signatures = getFieldsSignature0(klass);
return new Field(klass, names[i], intSlot, makeArrayClass(types,
dims, i), modifiers != null ? modifiers[i] & 0xffff :
klass.isInterface() ? Modifier.PUBLIC | Modifier.STATIC |
Modifier.FINAL : 0, signatures != null ? signatures[i] : null);
}
}
return null;
}
private static void checkAllowGet(Field field, Object obj, Class caller)
throws IllegalAccessException
{
int modifiers = getModifiersInternal(field);
Class declaringClass = field.getDeclaringClass();
if ((modifiers & Modifier.STATIC) == 0)
{
if (obj == null)
throw new NullPointerException();
if (!declaringClass.isInstance(obj))
throw new IllegalArgumentException(
"not an instance of a field declaring class: " +
declaringClass.getName());
}
if ((modifiers & Modifier.PUBLIC) == 0 && caller != declaringClass &&
caller != null && ((modifiers & Modifier.PRIVATE) != 0 ||
(((modifiers & Modifier.PROTECTED) == 0 ||
!declaringClass.isAssignableFrom(caller)) &&
!packageNameOf(declaringClass).equals(packageNameOf(caller)))))
throw new IllegalAccessException("field not accessible: " +
declaringClass.getName() + "." + field.getName());
}
private static void checkAllowWrite(Field field, Object obj, Class caller)
throws IllegalAccessException
{
checkAllowGet(field, obj, caller);
if ((getModifiersInternal(field) & Modifier.FINAL) != 0 &&
!field.isAccessible())
throw new IllegalAccessException("cannot set final field: " +
field.getDeclaringClass().getName() + "." + field.getName());
}
private static Object fieldObjectOrClass(Field field, Object obj)
{
if ((getModifiersInternal(field) & Modifier.STATIC) == 0)
return obj;
Class declaringClass = field.getDeclaringClass();
VMAccessorJavaLang.initializeVMClass(declaringClass);
return declaringClass;
}
private static int getIntInner(Field field, Object obj)
{
Class type = getType(field);
int typecode = TYPECODE_INT;
if (type != int.class)
{
if (type == short.class)
typecode = TYPECODE_SHORT;
else if (type == char.class)
typecode = TYPECODE_CHAR;
else if (type == byte.class)
typecode = TYPECODE_BYTE;
else throw new IllegalArgumentException("field type mismatch");
}
return getInt0(fieldObjectOrClass(field, obj), field.slot,
getModifiersInternal(field), typecode);
}
private static void setIntInner(Field field, Object obj, int value)
{
Class type = getType(field);
int mods = getModifiersInternal(field);
if (type == int.class)
setInt0(fieldObjectOrClass(field, obj), field.slot, mods, TYPECODE_INT,
value);
else if (type == long.class)
setLong0(fieldObjectOrClass(field, obj), value, field.slot, mods);
else if (type == float.class)
setFloat0(fieldObjectOrClass(field, obj), value, field.slot, mods);
else
{
if (type != double.class)
throw new IllegalArgumentException("field type mismatch");
setDouble0(fieldObjectOrClass(field, obj), value, field.slot, mods);
}
}
private static String packageNameOf(Class aclass)
{
String name = aclass.getName();
int lastInd = name.lastIndexOf('.');
return lastInd > 0 ? name.substring(0, lastInd) : "";
}
private static int unwrapIntValue(Object value)
{
int intValue;
if (value instanceof Integer)
intValue = ((Integer) value).intValue();
else if (value instanceof Short)
intValue = ((Short) value).intValue();
else if (value instanceof Character)
intValue = ((Character) value).charValue();
else if (value instanceof Byte)
intValue = ((Byte) value).intValue();
else throw new IllegalArgumentException("field type mismatch");
return intValue;
}
private static Field getFieldByNameInner(Class klass, String name,
Class type, boolean isStatic)
{
Class aclass = klass;
Field field = null;
do
{
String[] names = getFieldsName0(aclass);
int count;
if (names != null && (count = names.length) != 0)
{
Class[] types = getFieldsType0(aclass);
byte[] dims = getFieldsDims0(aclass);
short[] modifiers = getFieldsModifiers0(aclass);
int mods = aclass.isInterface() ?
Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL : 0;
for (int i = 0; i < count; i++)
if (name.equals(names[i]))
{
if (modifiers != null)
mods = modifiers[i] & 0xffff;
if (((mods & Modifier.STATIC) != 0) == isStatic)
{
Class fieldType = makeArrayClass(types, dims, i);
if (type == null || type == fieldType)
{
int[] slots = getFieldsSlot0(aclass);
String[] signatures = getFieldsSignature0(klass);
Field f = new Field(aclass, names[i], slots != null ? slots[i] : i,
fieldType, mods, signatures != null ? signatures[i] :
null);
if (aclass == klass ||
(mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0 ||
((mods & Modifier.PRIVATE) == 0 &&
packageNameOf(aclass).equals(packageNameOf(klass))))
return f;
if (field == null)
field = f;
break;
}
}
}
}
if (isStatic)
{
Class[] interfaces = VMAccessorJavaLang.getInterfacesInnerVMClass(aclass);
int len = interfaces.length;
for (int i = 0; i < len; i++)
{
Field f = getFieldByNameInner(interfaces[i], name, type, true);
if (f != null)
return f;
}
}
aclass = aclass.getSuperclass();
} while (aclass != null);
return field;
}
private static Class makeArrayClass(Class[] types, byte[] dims, int i)
{
return dims != null ? VMAccessorJavaLang.arrayClassOfVMClass(types[i],
dims[i] & 0xff) : types[i];
}
private static native String[] getFieldsName0(
Class klass); /* JVM-core */ /* const data */
private static native int[] getFieldsSlot0(
Class klass); /* JVM-core */ /* const data */
private static native Class[] getFieldsType0(
Class klass); /* JVM-core */ /* const data */
private static native byte[] getFieldsDims0(
Class klass); /* JVM-core */ /* const data */
private static native short[] getFieldsModifiers0(
Class klass); /* JVM-core */ /* const data */
private static native String[] getFieldsSignature0(
Class klass); /* JVM-core */ /* const data */
private static native int getInt0(Object objOrClass, int slot, int mods,
int typecode); /* JVM-core */
private static native int setInt0(Object objOrClass, int slot, int mods,
int typecode, int value); /* JVM-core */
private static native long getLong0(Object objOrClass,
int slot, int mods); /* JVM-core */
private static native int setLong0(Object objOrClass, long value,
int slot, int mods); /* JVM-core */
private static native float getFloat0(Object objOrClass,
int slot, int mods); /* JVM-core */
private static native int setFloat0(Object objOrClass, float value,
int slot, int mods); /* JVM-core */
private static native double getDouble0(Object objOrClass,
int slot, int mods); /* JVM-core */
private static native int setDouble0(Object objOrClass, double value,
int slot, int mods); /* JVM-core */
private static native Object get0(Object objOrClass,
int slot, int mods); /* JVM-core */
private static native int set0(Object objOrClass, Object value,
int slot, int mods); /* JVM-core */
private static native long objectFieldOffset0(Class aclass,
int slot); /* JVM-core */
}