comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeFieldAccessor.java @ 20129:5b7db8941fd7

Truffle: make NodeClass and NodeField a top-level class.
author Christian Humer <christian.humer@gmail.com>
date Thu, 02 Apr 2015 01:22:41 +0200
parents
children 8dc73c226c63
comparison
equal deleted inserted replaced
20128:7ad60a16bbb0 20129:5b7db8941fd7
1 /*
2 * Copyright (c) 2012, 2015, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package com.oracle.truffle.api.nodes;
26
27 import java.lang.reflect.*;
28
29 import sun.misc.*;
30
31 import com.oracle.truffle.api.nodes.Node.Child;
32 import com.oracle.truffle.api.nodes.Node.Children;
33 import com.oracle.truffle.api.nodes.NodeUtil.FieldOffsetProvider;
34
35 /**
36 * Information about a field in a {@link Node} class.
37 */
38 public abstract class NodeFieldAccessor {
39
40 public static enum NodeFieldKind {
41 /** The single {@link Node#getParent() parent} field. */
42 PARENT,
43 /** A field annotated with {@link Child}. */
44 CHILD,
45 /** A field annotated with {@link Children}. */
46 CHILDREN,
47 /** A normal non-child data field of the node. */
48 DATA
49 }
50
51 private static final boolean USE_UNSAFE = Boolean.getBoolean("truffle.unsafe");
52
53 private final NodeFieldKind kind;
54 private final String name;
55 protected final Class<?> type;
56 protected final long offset;
57
58 protected NodeFieldAccessor(NodeFieldKind kind, Field field) {
59 this.kind = kind;
60 this.type = field.getType();
61 this.name = field.getName();
62 this.offset = unsafeFieldOffsetProvider.objectFieldOffset(field);
63 }
64
65 protected static NodeFieldAccessor create(NodeFieldKind kind, Field field) {
66 if (USE_UNSAFE) {
67 return new UnsafeNodeField(kind, field);
68 } else {
69 return new ReflectionNodeField(kind, field);
70 }
71 }
72
73 public NodeFieldKind getKind() {
74 return kind;
75 }
76
77 public Class<?> getType() {
78 return type;
79 }
80
81 public String getName() {
82 return name;
83 }
84
85 public long getOffset() {
86 return offset;
87 }
88
89 public abstract void putObject(Node receiver, Object value);
90
91 public abstract Object getObject(Node receiver);
92
93 public abstract Object loadValue(Node node);
94
95 @Override
96 public int hashCode() {
97 return kind.hashCode() | type.hashCode() | name.hashCode() | ((Long) offset).hashCode();
98 }
99
100 @Override
101 public boolean equals(Object obj) {
102 if (obj instanceof NodeFieldAccessor) {
103 NodeFieldAccessor other = (NodeFieldAccessor) obj;
104 return offset == other.offset && name.equals(other.name) && type.equals(other.type) && kind.equals(other.kind);
105 }
106 return false;
107 }
108
109 private static final Unsafe unsafe = getUnsafe();
110
111 private static Unsafe getUnsafe() {
112 try {
113 return Unsafe.getUnsafe();
114 } catch (SecurityException e) {
115 }
116 try {
117 Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
118 theUnsafeInstance.setAccessible(true);
119 return (Unsafe) theUnsafeInstance.get(Unsafe.class);
120 } catch (Exception e) {
121 throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
122 }
123 }
124
125 private static final FieldOffsetProvider unsafeFieldOffsetProvider = new FieldOffsetProvider() {
126
127 @Override
128 public long objectFieldOffset(Field field) {
129 return unsafe.objectFieldOffset(field);
130 }
131
132 @Override
133 public int getTypeSize(Class<?> clazz) {
134 if (!clazz.isPrimitive()) {
135 return Unsafe.ARRAY_OBJECT_INDEX_SCALE;
136 } else if (clazz == int.class) {
137 return Unsafe.ARRAY_INT_INDEX_SCALE;
138 } else {
139 throw new UnsupportedOperationException("unsupported field type: " + clazz);
140 }
141 }
142 };
143
144 private static final class UnsafeNodeField extends NodeFieldAccessor {
145
146 protected UnsafeNodeField(NodeFieldKind kind, Field field) {
147 super(kind, field);
148 }
149
150 @Override
151 public void putObject(Node receiver, Object value) {
152 if (!type.isPrimitive() && value == null || type.isInstance(value)) {
153 unsafe.putObject(receiver, offset, value);
154 } else {
155 throw new IllegalArgumentException();
156 }
157 }
158
159 @Override
160 public Object getObject(Node receiver) {
161 if (!type.isPrimitive()) {
162 return unsafe.getObject(receiver, offset);
163 } else {
164 throw new IllegalArgumentException();
165 }
166 }
167
168 @Override
169 public Object loadValue(Node node) {
170 if (type == boolean.class) {
171 return unsafe.getBoolean(node, offset);
172 } else if (type == byte.class) {
173 return unsafe.getByte(node, offset);
174 } else if (type == short.class) {
175 return unsafe.getShort(node, offset);
176 } else if (type == char.class) {
177 return unsafe.getChar(node, offset);
178 } else if (type == int.class) {
179 return unsafe.getInt(node, offset);
180 } else if (type == long.class) {
181 return unsafe.getLong(node, offset);
182 } else if (type == float.class) {
183 return unsafe.getFloat(node, offset);
184 } else if (type == double.class) {
185 return unsafe.getDouble(node, offset);
186 } else {
187 return unsafe.getObject(node, offset);
188 }
189 }
190 }
191
192 private static final class ReflectionNodeField extends NodeFieldAccessor {
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 }
200
201 @Override
202 public void putObject(Node receiver, Object value) {
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 }
209 }
210
211 @Override
212 public Object getObject(Node receiver) {
213 assert !type.isPrimitive();
214 try {
215 return field.get(receiver);
216 } catch (IllegalAccessException e) {
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 }
246 }
247 }
248
249 }