# HG changeset patch # User Andreas Woess # Date 1421884889 -3600 # Node ID c46e268fd09148a2d9b1edbb194b593c6fbe0c00 # Parent 6ba170cb6f5386cea135fd198e8a66a5f1575f0e Truffle: add (and switch to) safe node field access implementation using reflection diff -r 6ba170cb6f53 -r c46e268fd091 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Thu Jan 22 00:37:29 2015 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Thu Jan 22 01:01:29 2015 +0100 @@ -43,6 +43,7 @@ * Utility class that manages the special access methods for node instances. */ public final class NodeUtil { + private static final boolean USE_UNSAFE = Boolean.getBoolean("truffle.unsafe"); /** * Interface that allows the customization of field offsets used for {@link Unsafe} field @@ -88,14 +89,14 @@ /** * Information about a field in a {@link Node} class. */ - public static final class NodeField { + public abstract static class NodeField { private final NodeFieldKind kind; - private final Class type; private final String name; - private long offset; + protected final Class type; + protected final long offset; - private NodeField(NodeFieldKind kind, Field field) { + protected NodeField(NodeFieldKind kind, Field field) { this.kind = kind; this.type = field.getType(); this.name = field.getName(); @@ -103,7 +104,11 @@ } protected static NodeField create(NodeFieldKind kind, Field field) { - return new NodeField(kind, field); + if (USE_UNSAFE) { + return new UnsafeNodeField(kind, field); + } else { + return new ReflectionNodeField(kind, field); + } } public NodeFieldKind getKind() { @@ -122,16 +127,45 @@ return offset; } - public void putObject(Object receiver, Object value) { + public abstract void putObject(Node receiver, Object value); + + public abstract Object getObject(Node receiver); + + public abstract Object loadValue(Node node); + + @Override + public int hashCode() { + return kind.hashCode() | type.hashCode() | name.hashCode() | ((Long) offset).hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NodeField) { + NodeField other = (NodeField) obj; + return offset == other.offset && name.equals(other.name) && type.equals(other.type) && kind.equals(other.kind); + } + return false; + } + } + + private static final class UnsafeNodeField extends NodeField { + protected UnsafeNodeField(NodeFieldKind kind, Field field) { + super(kind, field); + } + + @Override + public void putObject(Node receiver, Object value) { assert !type.isPrimitive() && value == null || type.isInstance(value); unsafe.putObject(receiver, offset, value); } - public Object getObject(Object receiver) { + @Override + public Object getObject(Node receiver) { assert !type.isPrimitive(); return unsafe.getObject(receiver, offset); } + @Override public Object loadValue(Node node) { if (type == boolean.class) { return unsafe.getBoolean(node, offset); @@ -153,19 +187,62 @@ return unsafe.getObject(node, offset); } } + } + + private static final class ReflectionNodeField extends NodeField { + private final Field field; + + protected ReflectionNodeField(NodeFieldKind kind, Field field) { + super(kind, field); + this.field = field; + field.setAccessible(true); + } @Override - public int hashCode() { - return kind.hashCode() | type.hashCode() | name.hashCode() | ((Long) offset).hashCode(); + public void putObject(Node receiver, Object value) { + assert !type.isPrimitive() && value == null || type.isInstance(value); + try { + field.set(receiver, value); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } } @Override - public boolean equals(Object obj) { - if (obj instanceof NodeField) { - NodeField other = (NodeField) obj; - return offset == other.offset && name.equals(other.name) && type.equals(other.type) && kind.equals(other.kind); + public Object getObject(Node receiver) { + assert !type.isPrimitive(); + try { + return field.get(receiver); + } catch (IllegalAccessException e) { + throw new AssertionError(e); } - return false; + } + + @Override + public Object loadValue(Node node) { + try { + if (type == boolean.class) { + return field.getBoolean(node); + } else if (type == byte.class) { + return field.getByte(node); + } else if (type == short.class) { + return field.getShort(node); + } else if (type == char.class) { + return field.getChar(node); + } else if (type == int.class) { + return field.getInt(node); + } else if (type == long.class) { + return field.getLong(node); + } else if (type == float.class) { + return field.getFloat(node); + } else if (type == double.class) { + return field.getDouble(node); + } else { + return field.get(node); + } + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } } }