Mercurial > hg > truffle
view graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/WordOperationPlugin.java @ 21543:93c50cefb9e8
moved GraalInternalError to com.oracle.jvmci.common and renamed it to JVMCIError (JBS:GRAAL-53)
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Mon, 25 May 2015 23:30:34 +0200 |
parents | cba35d171cd1 |
children | 48c1ebd24120 |
line wrap: on
line source
/* * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.graal.replacements; import static com.oracle.graal.api.meta.LocationIdentity.*; import static com.oracle.graal.nodes.ConstantNode.*; import java.lang.reflect.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.memory.HeapAccess.BarrierType; import com.oracle.graal.word.*; import com.oracle.graal.word.Word.Opcode; import com.oracle.graal.word.Word.Operation; import com.oracle.graal.word.nodes.*; import com.oracle.jvmci.common.*; /** * A {@link GenericInvocationPlugin} for calls to {@linkplain Operation word operations}, and a * {@link TypeCheckPlugin} to handle casts between word types. */ public class WordOperationPlugin implements GenericInvocationPlugin, TypeCheckPlugin { protected final WordTypes wordTypes; protected final Kind wordKind; protected final SnippetReflectionProvider snippetReflection; public WordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) { this.snippetReflection = snippetReflection; this.wordTypes = wordTypes; this.wordKind = wordTypes.getWordKind(); } /** * Processes a call to a method if it is annotated with {@link Operation} by adding nodes to the * graph being built that implement the denoted operation. * * @return {@code true} iff {@code method} is annotated with {@link Operation} (and was thus * processed by this method) */ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { if (!wordTypes.isWordOperation(method)) { return false; } processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass())); return true; } @Override public boolean checkCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { if (!wordTypes.isWord(type)) { if (object.getKind() != Kind.Object) { throw b.bailout("Cannot cast a word value to a non-word type: " + type.toJavaName(true)); } return false; } if (object.getKind() != wordTypes.getWordKind()) { throw b.bailout("Cannot cast a non-word value to a word type: " + type.toJavaName(true)); } b.push(Kind.Object, object); return true; } @Override public boolean instanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { if (wordTypes.isWord(type)) { throw b.bailout("Cannot use instanceof for word a type: " + type.toJavaName(true)); } else if (object.getKind() != Kind.Object) { throw b.bailout("Cannot use instanceof on a word value: " + type.toJavaName(true)); } return false; } protected void processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod) throws JVMCIError { Operation operation = wordMethod.getAnnotation(Word.Operation.class); Kind returnKind = wordMethod.getSignature().getReturnKind(); Kind returnStackKind = returnKind.getStackKind(); switch (operation.opcode()) { case NODE_CLASS: assert args.length == 2; ValueNode left = args[0]; ValueNode right = operation.rightOperandIsInt() ? toUnsigned(b, args[1], Kind.Int) : fromSigned(b, args[1]); b.addPush(returnStackKind, createBinaryNodeInstance(operation.node(), left, right)); break; case COMPARISON: assert args.length == 2; b.push(returnStackKind, comparisonOp(b, operation.condition(), args[0], fromSigned(b, args[1]))); break; case NOT: assert args.length == 1; b.addPush(returnStackKind, new XorNode(args[0], b.add(forIntegerKind(wordKind, -1)))); break; case READ_POINTER: case READ_OBJECT: case READ_BARRIERED: { assert args.length == 2 || args.length == 3; Kind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass())); LocationNode location; if (args.length == 2) { location = makeLocation(b, args[1], any()); } else { location = makeLocation(b, args[1], args[2]); } b.push(returnStackKind, readOp(b, readKind, args[0], location, operation.opcode())); break; } case READ_HEAP: { assert args.length == 3; Kind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass())); LocationNode location = makeLocation(b, args[1], any()); BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant()); b.push(returnStackKind, readOp(b, readKind, args[0], location, barrierType, true)); break; } case WRITE_POINTER: case WRITE_OBJECT: case WRITE_BARRIERED: case INITIALIZE: { assert args.length == 3 || args.length == 4; Kind writeKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(wordMethod.isStatic() ? 2 : 1, wordMethod.getDeclaringClass())); LocationNode location; if (args.length == 3) { location = makeLocation(b, args[1], LocationIdentity.any()); } else { location = makeLocation(b, args[1], args[3]); } writeOp(b, writeKind, args[0], args[2], location, operation.opcode()); break; } case ZERO: assert args.length == 0; b.addPush(returnStackKind, forIntegerKind(wordKind, 0L)); break; case FROM_UNSIGNED: assert args.length == 1; b.push(returnStackKind, fromUnsigned(b, args[0])); break; case FROM_SIGNED: assert args.length == 1; b.push(returnStackKind, fromSigned(b, args[0])); break; case TO_RAW_VALUE: assert args.length == 1; b.push(returnStackKind, toUnsigned(b, args[0], Kind.Long)); break; case FROM_WORDBASE: assert args.length == 1; b.push(returnStackKind, args[0]); break; case FROM_OBJECT: assert args.length == 1; WordCastNode objectToWord = b.add(WordCastNode.objectToWord(args[0], wordKind)); b.push(returnStackKind, objectToWord); break; case FROM_ARRAY: assert args.length == 2; b.addPush(returnStackKind, new ComputeAddressNode(args[0], args[1], StampFactory.forKind(wordKind))); break; case TO_OBJECT: assert args.length == 1; WordCastNode wordToObject = b.add(WordCastNode.wordToObject(args[0], wordKind)); b.push(returnStackKind, wordToObject); break; default: throw new JVMCIError("Unknown opcode: %s", operation.opcode()); } } /** * Create an instance of a binary node which is used to lower {@link Word} operations. This * method is called for all {@link Word} operations which are annotated with @Operation(node = * ...) and encapsulates the reflective allocation of the node. */ private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right) { try { Constructor<?> cons = nodeClass.getDeclaredConstructor(ValueNode.class, ValueNode.class); return (ValueNode) cons.newInstance(left, right); } catch (Throwable ex) { throw new JVMCIError(ex).addContext(nodeClass.getName()); } } private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) { assert left.getKind() == wordKind && right.getKind() == wordKind; // mirroring gets the condition into canonical form boolean mirror = condition.canonicalMirror(); ValueNode a = mirror ? right : left; ValueNode b = mirror ? left : right; CompareNode comparison; if (condition == Condition.EQ || condition == Condition.NE) { comparison = new IntegerEqualsNode(a, b); } else if (condition.isUnsigned()) { comparison = new IntegerBelowNode(a, b); } else { comparison = new IntegerLessThanNode(a, b); } ConstantNode trueValue = graph.add(forInt(1)); ConstantNode falseValue = graph.add(forInt(0)); if (condition.canonicalNegate()) { ConstantNode temp = trueValue; trueValue = falseValue; falseValue = temp; } ConditionalNode materialize = graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue)); return materialize; } protected ValueNode readOp(GraphBuilderContext b, Kind readKind, ValueNode base, LocationNode location, Opcode op) { assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED; final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE); final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED); return readOp(b, readKind, base, location, barrier, compressible); } public static ValueNode readOp(GraphBuilderContext b, Kind readKind, ValueNode base, LocationNode location, BarrierType barrierType, boolean compressible) { /* * A JavaReadNode lowered to a ReadNode that will not float. This means it cannot float * above an explicit zero check on its base address or any other test that ensures the read * is safe. */ JavaReadNode read = b.add(new JavaReadNode(readKind, base, location, barrierType, compressible)); return read; } protected void writeOp(GraphBuilderContext b, Kind writeKind, ValueNode base, ValueNode value, LocationNode location, Opcode op) { assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE; final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE); final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED); final boolean initialize = (op == Opcode.INITIALIZE); b.add(new JavaWriteNode(writeKind, base, value, location, barrier, compressible, initialize)); } public LocationNode makeLocation(GraphBuilderContext b, ValueNode offset, LocationIdentity locationIdentity) { return b.add(new IndexedLocationNode(locationIdentity, 0, fromSigned(b, offset), 1)); } public LocationNode makeLocation(GraphBuilderContext b, ValueNode offset, ValueNode locationIdentity) { if (locationIdentity.isConstant()) { return makeLocation(b, offset, snippetReflection.asObject(LocationIdentity.class, locationIdentity.asJavaConstant())); } return b.add(new SnippetLocationNode(snippetReflection, locationIdentity, b.add(ConstantNode.forLong(0)), fromSigned(b, offset), b.add(ConstantNode.forInt(1)))); } public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) { return convert(b, value, wordKind, true); } public ValueNode fromSigned(GraphBuilderContext b, ValueNode value) { return convert(b, value, wordKind, false); } public ValueNode toUnsigned(GraphBuilderContext b, ValueNode value, Kind toKind) { return convert(b, value, toKind, true); } public ValueNode convert(GraphBuilderContext b, ValueNode value, Kind toKind, boolean unsigned) { if (value.getKind() == toKind) { return value; } if (toKind == Kind.Int) { assert value.getKind() == Kind.Long; return b.add(new NarrowNode(value, 32)); } else { assert toKind == Kind.Long; assert value.getKind().getStackKind() == Kind.Int; if (unsigned) { return b.add(new ZeroExtendNode(value, 64)); } else { return b.add(new SignExtendNode(value, 64)); } } } public WordTypes getWordTypes() { return wordTypes; } }