46459
|
1 |
/*
|
|
2 |
* Copyright (c) 2015, 2016, 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.
|
|
8 |
*
|
|
9 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
13 |
* accompanied this code).
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License version
|
|
16 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 |
*
|
|
19 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
20 |
* or visit www.oracle.com if you need additional information or have any
|
|
21 |
* questions.
|
|
22 |
*/
|
|
23 |
package org.graalvm.compiler.word;
|
|
24 |
|
|
25 |
import static org.graalvm.compiler.nodes.ConstantNode.forInt;
|
|
26 |
import static org.graalvm.compiler.nodes.ConstantNode.forIntegerKind;
|
46551
|
27 |
import static org.graalvm.word.LocationIdentity.any;
|
46459
|
28 |
|
|
29 |
import java.lang.reflect.Constructor;
|
|
30 |
import java.util.Arrays;
|
|
31 |
|
|
32 |
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
|
|
33 |
import org.graalvm.compiler.bytecode.BridgeMethodUtils;
|
48861
|
34 |
import org.graalvm.compiler.core.common.calc.CanonicalCondition;
|
46459
|
35 |
import org.graalvm.compiler.core.common.calc.Condition;
|
48861
|
36 |
import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition;
|
46459
|
37 |
import org.graalvm.compiler.core.common.type.Stamp;
|
|
38 |
import org.graalvm.compiler.core.common.type.StampFactory;
|
|
39 |
import org.graalvm.compiler.core.common.type.StampPair;
|
|
40 |
import org.graalvm.compiler.core.common.type.TypeReference;
|
|
41 |
import org.graalvm.compiler.debug.GraalError;
|
|
42 |
import org.graalvm.compiler.nodes.ConstantNode;
|
|
43 |
import org.graalvm.compiler.nodes.Invoke;
|
|
44 |
import org.graalvm.compiler.nodes.ValueNode;
|
|
45 |
import org.graalvm.compiler.nodes.calc.CompareNode;
|
|
46 |
import org.graalvm.compiler.nodes.calc.ConditionalNode;
|
|
47 |
import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
|
|
48 |
import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
|
|
49 |
import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
|
|
50 |
import org.graalvm.compiler.nodes.calc.NarrowNode;
|
|
51 |
import org.graalvm.compiler.nodes.calc.SignExtendNode;
|
|
52 |
import org.graalvm.compiler.nodes.calc.XorNode;
|
|
53 |
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
|
|
54 |
import org.graalvm.compiler.nodes.extended.JavaReadNode;
|
|
55 |
import org.graalvm.compiler.nodes.extended.JavaWriteNode;
|
|
56 |
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
|
|
57 |
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
|
|
58 |
import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
|
|
59 |
import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
|
|
60 |
import org.graalvm.compiler.nodes.graphbuilderconf.TypePlugin;
|
|
61 |
import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
|
|
62 |
import org.graalvm.compiler.nodes.java.LoadFieldNode;
|
|
63 |
import org.graalvm.compiler.nodes.java.LoadIndexedNode;
|
|
64 |
import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
|
|
65 |
import org.graalvm.compiler.nodes.java.StoreIndexedNode;
|
|
66 |
import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
|
|
67 |
import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
|
|
68 |
import org.graalvm.compiler.nodes.memory.address.AddressNode;
|
|
69 |
import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
|
|
70 |
import org.graalvm.compiler.nodes.type.StampTool;
|
|
71 |
import org.graalvm.compiler.word.Word.Opcode;
|
|
72 |
import org.graalvm.compiler.word.Word.Operation;
|
46551
|
73 |
import org.graalvm.word.LocationIdentity;
|
|
74 |
import org.graalvm.word.WordFactory;
|
46459
|
75 |
|
|
76 |
import jdk.vm.ci.code.BailoutException;
|
|
77 |
import jdk.vm.ci.meta.JavaKind;
|
|
78 |
import jdk.vm.ci.meta.JavaType;
|
|
79 |
import jdk.vm.ci.meta.JavaTypeProfile;
|
|
80 |
import jdk.vm.ci.meta.ResolvedJavaField;
|
|
81 |
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
|
82 |
import jdk.vm.ci.meta.ResolvedJavaType;
|
|
83 |
|
|
84 |
/**
|
|
85 |
* A plugin for calls to {@linkplain Operation word operations}, as well as all other nodes that
|
|
86 |
* need special handling for {@link Word} types.
|
|
87 |
*/
|
|
88 |
public class WordOperationPlugin extends WordFactory implements NodePlugin, TypePlugin, InlineInvokePlugin {
|
|
89 |
protected final WordTypes wordTypes;
|
|
90 |
protected final JavaKind wordKind;
|
|
91 |
protected final SnippetReflectionProvider snippetReflection;
|
|
92 |
|
|
93 |
public WordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) {
|
|
94 |
this.snippetReflection = snippetReflection;
|
|
95 |
this.wordTypes = wordTypes;
|
|
96 |
this.wordKind = wordTypes.getWordKind();
|
|
97 |
}
|
|
98 |
|
|
99 |
@Override
|
|
100 |
public boolean canChangeStackKind(GraphBuilderContext b) {
|
|
101 |
return true;
|
|
102 |
}
|
|
103 |
|
|
104 |
/**
|
|
105 |
* Processes a call to a method if it is annotated as a word operation by adding nodes to the
|
|
106 |
* graph being built that implement the denoted operation.
|
|
107 |
*
|
|
108 |
* @return {@code true} iff {@code method} is annotated with {@link Operation} (and was thus
|
|
109 |
* processed by this method)
|
|
110 |
*/
|
|
111 |
@Override
|
|
112 |
public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
|
|
113 |
if (!wordTypes.isWordOperation(method)) {
|
|
114 |
return false;
|
|
115 |
}
|
|
116 |
processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass()));
|
|
117 |
return true;
|
|
118 |
}
|
|
119 |
|
|
120 |
@Override
|
|
121 |
public StampPair interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull) {
|
|
122 |
Stamp wordStamp = null;
|
|
123 |
if (declaredType instanceof ResolvedJavaType) {
|
|
124 |
ResolvedJavaType resolved = (ResolvedJavaType) declaredType;
|
|
125 |
if (wordTypes.isWord(resolved)) {
|
|
126 |
wordStamp = wordTypes.getWordStamp(resolved);
|
|
127 |
} else if (resolved.isArray() && wordTypes.isWord(resolved.getElementalType())) {
|
|
128 |
TypeReference trusted = TypeReference.createTrustedWithoutAssumptions(resolved);
|
|
129 |
wordStamp = StampFactory.object(trusted, nonNull);
|
|
130 |
}
|
|
131 |
}
|
|
132 |
if (wordStamp != null) {
|
|
133 |
return StampPair.createSingle(wordStamp);
|
|
134 |
} else {
|
|
135 |
return null;
|
|
136 |
}
|
|
137 |
}
|
|
138 |
|
|
139 |
@Override
|
|
140 |
public void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
|
|
141 |
if (wordTypes.isWord(invoke.asNode())) {
|
|
142 |
invoke.asNode().setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(invoke.asNode())));
|
|
143 |
}
|
|
144 |
}
|
|
145 |
|
|
146 |
@Override
|
|
147 |
public boolean handleLoadField(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) {
|
|
148 |
StampPair wordStamp = interceptType(b, field.getType(), false);
|
|
149 |
if (wordStamp != null) {
|
|
150 |
LoadFieldNode loadFieldNode = LoadFieldNode.createOverrideStamp(wordStamp, receiver, field);
|
|
151 |
b.addPush(field.getJavaKind(), loadFieldNode);
|
|
152 |
return true;
|
|
153 |
}
|
|
154 |
return false;
|
|
155 |
}
|
|
156 |
|
|
157 |
@Override
|
|
158 |
public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField staticField) {
|
|
159 |
return handleLoadField(b, null, staticField);
|
|
160 |
}
|
|
161 |
|
|
162 |
@Override
|
|
163 |
public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
|
|
164 |
ResolvedJavaType arrayType = StampTool.typeOrNull(array);
|
|
165 |
/*
|
|
166 |
* There are cases where the array does not have a known type yet, i.e., the type is null.
|
|
167 |
* In that case we assume it is not a word type.
|
|
168 |
*/
|
|
169 |
if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) {
|
|
170 |
assert elementKind == JavaKind.Object;
|
|
171 |
b.addPush(elementKind, createLoadIndexedNode(array, index));
|
|
172 |
return true;
|
|
173 |
}
|
|
174 |
return false;
|
|
175 |
}
|
|
176 |
|
|
177 |
protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) {
|
|
178 |
return new LoadIndexedNode(null, array, index, wordTypes.getWordKind());
|
|
179 |
}
|
|
180 |
|
|
181 |
@Override
|
|
182 |
public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
|
|
183 |
if (field.getJavaKind() == JavaKind.Object) {
|
|
184 |
boolean isWordField = wordTypes.isWord(field.getType());
|
|
185 |
boolean isWordValue = value.getStackKind() == wordTypes.getWordKind();
|
|
186 |
|
|
187 |
if (isWordField && !isWordValue) {
|
|
188 |
throw bailout(b, "Cannot store a non-word value into a word field: " + field.format("%H.%n"));
|
|
189 |
} else if (!isWordField && isWordValue) {
|
|
190 |
throw bailout(b, "Cannot store a word value into a non-word field: " + field.format("%H.%n"));
|
|
191 |
}
|
|
192 |
}
|
|
193 |
|
|
194 |
/* We never need to intercept the field store. */
|
|
195 |
return false;
|
|
196 |
}
|
|
197 |
|
|
198 |
@Override
|
|
199 |
public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) {
|
|
200 |
return handleStoreField(b, null, field, value);
|
|
201 |
}
|
|
202 |
|
|
203 |
@Override
|
|
204 |
public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
|
|
205 |
ResolvedJavaType arrayType = StampTool.typeOrNull(array);
|
|
206 |
if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) {
|
|
207 |
assert elementKind == JavaKind.Object;
|
|
208 |
if (value.getStackKind() != wordTypes.getWordKind()) {
|
|
209 |
throw bailout(b, "Cannot store a non-word value into a word array: " + arrayType.toJavaName(true));
|
|
210 |
}
|
|
211 |
b.add(createStoreIndexedNode(array, index, value));
|
|
212 |
return true;
|
|
213 |
}
|
|
214 |
if (elementKind == JavaKind.Object && value.getStackKind() == wordTypes.getWordKind()) {
|
|
215 |
throw bailout(b, "Cannot store a word value into a non-word array: " + arrayType.toJavaName(true));
|
|
216 |
}
|
|
217 |
return false;
|
|
218 |
}
|
|
219 |
|
|
220 |
protected StoreIndexedNode createStoreIndexedNode(ValueNode array, ValueNode index, ValueNode value) {
|
|
221 |
return new StoreIndexedNode(array, index, wordTypes.getWordKind(), value);
|
|
222 |
}
|
|
223 |
|
|
224 |
@Override
|
|
225 |
public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
|
|
226 |
if (!wordTypes.isWord(type)) {
|
|
227 |
if (object.getStackKind() != JavaKind.Object) {
|
|
228 |
throw bailout(b, "Cannot cast a word value to a non-word type: " + type.toJavaName(true));
|
|
229 |
}
|
|
230 |
return false;
|
|
231 |
}
|
|
232 |
|
|
233 |
if (object.getStackKind() != wordTypes.getWordKind()) {
|
|
234 |
throw bailout(b, "Cannot cast a non-word value to a word type: " + type.toJavaName(true));
|
|
235 |
}
|
|
236 |
b.push(JavaKind.Object, object);
|
|
237 |
return true;
|
|
238 |
}
|
|
239 |
|
|
240 |
@Override
|
|
241 |
public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
|
|
242 |
if (wordTypes.isWord(type)) {
|
|
243 |
throw bailout(b, "Cannot use instanceof for word a type: " + type.toJavaName(true));
|
|
244 |
} else if (object.getStackKind() != JavaKind.Object) {
|
|
245 |
throw bailout(b, "Cannot use instanceof on a word value: " + type.toJavaName(true));
|
|
246 |
}
|
|
247 |
return false;
|
|
248 |
}
|
|
249 |
|
|
250 |
protected void processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod) throws GraalError {
|
|
251 |
JavaKind returnKind = wordMethod.getSignature().getReturnKind();
|
|
252 |
WordFactory.FactoryOperation factoryOperation = BridgeMethodUtils.getAnnotation(WordFactory.FactoryOperation.class, wordMethod);
|
|
253 |
if (factoryOperation != null) {
|
|
254 |
switch (factoryOperation.opcode()) {
|
|
255 |
case ZERO:
|
|
256 |
assert args.length == 0;
|
|
257 |
b.addPush(returnKind, forIntegerKind(wordKind, 0L));
|
|
258 |
return;
|
|
259 |
|
|
260 |
case FROM_UNSIGNED:
|
|
261 |
assert args.length == 1;
|
|
262 |
b.push(returnKind, fromUnsigned(b, args[0]));
|
|
263 |
return;
|
|
264 |
|
|
265 |
case FROM_SIGNED:
|
|
266 |
assert args.length == 1;
|
|
267 |
b.push(returnKind, fromSigned(b, args[0]));
|
|
268 |
return;
|
|
269 |
}
|
|
270 |
}
|
|
271 |
|
|
272 |
Word.Operation operation = BridgeMethodUtils.getAnnotation(Word.Operation.class, wordMethod);
|
47667
|
273 |
if (operation == null) {
|
|
274 |
throw bailout(b, "Cannot call method on a word value: " + wordMethod.format("%H.%n(%p)"));
|
|
275 |
}
|
46459
|
276 |
switch (operation.opcode()) {
|
|
277 |
case NODE_CLASS:
|
|
278 |
assert args.length == 2;
|
|
279 |
ValueNode left = args[0];
|
|
280 |
ValueNode right = operation.rightOperandIsInt() ? toUnsigned(b, args[1], JavaKind.Int) : fromSigned(b, args[1]);
|
|
281 |
|
|
282 |
b.addPush(returnKind, createBinaryNodeInstance(operation.node(), left, right));
|
|
283 |
break;
|
|
284 |
|
|
285 |
case COMPARISON:
|
|
286 |
assert args.length == 2;
|
|
287 |
b.push(returnKind, comparisonOp(b, operation.condition(), args[0], fromSigned(b, args[1])));
|
|
288 |
break;
|
|
289 |
|
46640
|
290 |
case IS_NULL:
|
|
291 |
assert args.length == 1;
|
|
292 |
b.push(returnKind, comparisonOp(b, Condition.EQ, args[0], ConstantNode.forIntegerKind(wordKind, 0L)));
|
|
293 |
break;
|
|
294 |
|
|
295 |
case IS_NON_NULL:
|
|
296 |
assert args.length == 1;
|
|
297 |
b.push(returnKind, comparisonOp(b, Condition.NE, args[0], ConstantNode.forIntegerKind(wordKind, 0L)));
|
|
298 |
break;
|
|
299 |
|
46459
|
300 |
case NOT:
|
|
301 |
assert args.length == 1;
|
|
302 |
b.addPush(returnKind, new XorNode(args[0], b.add(forIntegerKind(wordKind, -1))));
|
|
303 |
break;
|
|
304 |
|
|
305 |
case READ_POINTER:
|
|
306 |
case READ_OBJECT:
|
|
307 |
case READ_BARRIERED: {
|
|
308 |
assert args.length == 2 || args.length == 3;
|
|
309 |
JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
|
|
310 |
AddressNode address = makeAddress(b, args[0], args[1]);
|
|
311 |
LocationIdentity location;
|
|
312 |
if (args.length == 2) {
|
|
313 |
location = any();
|
|
314 |
} else {
|
|
315 |
assert args[2].isConstant();
|
|
316 |
location = snippetReflection.asObject(LocationIdentity.class, args[2].asJavaConstant());
|
|
317 |
}
|
|
318 |
b.push(returnKind, readOp(b, readKind, address, location, operation.opcode()));
|
|
319 |
break;
|
|
320 |
}
|
|
321 |
case READ_HEAP: {
|
|
322 |
assert args.length == 3;
|
|
323 |
JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
|
|
324 |
AddressNode address = makeAddress(b, args[0], args[1]);
|
|
325 |
BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant());
|
|
326 |
b.push(returnKind, readOp(b, readKind, address, any(), barrierType, true));
|
|
327 |
break;
|
|
328 |
}
|
|
329 |
case WRITE_POINTER:
|
|
330 |
case WRITE_OBJECT:
|
|
331 |
case WRITE_BARRIERED:
|
|
332 |
case INITIALIZE: {
|
|
333 |
assert args.length == 3 || args.length == 4;
|
|
334 |
JavaKind writeKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(wordMethod.isStatic() ? 2 : 1, wordMethod.getDeclaringClass()));
|
|
335 |
AddressNode address = makeAddress(b, args[0], args[1]);
|
|
336 |
LocationIdentity location;
|
|
337 |
if (args.length == 3) {
|
|
338 |
location = any();
|
|
339 |
} else {
|
|
340 |
assert args[3].isConstant();
|
|
341 |
location = snippetReflection.asObject(LocationIdentity.class, args[3].asJavaConstant());
|
|
342 |
}
|
|
343 |
writeOp(b, writeKind, address, location, args[2], operation.opcode());
|
|
344 |
break;
|
|
345 |
}
|
|
346 |
|
|
347 |
case TO_RAW_VALUE:
|
|
348 |
assert args.length == 1;
|
|
349 |
b.push(returnKind, toUnsigned(b, args[0], JavaKind.Long));
|
|
350 |
break;
|
|
351 |
|
|
352 |
case OBJECT_TO_TRACKED:
|
|
353 |
assert args.length == 1;
|
|
354 |
WordCastNode objectToTracked = b.add(WordCastNode.objectToTrackedPointer(args[0], wordKind));
|
|
355 |
b.push(returnKind, objectToTracked);
|
|
356 |
break;
|
|
357 |
|
|
358 |
case OBJECT_TO_UNTRACKED:
|
|
359 |
assert args.length == 1;
|
|
360 |
WordCastNode objectToUntracked = b.add(WordCastNode.objectToUntrackedPointer(args[0], wordKind));
|
|
361 |
b.push(returnKind, objectToUntracked);
|
|
362 |
break;
|
|
363 |
|
|
364 |
case FROM_ADDRESS:
|
|
365 |
assert args.length == 1;
|
|
366 |
WordCastNode addressToWord = b.add(WordCastNode.addressToWord(args[0], wordKind));
|
|
367 |
b.push(returnKind, addressToWord);
|
|
368 |
break;
|
|
369 |
|
|
370 |
case TO_OBJECT:
|
|
371 |
assert args.length == 1;
|
|
372 |
WordCastNode wordToObject = b.add(WordCastNode.wordToObject(args[0], wordKind));
|
|
373 |
b.push(returnKind, wordToObject);
|
|
374 |
break;
|
|
375 |
|
|
376 |
case TO_OBJECT_NON_NULL:
|
|
377 |
assert args.length == 1;
|
|
378 |
WordCastNode wordToObjectNonNull = b.add(WordCastNode.wordToObjectNonNull(args[0], wordKind));
|
|
379 |
b.push(returnKind, wordToObjectNonNull);
|
|
380 |
break;
|
|
381 |
|
|
382 |
case CAS_POINTER:
|
|
383 |
assert args.length == 5;
|
|
384 |
AddressNode address = makeAddress(b, args[0], args[1]);
|
|
385 |
JavaKind valueKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(1, wordMethod.getDeclaringClass()));
|
|
386 |
assert valueKind.equals(wordTypes.asKind(wordMethod.getSignature().getParameterType(2, wordMethod.getDeclaringClass()))) : wordMethod.getSignature();
|
|
387 |
assert args[4].isConstant() : Arrays.toString(args);
|
|
388 |
LocationIdentity location = snippetReflection.asObject(LocationIdentity.class, args[4].asJavaConstant());
|
|
389 |
JavaType returnType = wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass());
|
|
390 |
b.addPush(returnKind, casOp(valueKind, wordTypes.asKind(returnType), address, location, args[2], args[3]));
|
|
391 |
break;
|
|
392 |
default:
|
|
393 |
throw new GraalError("Unknown opcode: %s", operation.opcode());
|
|
394 |
}
|
|
395 |
}
|
|
396 |
|
|
397 |
/**
|
|
398 |
* Create an instance of a binary node which is used to lower {@link Word} operations. This
|
|
399 |
* method is called for all {@link Word} operations which are annotated with @Operation(node =
|
|
400 |
* ...) and encapsulates the reflective allocation of the node.
|
|
401 |
*/
|
|
402 |
private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right) {
|
|
403 |
try {
|
|
404 |
Constructor<?> cons = nodeClass.getDeclaredConstructor(ValueNode.class, ValueNode.class);
|
|
405 |
return (ValueNode) cons.newInstance(left, right);
|
|
406 |
} catch (Throwable ex) {
|
|
407 |
throw new GraalError(ex).addContext(nodeClass.getName());
|
|
408 |
}
|
|
409 |
}
|
|
410 |
|
|
411 |
private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) {
|
|
412 |
assert left.getStackKind() == wordKind && right.getStackKind() == wordKind;
|
|
413 |
|
48861
|
414 |
CanonicalizedCondition canonical = condition.canonicalize();
|
46459
|
415 |
|
48861
|
416 |
ValueNode a = canonical.mustMirror() ? right : left;
|
|
417 |
ValueNode b = canonical.mustMirror() ? left : right;
|
46459
|
418 |
|
|
419 |
CompareNode comparison;
|
48861
|
420 |
if (canonical.getCanonicalCondition() == CanonicalCondition.EQ) {
|
46459
|
421 |
comparison = new IntegerEqualsNode(a, b);
|
48861
|
422 |
} else if (canonical.getCanonicalCondition() == CanonicalCondition.BT) {
|
46459
|
423 |
comparison = new IntegerBelowNode(a, b);
|
|
424 |
} else {
|
48861
|
425 |
assert canonical.getCanonicalCondition() == CanonicalCondition.LT;
|
46459
|
426 |
comparison = new IntegerLessThanNode(a, b);
|
|
427 |
}
|
|
428 |
|
|
429 |
ConstantNode trueValue = graph.add(forInt(1));
|
|
430 |
ConstantNode falseValue = graph.add(forInt(0));
|
|
431 |
|
48861
|
432 |
if (canonical.mustNegate()) {
|
46459
|
433 |
ConstantNode temp = trueValue;
|
|
434 |
trueValue = falseValue;
|
|
435 |
falseValue = temp;
|
|
436 |
}
|
48861
|
437 |
return graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue));
|
46459
|
438 |
}
|
|
439 |
|
|
440 |
protected ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, Opcode op) {
|
|
441 |
assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED;
|
|
442 |
final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
|
|
443 |
final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED);
|
|
444 |
|
|
445 |
return readOp(b, readKind, address, location, barrier, compressible);
|
|
446 |
}
|
|
447 |
|
|
448 |
public static ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, BarrierType barrierType, boolean compressible) {
|
|
449 |
/*
|
|
450 |
* A JavaReadNode lowered to a ReadNode that will not float. This means it cannot float
|
|
451 |
* above an explicit zero check on its base address or any other test that ensures the read
|
|
452 |
* is safe.
|
|
453 |
*/
|
|
454 |
JavaReadNode read = b.add(new JavaReadNode(readKind, address, location, barrierType, compressible));
|
|
455 |
return read;
|
|
456 |
}
|
|
457 |
|
|
458 |
protected void writeOp(GraphBuilderContext b, JavaKind writeKind, AddressNode address, LocationIdentity location, ValueNode value, Opcode op) {
|
|
459 |
assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE;
|
|
460 |
final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
|
|
461 |
final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED);
|
|
462 |
assert op != Opcode.INITIALIZE || location.isInit() : "must use init location for initializing";
|
|
463 |
b.add(new JavaWriteNode(writeKind, address, location, value, barrier, compressible));
|
|
464 |
}
|
|
465 |
|
|
466 |
protected AbstractCompareAndSwapNode casOp(JavaKind writeKind, JavaKind returnKind, AddressNode address, LocationIdentity location, ValueNode expectedValue, ValueNode newValue) {
|
|
467 |
boolean isLogic = returnKind == JavaKind.Boolean;
|
|
468 |
assert isLogic || writeKind == returnKind : writeKind + " != " + returnKind;
|
|
469 |
AbstractCompareAndSwapNode cas;
|
|
470 |
if (isLogic) {
|
|
471 |
cas = new LogicCompareAndSwapNode(address, expectedValue, newValue, location);
|
|
472 |
} else {
|
|
473 |
cas = new ValueCompareAndSwapNode(address, expectedValue, newValue, location);
|
|
474 |
}
|
|
475 |
return cas;
|
|
476 |
}
|
|
477 |
|
|
478 |
public AddressNode makeAddress(GraphBuilderContext b, ValueNode base, ValueNode offset) {
|
|
479 |
return b.add(new OffsetAddressNode(base, fromSigned(b, offset)));
|
|
480 |
}
|
|
481 |
|
|
482 |
public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) {
|
|
483 |
return convert(b, value, wordKind, true);
|
|
484 |
}
|
|
485 |
|
|
486 |
public ValueNode fromSigned(GraphBuilderContext b, ValueNode value) {
|
|
487 |
return convert(b, value, wordKind, false);
|
|
488 |
}
|
|
489 |
|
|
490 |
public ValueNode toUnsigned(GraphBuilderContext b, ValueNode value, JavaKind toKind) {
|
|
491 |
return convert(b, value, toKind, true);
|
|
492 |
}
|
|
493 |
|
|
494 |
public ValueNode convert(GraphBuilderContext b, ValueNode value, JavaKind toKind, boolean unsigned) {
|
|
495 |
if (value.getStackKind() == toKind) {
|
|
496 |
return value;
|
|
497 |
}
|
|
498 |
|
|
499 |
if (toKind == JavaKind.Int) {
|
|
500 |
assert value.getStackKind() == JavaKind.Long;
|
|
501 |
return b.add(new NarrowNode(value, 32));
|
|
502 |
} else {
|
|
503 |
assert toKind == JavaKind.Long;
|
|
504 |
assert value.getStackKind() == JavaKind.Int;
|
|
505 |
if (unsigned) {
|
|
506 |
return b.add(new ZeroExtendNode(value, 64));
|
|
507 |
} else {
|
|
508 |
return b.add(new SignExtendNode(value, 64));
|
|
509 |
}
|
|
510 |
}
|
|
511 |
}
|
|
512 |
|
|
513 |
public WordTypes getWordTypes() {
|
|
514 |
return wordTypes;
|
|
515 |
}
|
|
516 |
|
|
517 |
private static BailoutException bailout(GraphBuilderContext b, String msg) {
|
|
518 |
throw b.bailout(msg + "\nat " + b.getCode().asStackTraceElement(b.bci()));
|
|
519 |
}
|
|
520 |
}
|