1 /* 2 * Copyright (c) 2014, 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. 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.core.match; 24 25 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.LogVerbose; 26 27 import java.util.List; 28 29 import jdk.vm.ci.meta.Value; 30 31 import org.graalvm.compiler.core.gen.NodeLIRBuilder; 32 import org.graalvm.compiler.core.match.MatchPattern.MatchResultCode; 33 import org.graalvm.compiler.core.match.MatchPattern.Result; 34 import org.graalvm.compiler.debug.Debug; 35 import org.graalvm.compiler.debug.DebugCounter; 36 import org.graalvm.compiler.graph.GraalGraphError; 37 import org.graalvm.compiler.graph.Node; 38 import org.graalvm.compiler.nodeinfo.Verbosity; 39 40 /** 41 * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace 42 * one or more {@link Node}s with a single {@link Value}. 43 */ 44 45 public class MatchStatement { 46 private static final DebugCounter MatchStatementSuccess = Debug.counter("MatchStatementSuccess"); 47 48 /** 49 * A printable name for this statement. Usually it's just the name of the method doing the 50 * emission. 51 */ 52 private final String name; 53 54 /** 55 * The actual match pattern. 56 */ 57 private final MatchPattern pattern; 58 59 /** 60 * The method in the {@link NodeLIRBuilder} subclass that will actually do the code emission. 61 */ 62 private MatchGenerator generatorMethod; 63 64 /** 65 * The name of arguments in the order they are expected to be passed to the generator method. 66 */ 67 private String[] arguments; 68 69 public MatchStatement(String name, MatchPattern pattern, MatchGenerator generator, String[] arguments) { 70 this.name = name; 71 this.pattern = pattern; 72 this.generatorMethod = generator; 73 this.arguments = arguments; 74 } 75 76 /** 77 * Attempt to match the current statement against a Node. 78 * 79 * @param builder the current builder instance. 80 * @param node the node to be matched 81 * @param nodes the nodes in the current block 82 * @return true if the statement matched something and set a {@link ComplexMatchResult} to be 83 * evaluated by the NodeLIRBuilder. 84 */ 85 public boolean generate(NodeLIRBuilder builder, int index, Node node, List<Node> nodes) { 86 assert index == nodes.indexOf(node); 87 // Check that the basic shape matches 88 Result result = pattern.matchShape(node, this); 89 if (result != Result.OK) { 90 return false; 91 } 92 // Now ensure that the other safety constraints are matched. 93 MatchContext context = new MatchContext(builder, this, index, node, nodes); 94 result = pattern.matchUsage(node, context); 95 if (result == Result.OK) { 96 // Invoke the generator method and set the result if it's non null. 97 ComplexMatchResult value = generatorMethod.match(builder.getNodeMatchRules(), buildArgList(context)); 98 if (value != null) { 99 context.setResult(value); 100 MatchStatementSuccess.increment(); 101 Debug.counter("MatchStatement[%s]", getName()).increment(); 102 return true; 103 } 104 // The pattern matched but some other code generation constraint disallowed code 105 // generation for the pattern. 106 if (LogVerbose.getValue()) { 107 Debug.log("while matching %s|%s %s %s returned null", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), generatorMethod.getName()); 108 Debug.log("with nodes %s", formatMatch(node)); 109 } 110 } else { 111 if (LogVerbose.getValue() && result.code != MatchResultCode.WRONG_CLASS) { 112 Debug.log("while matching %s|%s %s %s", context.getRoot().toString(Verbosity.Id), context.getRoot().getClass().getSimpleName(), getName(), result); 113 } 114 } 115 return false; 116 } 117 118 /** 119 * @param context 120 * @return the Nodes captured by the match rule in the order expected by the generatorMethod 121 */ 122 private Object[] buildArgList(MatchContext context) { 123 Object[] result = new Object[arguments.length]; 124 for (int i = 0; i < arguments.length; i++) { 125 if ("root".equals(arguments[i])) { 126 result[i] = context.getRoot(); 127 } else { 128 result[i] = context.namedNode(arguments[i]); 129 if (result[i] == null) { 130 throw new GraalGraphError("Can't find named node %s", arguments[i]); 131 } 132 } 133 } 134 return result; 135 } 136 137 public String formatMatch(Node root) { 138 return pattern.formatMatch(root); 139 } 140 141 public MatchPattern getPattern() { 142 return pattern; 143 } 144 145 public String getName() { 146 return name; 147 } 148 149 @Override 150 public String toString() { 151 return pattern.toString(); 152 } 153 }