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