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