comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java @ 18905:c46e268fd091

Truffle: add (and switch to) safe node field access implementation using reflection
author Andreas Woess <andreas.woess@jku.at>
date Thu, 22 Jan 2015 01:01:29 +0100
parents 6ba170cb6f53
children 0f462015296f
comparison
equal deleted inserted replaced
18904:6ba170cb6f53 18905:c46e268fd091
41 41
42 /** 42 /**
43 * Utility class that manages the special access methods for node instances. 43 * Utility class that manages the special access methods for node instances.
44 */ 44 */
45 public final class NodeUtil { 45 public final class NodeUtil {
46 private static final boolean USE_UNSAFE = Boolean.getBoolean("truffle.unsafe");
46 47
47 /** 48 /**
48 * Interface that allows the customization of field offsets used for {@link Unsafe} field 49 * Interface that allows the customization of field offsets used for {@link Unsafe} field
49 * accesses. 50 * accesses.
50 */ 51 */
86 } 87 }
87 88
88 /** 89 /**
89 * Information about a field in a {@link Node} class. 90 * Information about a field in a {@link Node} class.
90 */ 91 */
91 public static final class NodeField { 92 public abstract static class NodeField {
92 93
93 private final NodeFieldKind kind; 94 private final NodeFieldKind kind;
94 private final Class<?> type;
95 private final String name; 95 private final String name;
96 private long offset; 96 protected final Class<?> type;
97 97 protected final long offset;
98 private NodeField(NodeFieldKind kind, Field field) { 98
99 protected NodeField(NodeFieldKind kind, Field field) {
99 this.kind = kind; 100 this.kind = kind;
100 this.type = field.getType(); 101 this.type = field.getType();
101 this.name = field.getName(); 102 this.name = field.getName();
102 this.offset = unsafeFieldOffsetProvider.objectFieldOffset(field); 103 this.offset = unsafeFieldOffsetProvider.objectFieldOffset(field);
103 } 104 }
104 105
105 protected static NodeField create(NodeFieldKind kind, Field field) { 106 protected static NodeField create(NodeFieldKind kind, Field field) {
106 return new NodeField(kind, field); 107 if (USE_UNSAFE) {
108 return new UnsafeNodeField(kind, field);
109 } else {
110 return new ReflectionNodeField(kind, field);
111 }
107 } 112 }
108 113
109 public NodeFieldKind getKind() { 114 public NodeFieldKind getKind() {
110 return kind; 115 return kind;
111 } 116 }
120 125
121 public long getOffset() { 126 public long getOffset() {
122 return offset; 127 return offset;
123 } 128 }
124 129
125 public void putObject(Object receiver, Object value) { 130 public abstract void putObject(Node receiver, Object value);
131
132 public abstract Object getObject(Node receiver);
133
134 public abstract Object loadValue(Node node);
135
136 @Override
137 public int hashCode() {
138 return kind.hashCode() | type.hashCode() | name.hashCode() | ((Long) offset).hashCode();
139 }
140
141 @Override
142 public boolean equals(Object obj) {
143 if (obj instanceof NodeField) {
144 NodeField other = (NodeField) obj;
145 return offset == other.offset && name.equals(other.name) && type.equals(other.type) && kind.equals(other.kind);
146 }
147 return false;
148 }
149 }
150
151 private static final class UnsafeNodeField extends NodeField {
152 protected UnsafeNodeField(NodeFieldKind kind, Field field) {
153 super(kind, field);
154 }
155
156 @Override
157 public void putObject(Node receiver, Object value) {
126 assert !type.isPrimitive() && value == null || type.isInstance(value); 158 assert !type.isPrimitive() && value == null || type.isInstance(value);
127 unsafe.putObject(receiver, offset, value); 159 unsafe.putObject(receiver, offset, value);
128 } 160 }
129 161
130 public Object getObject(Object receiver) { 162 @Override
163 public Object getObject(Node receiver) {
131 assert !type.isPrimitive(); 164 assert !type.isPrimitive();
132 return unsafe.getObject(receiver, offset); 165 return unsafe.getObject(receiver, offset);
133 } 166 }
134 167
168 @Override
135 public Object loadValue(Node node) { 169 public Object loadValue(Node node) {
136 if (type == boolean.class) { 170 if (type == boolean.class) {
137 return unsafe.getBoolean(node, offset); 171 return unsafe.getBoolean(node, offset);
138 } else if (type == byte.class) { 172 } else if (type == byte.class) {
139 return unsafe.getByte(node, offset); 173 return unsafe.getByte(node, offset);
151 return unsafe.getDouble(node, offset); 185 return unsafe.getDouble(node, offset);
152 } else { 186 } else {
153 return unsafe.getObject(node, offset); 187 return unsafe.getObject(node, offset);
154 } 188 }
155 } 189 }
190 }
191
192 private static final class ReflectionNodeField extends NodeField {
193 private final Field field;
194
195 protected ReflectionNodeField(NodeFieldKind kind, Field field) {
196 super(kind, field);
197 this.field = field;
198 field.setAccessible(true);
199 }
156 200
157 @Override 201 @Override
158 public int hashCode() { 202 public void putObject(Node receiver, Object value) {
159 return kind.hashCode() | type.hashCode() | name.hashCode() | ((Long) offset).hashCode(); 203 assert !type.isPrimitive() && value == null || type.isInstance(value);
204 try {
205 field.set(receiver, value);
206 } catch (IllegalAccessException e) {
207 throw new AssertionError(e);
208 }
160 } 209 }
161 210
162 @Override 211 @Override
163 public boolean equals(Object obj) { 212 public Object getObject(Node receiver) {
164 if (obj instanceof NodeField) { 213 assert !type.isPrimitive();
165 NodeField other = (NodeField) obj; 214 try {
166 return offset == other.offset && name.equals(other.name) && type.equals(other.type) && kind.equals(other.kind); 215 return field.get(receiver);
167 } 216 } catch (IllegalAccessException e) {
168 return false; 217 throw new AssertionError(e);
218 }
219 }
220
221 @Override
222 public Object loadValue(Node node) {
223 try {
224 if (type == boolean.class) {
225 return field.getBoolean(node);
226 } else if (type == byte.class) {
227 return field.getByte(node);
228 } else if (type == short.class) {
229 return field.getShort(node);
230 } else if (type == char.class) {
231 return field.getChar(node);
232 } else if (type == int.class) {
233 return field.getInt(node);
234 } else if (type == long.class) {
235 return field.getLong(node);
236 } else if (type == float.class) {
237 return field.getFloat(node);
238 } else if (type == double.class) {
239 return field.getDouble(node);
240 } else {
241 return field.get(node);
242 }
243 } catch (IllegalAccessException e) {
244 throw new AssertionError(e);
245 }
169 } 246 }
170 } 247 }
171 248
172 /** 249 /**
173 * Information about a {@link Node} class. A single instance of this class is allocated for 250 * Information about a {@link Node} class. A single instance of this class is allocated for