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