1 /*
   2  * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.core.common;
  26 
  27 import static org.graalvm.compiler.core.common.UnsafeAccess.UNSAFE;
  28 
  29 import java.util.ArrayList;
  30 import java.util.Collections;
  31 
  32 import org.graalvm.compiler.debug.GraalError;
  33 
  34 import sun.misc.Unsafe;
  35 
  36 /**
  37  * Describes fields in a class, primarily for access via {@link Unsafe}.
  38  */
  39 public class Fields {
  40 
  41     /**
  42      * Offsets used with {@link Unsafe} to access the fields.
  43      */
  44     protected final long[] offsets;
  45 
  46     /**
  47      * The names of the fields.
  48      */
  49     private final String[] names;
  50 
  51     /**
  52      * The types of the fields.
  53      */
  54     private final Class<?>[] types;
  55 
  56     private final Class<?>[] declaringClasses;
  57 
  58     public static Fields forClass(Class<?> clazz, Class<?> endClazz, boolean includeTransient, FieldsScanner.CalcOffset calcOffset) {
  59         FieldsScanner scanner = new FieldsScanner(calcOffset == null ? new FieldsScanner.DefaultCalcOffset() : calcOffset);
  60         scanner.scan(clazz, endClazz, includeTransient);
  61         return new Fields(scanner.data);
  62     }
  63 
  64     public Fields(ArrayList<? extends FieldsScanner.FieldInfo> fields) {
  65         Collections.sort(fields);
  66         this.offsets = new long[fields.size()];
  67         this.names = new String[offsets.length];
  68         this.types = new Class<?>[offsets.length];
  69         this.declaringClasses = new Class<?>[offsets.length];
  70         int index = 0;
  71         for (FieldsScanner.FieldInfo f : fields) {
  72             offsets[index] = f.offset;
  73             names[index] = f.name;
  74             types[index] = f.type;
  75             declaringClasses[index] = f.declaringClass;
  76             index++;
  77         }
  78     }
  79 
  80     /**
  81      * Gets the number of fields represented by this object.
  82      */
  83     public int getCount() {
  84         return offsets.length;
  85     }
  86 
  87     public static void translateInto(Fields fields, ArrayList<FieldsScanner.FieldInfo> infos) {
  88         for (int index = 0; index < fields.getCount(); index++) {
  89             infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index], fields.declaringClasses[index]));
  90         }
  91     }
  92 
  93     /**
  94      * Function enabling an object field value to be replaced with another value when being copied
  95      * within {@link Fields#copy(Object, Object, ObjectTransformer)}.
  96      */
  97     @FunctionalInterface
  98     public interface ObjectTransformer {
  99         Object apply(int index, Object from);
 100     }
 101 
 102     /**
 103      * Copies fields from {@code from} to {@code to}, both of which must be of the same type.
 104      *
 105      * @param from the object from which the fields should be copied
 106      * @param to the object to which the fields should be copied
 107      */
 108     public void copy(Object from, Object to) {
 109         copy(from, to, null);
 110     }
 111 
 112     /**
 113      * Copies fields from {@code from} to {@code to}, both of which must be of the same type.
 114      *
 115      * @param from the object from which the fields should be copied
 116      * @param to the object to which the fields should be copied
 117      * @param trans function to applied to object field values as they are copied. If {@code null},
 118      *            the value is copied unchanged.
 119      */
 120     public void copy(Object from, Object to, ObjectTransformer trans) {
 121         assert from.getClass() == to.getClass();
 122         for (int index = 0; index < offsets.length; index++) {
 123             long offset = offsets[index];
 124             Class<?> type = types[index];
 125             if (type.isPrimitive()) {
 126                 if (type == Integer.TYPE) {
 127                     UNSAFE.putInt(to, offset, UNSAFE.getInt(from, offset));
 128                 } else if (type == Long.TYPE) {
 129                     UNSAFE.putLong(to, offset, UNSAFE.getLong(from, offset));
 130                 } else if (type == Boolean.TYPE) {
 131                     UNSAFE.putBoolean(to, offset, UNSAFE.getBoolean(from, offset));
 132                 } else if (type == Float.TYPE) {
 133                     UNSAFE.putFloat(to, offset, UNSAFE.getFloat(from, offset));
 134                 } else if (type == Double.TYPE) {
 135                     UNSAFE.putDouble(to, offset, UNSAFE.getDouble(from, offset));
 136                 } else if (type == Short.TYPE) {
 137                     UNSAFE.putShort(to, offset, UNSAFE.getShort(from, offset));
 138                 } else if (type == Character.TYPE) {
 139                     UNSAFE.putChar(to, offset, UNSAFE.getChar(from, offset));
 140                 } else if (type == Byte.TYPE) {
 141                     UNSAFE.putByte(to, offset, UNSAFE.getByte(from, offset));
 142                 } else {
 143                     assert false : "unhandled property type: " + type;
 144                 }
 145             } else {
 146                 Object obj = UNSAFE.getObject(from, offset);
 147                 UNSAFE.putObject(to, offset, trans == null ? obj : trans.apply(index, obj));
 148             }
 149         }
 150     }
 151 
 152     /**
 153      * Gets the value of a field for a given object.
 154      *
 155      * @param object the object whose field is to be read
 156      * @param index the index of the field (between 0 and {@link #getCount()})
 157      * @return the value of the specified field which will be boxed if the field type is primitive
 158      */
 159     public Object get(Object object, int index) {
 160         long offset = offsets[index];
 161         Class<?> type = types[index];
 162         Object value = null;
 163         if (type.isPrimitive()) {
 164             if (type == Integer.TYPE) {
 165                 value = UNSAFE.getInt(object, offset);
 166             } else if (type == Long.TYPE) {
 167                 value = UNSAFE.getLong(object, offset);
 168             } else if (type == Boolean.TYPE) {
 169                 value = UNSAFE.getBoolean(object, offset);
 170             } else if (type == Float.TYPE) {
 171                 value = UNSAFE.getFloat(object, offset);
 172             } else if (type == Double.TYPE) {
 173                 value = UNSAFE.getDouble(object, offset);
 174             } else if (type == Short.TYPE) {
 175                 value = UNSAFE.getShort(object, offset);
 176             } else if (type == Character.TYPE) {
 177                 value = UNSAFE.getChar(object, offset);
 178             } else if (type == Byte.TYPE) {
 179                 value = UNSAFE.getByte(object, offset);
 180             } else {
 181                 assert false : "unhandled property type: " + type;
 182             }
 183         } else {
 184             value = UNSAFE.getObject(object, offset);
 185         }
 186         return value;
 187     }
 188 
 189     /**
 190      * Gets the value of a field for a given object.
 191      *
 192      * @param object the object whose field is to be read
 193      * @param index the index of the field (between 0 and {@link #getCount()})
 194      * @return the value of the specified field which will be boxed if the field type is primitive
 195      */
 196     public long getRawPrimitive(Object object, int index) {
 197         long offset = offsets[index];
 198         Class<?> type = types[index];
 199 
 200         if (type == Integer.TYPE) {
 201             return UNSAFE.getInt(object, offset);
 202         } else if (type == Long.TYPE) {
 203             return UNSAFE.getLong(object, offset);
 204         } else if (type == Boolean.TYPE) {
 205             return UNSAFE.getBoolean(object, offset) ? 1 : 0;
 206         } else if (type == Float.TYPE) {
 207             return Float.floatToRawIntBits(UNSAFE.getFloat(object, offset));
 208         } else if (type == Double.TYPE) {
 209             return Double.doubleToRawLongBits(UNSAFE.getDouble(object, offset));
 210         } else if (type == Short.TYPE) {
 211             return UNSAFE.getShort(object, offset);
 212         } else if (type == Character.TYPE) {
 213             return UNSAFE.getChar(object, offset);
 214         } else if (type == Byte.TYPE) {
 215             return UNSAFE.getByte(object, offset);
 216         } else {
 217             throw GraalError.shouldNotReachHere();
 218         }
 219     }
 220 
 221     /**
 222      * Determines if a field in the domain of this object is the same as the field denoted by the
 223      * same index in another {@link Fields} object.
 224      */
 225     public boolean isSame(Fields other, int index) {
 226         return other.offsets[index] == offsets[index];
 227     }
 228 
 229     public long[] getOffsets() {
 230         return offsets;
 231     }
 232 
 233     /**
 234      * Gets the name of a field.
 235      *
 236      * @param index index of a field
 237      */
 238     public String getName(int index) {
 239         return names[index];
 240     }
 241 
 242     /**
 243      * Gets the type of a field.
 244      *
 245      * @param index index of a field
 246      */
 247     public Class<?> getType(int index) {
 248         return types[index];
 249     }
 250 
 251     public Class<?> getDeclaringClass(int index) {
 252         return declaringClasses[index];
 253     }
 254 
 255     /**
 256      * Checks that a given field is assignable from a given value.
 257      *
 258      * @param index the index of the field to check
 259      * @param value a value that will be assigned to the field
 260      */
 261     private boolean checkAssignableFrom(Object object, int index, Object value) {
 262         assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("Field %s.%s of type %s is not assignable from %s", object.getClass().getSimpleName(),
 263                         getName(index), getType(index).getSimpleName(), value.getClass().getSimpleName());
 264         return true;
 265     }
 266 
 267     public void set(Object object, int index, Object value) {
 268         long offset = offsets[index];
 269         Class<?> type = types[index];
 270         if (type.isPrimitive()) {
 271             if (type == Integer.TYPE) {
 272                 UNSAFE.putInt(object, offset, (Integer) value);
 273             } else if (type == Long.TYPE) {
 274                 UNSAFE.putLong(object, offset, (Long) value);
 275             } else if (type == Boolean.TYPE) {
 276                 UNSAFE.putBoolean(object, offset, (Boolean) value);
 277             } else if (type == Float.TYPE) {
 278                 UNSAFE.putFloat(object, offset, (Float) value);
 279             } else if (type == Double.TYPE) {
 280                 UNSAFE.putDouble(object, offset, (Double) value);
 281             } else if (type == Short.TYPE) {
 282                 UNSAFE.putShort(object, offset, (Short) value);
 283             } else if (type == Character.TYPE) {
 284                 UNSAFE.putChar(object, offset, (Character) value);
 285             } else if (type == Byte.TYPE) {
 286                 UNSAFE.putByte(object, offset, (Byte) value);
 287             } else {
 288                 assert false : "unhandled property type: " + type;
 289             }
 290         } else {
 291             assert checkAssignableFrom(object, index, value);
 292             UNSAFE.putObject(object, offset, value);
 293         }
 294     }
 295 
 296     public void setRawPrimitive(Object object, int index, long value) {
 297         long offset = offsets[index];
 298         Class<?> type = types[index];
 299         if (type == Integer.TYPE) {
 300             UNSAFE.putInt(object, offset, (int) value);
 301         } else if (type == Long.TYPE) {
 302             UNSAFE.putLong(object, offset, value);
 303         } else if (type == Boolean.TYPE) {
 304             UNSAFE.putBoolean(object, offset, value != 0);
 305         } else if (type == Float.TYPE) {
 306             UNSAFE.putFloat(object, offset, Float.intBitsToFloat((int) value));
 307         } else if (type == Double.TYPE) {
 308             UNSAFE.putDouble(object, offset, Double.longBitsToDouble(value));
 309         } else if (type == Short.TYPE) {
 310             UNSAFE.putShort(object, offset, (short) value);
 311         } else if (type == Character.TYPE) {
 312             UNSAFE.putChar(object, offset, (char) value);
 313         } else if (type == Byte.TYPE) {
 314             UNSAFE.putByte(object, offset, (byte) value);
 315         } else {
 316             throw GraalError.shouldNotReachHere();
 317         }
 318     }
 319 
 320     @Override
 321     public String toString() {
 322         StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
 323         appendFields(sb);
 324         return sb.append(']').toString();
 325     }
 326 
 327     public void appendFields(StringBuilder sb) {
 328         for (int i = 0; i < offsets.length; i++) {
 329             sb.append(i == 0 ? "" : ", ").append(getDeclaringClass(i).getSimpleName()).append('.').append(getName(i)).append('@').append(offsets[i]);
 330         }
 331     }
 332 
 333     public boolean getBoolean(Object n, int i) {
 334         assert types[i] == boolean.class;
 335         return UNSAFE.getBoolean(n, offsets[i]);
 336     }
 337 
 338     public byte getByte(Object n, int i) {
 339         assert types[i] == byte.class;
 340         return UNSAFE.getByte(n, offsets[i]);
 341     }
 342 
 343     public short getShort(Object n, int i) {
 344         assert types[i] == short.class;
 345         return UNSAFE.getShort(n, offsets[i]);
 346     }
 347 
 348     public char getChar(Object n, int i) {
 349         assert types[i] == char.class;
 350         return UNSAFE.getChar(n, offsets[i]);
 351     }
 352 
 353     public int getInt(Object n, int i) {
 354         assert types[i] == int.class;
 355         return UNSAFE.getInt(n, offsets[i]);
 356     }
 357 
 358     public long getLong(Object n, int i) {
 359         assert types[i] == long.class;
 360         return UNSAFE.getLong(n, offsets[i]);
 361     }
 362 
 363     public float getFloat(Object n, int i) {
 364         assert types[i] == float.class;
 365         return UNSAFE.getFloat(n, offsets[i]);
 366     }
 367 
 368     public double getDouble(Object n, int i) {
 369         assert types[i] == double.class;
 370         return UNSAFE.getDouble(n, offsets[i]);
 371     }
 372 
 373     public Object getObject(Object object, int i) {
 374         assert !types[i].isPrimitive();
 375         return UNSAFE.getObject(object, offsets[i]);
 376     }
 377 
 378     public void putObject(Object object, int i, Object value) {
 379         assert checkAssignableFrom(object, i, value);
 380         UNSAFE.putObject(object, offsets[i], value);
 381     }
 382 }