Mercurial > hg > truffle
comparison truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeClass.java @ 22399:efbc311e9ff2
Turning NodeClass into abstract class to allow its independent implementations.
author | Jaroslav Tulach <jaroslav.tulach@oracle.com> |
---|---|
date | Fri, 20 Nov 2015 10:36:52 +0100 |
parents | 07c98b5a9496 |
children | 5033b980cc68 |
comparison
equal
deleted
inserted
replaced
22398:07c98b5a9496 | 22399:efbc311e9ff2 |
---|---|
22 * or visit www.oracle.com if you need additional information or have any | 22 * or visit www.oracle.com if you need additional information or have any |
23 * questions. | 23 * questions. |
24 */ | 24 */ |
25 package com.oracle.truffle.api.nodes; | 25 package com.oracle.truffle.api.nodes; |
26 | 26 |
27 import java.lang.reflect.Field; | |
28 import java.lang.reflect.Modifier; | |
29 import java.security.AccessController; | 27 import java.security.AccessController; |
30 import java.security.PrivilegedAction; | 28 import java.security.PrivilegedAction; |
31 import java.util.ArrayList; | |
32 import java.util.Iterator; | 29 import java.util.Iterator; |
33 import java.util.List; | |
34 | |
35 import com.oracle.truffle.api.nodes.Node.Child; | |
36 import com.oracle.truffle.api.nodes.Node.Children; | |
37 import com.oracle.truffle.api.nodes.NodeFieldAccessor.NodeFieldKind; | |
38 | 30 |
39 /** | 31 /** |
40 * Information about a {@link Node} class. A single instance of this class is allocated for every | 32 * Information about a {@link Node} class. A single instance of this class is allocated for every |
41 * subclass of {@link Node} that is used. | 33 * subclass of {@link Node} that is used. |
42 */ | 34 */ |
43 public final class NodeClass { | 35 public abstract class NodeClass { |
44 private static final ClassValue<NodeClass> nodeClasses = new ClassValue<NodeClass>() { | 36 private static final ClassValue<NodeClass> nodeClasses = new ClassValue<NodeClass>() { |
45 @SuppressWarnings("unchecked") | 37 @SuppressWarnings("unchecked") |
46 @Override | 38 @Override |
47 protected NodeClass computeValue(final Class<?> clazz) { | 39 protected NodeClass computeValue(final Class<?> clazz) { |
48 assert Node.class.isAssignableFrom(clazz); | 40 assert Node.class.isAssignableFrom(clazz); |
49 return AccessController.doPrivileged(new PrivilegedAction<NodeClass>() { | 41 return AccessController.doPrivileged(new PrivilegedAction<NodeClass>() { |
50 public NodeClass run() { | 42 public NodeClass run() { |
51 return new NodeClass((Class<? extends Node>) clazz); | 43 return new NodeClassImpl((Class<? extends Node>) clazz); |
52 } | 44 } |
53 }); | 45 }); |
54 } | 46 } |
55 }; | 47 }; |
56 | |
57 private static final NodeFieldAccessor[] EMPTY_NODE_FIELD_ARRAY = new NodeFieldAccessor[0]; | |
58 | |
59 // The comprehensive list of all fields. | |
60 private final NodeFieldAccessor[] fields; | |
61 // Separate arrays for the frequently accessed fields. | |
62 private final NodeFieldAccessor parentField; | |
63 private final NodeFieldAccessor nodeClassField; | |
64 private final NodeFieldAccessor[] childFields; | |
65 private final NodeFieldAccessor[] childrenFields; | |
66 private final NodeFieldAccessor[] cloneableFields; | |
67 | |
68 private final Class<? extends Node> clazz; | |
69 | 48 |
70 public static NodeClass get(Class<? extends Node> clazz) { | 49 public static NodeClass get(Class<? extends Node> clazz) { |
71 return nodeClasses.get(clazz); | 50 return nodeClasses.get(clazz); |
72 } | 51 } |
73 | 52 |
74 public static NodeClass get(Node node) { | 53 public static NodeClass get(Node node) { |
75 return node.getNodeClass(); | 54 return node.getNodeClass(); |
76 } | 55 } |
77 | 56 |
78 NodeClass(Class<? extends Node> clazz) { | 57 protected NodeClass() { |
79 if (!Node.class.isAssignableFrom(clazz)) { | |
80 throw new IllegalArgumentException(); | |
81 } | |
82 | |
83 List<NodeFieldAccessor> fieldsList = new ArrayList<>(); | |
84 NodeFieldAccessor parentFieldTmp = null; | |
85 NodeFieldAccessor nodeClassFieldTmp = null; | |
86 List<NodeFieldAccessor> childFieldList = new ArrayList<>(); | |
87 List<NodeFieldAccessor> childrenFieldList = new ArrayList<>(); | |
88 List<NodeFieldAccessor> cloneableFieldList = new ArrayList<>(); | |
89 | |
90 try { | |
91 Field field = Node.class.getDeclaredField("parent"); | |
92 assert Node.class.isAssignableFrom(field.getType()); | |
93 parentFieldTmp = NodeFieldAccessor.create(NodeFieldKind.PARENT, field); | |
94 field = Node.class.getDeclaredField("nodeClass"); | |
95 assert NodeClass.class.isAssignableFrom(field.getType()); | |
96 nodeClassFieldTmp = NodeFieldAccessor.create(NodeFieldKind.NODE_CLASS, field); | |
97 } catch (NoSuchFieldException e) { | |
98 throw new AssertionError("Node field not found", e); | |
99 } | |
100 | |
101 collectInstanceFields(clazz, fieldsList, childFieldList, childrenFieldList, cloneableFieldList); | |
102 | |
103 this.fields = fieldsList.toArray(EMPTY_NODE_FIELD_ARRAY); | |
104 this.nodeClassField = nodeClassFieldTmp; | |
105 this.parentField = parentFieldTmp; | |
106 this.childFields = childFieldList.toArray(EMPTY_NODE_FIELD_ARRAY); | |
107 this.childrenFields = childrenFieldList.toArray(EMPTY_NODE_FIELD_ARRAY); | |
108 this.cloneableFields = cloneableFieldList.toArray(EMPTY_NODE_FIELD_ARRAY); | |
109 this.clazz = clazz; | |
110 } | 58 } |
111 | 59 |
112 private static void collectInstanceFields(Class<? extends Object> clazz, List<NodeFieldAccessor> fieldsList, List<NodeFieldAccessor> childFieldList, List<NodeFieldAccessor> childrenFieldList, | 60 public abstract NodeFieldAccessor getNodeClassField(); |
113 List<NodeFieldAccessor> cloneableFieldList) { | |
114 if (clazz.getSuperclass() != null) { | |
115 collectInstanceFields(clazz.getSuperclass(), fieldsList, childFieldList, childrenFieldList, cloneableFieldList); | |
116 } | |
117 Field[] declaredFields = clazz.getDeclaredFields(); | |
118 for (Field field : declaredFields) { | |
119 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { | |
120 continue; | |
121 } | |
122 | 61 |
123 NodeFieldAccessor nodeField; | 62 public abstract NodeFieldAccessor[] getCloneableFields(); |
124 if (field.getDeclaringClass() == Node.class && (field.getName().equals("parent") || field.getName().equals("nodeClass"))) { | |
125 continue; | |
126 } else if (field.getAnnotation(Child.class) != null) { | |
127 checkChildField(field); | |
128 nodeField = NodeFieldAccessor.create(NodeFieldKind.CHILD, field); | |
129 childFieldList.add(nodeField); | |
130 } else if (field.getAnnotation(Children.class) != null) { | |
131 checkChildrenField(field); | |
132 nodeField = NodeFieldAccessor.create(NodeFieldKind.CHILDREN, field); | |
133 childrenFieldList.add(nodeField); | |
134 } else { | |
135 nodeField = NodeFieldAccessor.create(NodeFieldKind.DATA, field); | |
136 if (NodeCloneable.class.isAssignableFrom(field.getType())) { | |
137 cloneableFieldList.add(nodeField); | |
138 } | |
139 } | |
140 fieldsList.add(nodeField); | |
141 } | |
142 } | |
143 | 63 |
144 public NodeFieldAccessor getNodeClassField() { | 64 public abstract NodeFieldAccessor[] getFields(); |
145 return nodeClassField; | |
146 } | |
147 | 65 |
148 public NodeFieldAccessor[] getCloneableFields() { | 66 public abstract NodeFieldAccessor getParentField(); |
149 return cloneableFields; | |
150 } | |
151 | 67 |
152 private static boolean isNodeType(Class<?> clazz) { | 68 public abstract NodeFieldAccessor[] getChildFields(); |
153 return Node.class.isAssignableFrom(clazz) || (clazz.isInterface() && NodeInterface.class.isAssignableFrom(clazz)); | |
154 } | |
155 | 69 |
156 private static void checkChildField(Field field) { | 70 public abstract NodeFieldAccessor[] getChildrenFields(); |
157 if (!isNodeType(field.getType())) { | |
158 throw new AssertionError("@Child field type must be a subclass of Node or an interface extending NodeInterface (" + field + ")"); | |
159 } | |
160 if (Modifier.isFinal(field.getModifiers())) { | |
161 throw new AssertionError("@Child field must not be final (" + field + ")"); | |
162 } | |
163 } | |
164 | 71 |
165 private static void checkChildrenField(Field field) { | 72 public abstract Iterator<Node> makeIterator(Node node); |
166 if (!(field.getType().isArray() && isNodeType(field.getType().getComponentType()))) { | |
167 throw new AssertionError("@Children field type must be an array of a subclass of Node or an interface extending NodeInterface (" + field + ")"); | |
168 } | |
169 if (!Modifier.isFinal(field.getModifiers())) { | |
170 throw new AssertionError("@Children field must be final (" + field + ")"); | |
171 } | |
172 } | |
173 | |
174 public NodeFieldAccessor[] getFields() { | |
175 return fields; | |
176 } | |
177 | |
178 public NodeFieldAccessor getParentField() { | |
179 return parentField; | |
180 } | |
181 | |
182 public NodeFieldAccessor[] getChildFields() { | |
183 return childFields; | |
184 } | |
185 | |
186 public NodeFieldAccessor[] getChildrenFields() { | |
187 return childrenFields; | |
188 } | |
189 | |
190 @Override | |
191 public int hashCode() { | |
192 return clazz.hashCode(); | |
193 } | |
194 | |
195 @Override | |
196 public boolean equals(Object obj) { | |
197 if (obj instanceof NodeClass) { | |
198 NodeClass other = (NodeClass) obj; | |
199 return clazz.equals(other.clazz); | |
200 } | |
201 return false; | |
202 } | |
203 | |
204 public Iterator<Node> makeIterator(Node node) { | |
205 assert clazz.isInstance(node); | |
206 return new NodeIterator(this, node); | |
207 } | |
208 | |
209 private static final class NodeIterator implements Iterator<Node> { | |
210 private final NodeFieldAccessor[] childFields; | |
211 private final NodeFieldAccessor[] childrenFields; | |
212 private final Node node; | |
213 private final int childrenCount; | |
214 private int index; | |
215 | |
216 protected NodeIterator(NodeClass nodeClass, Node node) { | |
217 this.childFields = nodeClass.getChildFields(); | |
218 this.childrenFields = nodeClass.getChildrenFields(); | |
219 this.node = node; | |
220 this.childrenCount = childrenCount(); | |
221 this.index = 0; | |
222 } | |
223 | |
224 private int childrenCount() { | |
225 int nodeCount = childFields.length; | |
226 for (NodeFieldAccessor childrenField : childrenFields) { | |
227 Object[] children = ((Object[]) childrenField.getObject(node)); | |
228 if (children != null) { | |
229 nodeCount += children.length; | |
230 } | |
231 } | |
232 return nodeCount; | |
233 } | |
234 | |
235 private Node nodeAt(int idx) { | |
236 int nodeCount = childFields.length; | |
237 if (idx < nodeCount) { | |
238 return (Node) childFields[idx].getObject(node); | |
239 } else { | |
240 for (NodeFieldAccessor childrenField : childrenFields) { | |
241 Object[] nodeArray = (Object[]) childrenField.getObject(node); | |
242 if (idx < nodeCount + nodeArray.length) { | |
243 return (Node) nodeArray[idx - nodeCount]; | |
244 } | |
245 nodeCount += nodeArray.length; | |
246 } | |
247 } | |
248 return null; | |
249 } | |
250 | |
251 private void forward() { | |
252 if (index < childrenCount) { | |
253 index++; | |
254 } | |
255 } | |
256 | |
257 public boolean hasNext() { | |
258 return index < childrenCount; | |
259 } | |
260 | |
261 public Node next() { | |
262 try { | |
263 return nodeAt(index); | |
264 } finally { | |
265 forward(); | |
266 } | |
267 } | |
268 | |
269 public void remove() { | |
270 throw new UnsupportedOperationException(); | |
271 } | |
272 } | |
273 } | 73 } |