Mercurial > hg > truffle
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeClass.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 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[] childFields; | |
58 private final NodeFieldAccessor[] childrenFields; | |
59 private final NodeFieldAccessor[] cloneableFields; | |
60 | |
61 private final Class<? extends Node> clazz; | |
62 | |
63 public static NodeClass get(Class<? extends Node> clazz) { | |
64 return nodeClasses.get(clazz); | |
65 } | |
66 | |
67 public NodeClass(Class<? extends Node> clazz) { | |
68 List<NodeFieldAccessor> fieldsList = new ArrayList<>(); | |
69 NodeFieldAccessor parentFieldTmp = null; | |
70 List<NodeFieldAccessor> childFieldList = new ArrayList<>(); | |
71 List<NodeFieldAccessor> childrenFieldList = new ArrayList<>(); | |
72 List<NodeFieldAccessor> cloneableFieldList = new ArrayList<>(); | |
73 | |
74 for (Field field : NodeUtil.getAllFields(clazz)) { | |
75 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { | |
76 continue; | |
77 } | |
78 | |
79 NodeFieldAccessor nodeField; | |
80 if (field.getDeclaringClass() == Node.class && field.getName().equals("parent")) { | |
81 assert Node.class.isAssignableFrom(field.getType()); | |
82 nodeField = NodeFieldAccessor.create(NodeFieldKind.PARENT, field); | |
83 parentFieldTmp = nodeField; | |
84 } else if (field.getAnnotation(Child.class) != null) { | |
85 checkChildField(field); | |
86 nodeField = NodeFieldAccessor.create(NodeFieldKind.CHILD, field); | |
87 childFieldList.add(nodeField); | |
88 } else if (field.getAnnotation(Children.class) != null) { | |
89 checkChildrenField(field); | |
90 nodeField = NodeFieldAccessor.create(NodeFieldKind.CHILDREN, field); | |
91 childrenFieldList.add(nodeField); | |
92 } else { | |
93 nodeField = NodeFieldAccessor.create(NodeFieldKind.DATA, field); | |
94 if (NodeCloneable.class.isAssignableFrom(field.getType())) { | |
95 cloneableFieldList.add(nodeField); | |
96 } | |
97 } | |
98 fieldsList.add(nodeField); | |
99 } | |
100 | |
101 if (parentFieldTmp == null) { | |
102 throw new AssertionError("parent field not found"); | |
103 } | |
104 | |
105 this.fields = fieldsList.toArray(new NodeFieldAccessor[fieldsList.size()]); | |
106 this.parentField = parentFieldTmp; | |
107 this.childFields = childFieldList.toArray(new NodeFieldAccessor[childFieldList.size()]); | |
108 this.childrenFields = childrenFieldList.toArray(new NodeFieldAccessor[childrenFieldList.size()]); | |
109 this.cloneableFields = cloneableFieldList.toArray(new NodeFieldAccessor[cloneableFieldList.size()]); | |
110 this.clazz = clazz; | |
111 } | |
112 | |
113 public NodeFieldAccessor[] getCloneableFields() { | |
114 return cloneableFields; | |
115 } | |
116 | |
117 private static boolean isNodeType(Class<?> clazz) { | |
118 return Node.class.isAssignableFrom(clazz) || (clazz.isInterface() && NodeInterface.class.isAssignableFrom(clazz)); | |
119 } | |
120 | |
121 private static void checkChildField(Field field) { | |
122 if (!isNodeType(field.getType())) { | |
123 throw new AssertionError("@Child field type must be a subclass of Node or an interface extending NodeInterface (" + field + ")"); | |
124 } | |
125 if (Modifier.isFinal(field.getModifiers())) { | |
126 throw new AssertionError("@Child field must not be final (" + field + ")"); | |
127 } | |
128 } | |
129 | |
130 private static void checkChildrenField(Field field) { | |
131 if (!(field.getType().isArray() && isNodeType(field.getType().getComponentType()))) { | |
132 throw new AssertionError("@Children field type must be an array of a subclass of Node or an interface extending NodeInterface (" + field + ")"); | |
133 } | |
134 if (!Modifier.isFinal(field.getModifiers())) { | |
135 throw new AssertionError("@Children field must be final (" + field + ")"); | |
136 } | |
137 } | |
138 | |
139 public NodeFieldAccessor[] getFields() { | |
140 return fields; | |
141 } | |
142 | |
143 public NodeFieldAccessor getParentField() { | |
144 return parentField; | |
145 } | |
146 | |
147 public NodeFieldAccessor[] getChildFields() { | |
148 return childFields; | |
149 } | |
150 | |
151 public NodeFieldAccessor[] getChildrenFields() { | |
152 return childrenFields; | |
153 } | |
154 | |
155 @Override | |
156 public int hashCode() { | |
157 return clazz.hashCode(); | |
158 } | |
159 | |
160 @Override | |
161 public boolean equals(Object obj) { | |
162 if (obj instanceof NodeClass) { | |
163 NodeClass other = (NodeClass) obj; | |
164 return clazz.equals(other.clazz); | |
165 } | |
166 return false; | |
167 } | |
168 | |
169 public Iterator<Node> makeIterator(Node node) { | |
170 assert clazz.isInstance(node); | |
171 return new NodeIterator(this, node); | |
172 } | |
173 | |
174 private static final class NodeIterator implements Iterator<Node> { | |
175 private final NodeFieldAccessor[] childFields; | |
176 private final NodeFieldAccessor[] childrenFields; | |
177 private final Node node; | |
178 private final int childrenCount; | |
179 private int index; | |
180 | |
181 protected NodeIterator(NodeClass nodeClass, Node node) { | |
182 this.childFields = nodeClass.getChildFields(); | |
183 this.childrenFields = nodeClass.getChildrenFields(); | |
184 this.node = node; | |
185 this.childrenCount = childrenCount(); | |
186 this.index = 0; | |
187 } | |
188 | |
189 private int childrenCount() { | |
190 int nodeCount = childFields.length; | |
191 for (NodeFieldAccessor childrenField : childrenFields) { | |
192 Object[] children = ((Object[]) childrenField.getObject(node)); | |
193 if (children != null) { | |
194 nodeCount += children.length; | |
195 } | |
196 } | |
197 return nodeCount; | |
198 } | |
199 | |
200 private Node nodeAt(int idx) { | |
201 int nodeCount = childFields.length; | |
202 if (idx < nodeCount) { | |
203 return (Node) childFields[idx].getObject(node); | |
204 } else { | |
205 for (NodeFieldAccessor childrenField : childrenFields) { | |
206 Object[] nodeArray = (Object[]) childrenField.getObject(node); | |
207 if (idx < nodeCount + nodeArray.length) { | |
208 return (Node) nodeArray[idx - nodeCount]; | |
209 } | |
210 nodeCount += nodeArray.length; | |
211 } | |
212 } | |
213 return null; | |
214 } | |
215 | |
216 private void forward() { | |
217 if (index < childrenCount) { | |
218 index++; | |
219 } | |
220 } | |
221 | |
222 public boolean hasNext() { | |
223 return index < childrenCount; | |
224 } | |
225 | |
226 public Node next() { | |
227 try { | |
228 return nodeAt(index); | |
229 } finally { | |
230 forward(); | |
231 } | |
232 } | |
233 | |
234 public void remove() { | |
235 throw new UnsupportedOperationException(); | |
236 } | |
237 } | |
238 } |