1 /*
   2  * Copyright (c) 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.replacements.verifier;
  24 
  25 import java.io.PrintWriter;
  26 import java.util.List;
  27 import java.util.Set;
  28 
  29 import javax.annotation.processing.ProcessingEnvironment;
  30 import javax.lang.model.element.ExecutableElement;
  31 import javax.lang.model.element.VariableElement;
  32 import javax.lang.model.type.DeclaredType;
  33 import javax.lang.model.type.TypeKind;
  34 import javax.lang.model.type.TypeMirror;
  35 import javax.tools.Diagnostic.Kind;
  36 
  37 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
  38 import org.graalvm.compiler.graph.Node.InjectedNodeParameter;
  39 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
  40 import org.graalvm.compiler.replacements.verifier.InjectedDependencies.WellKnownDependency;
  41 
  42 /**
  43  * Create graph builder plugins for {@link NodeIntrinsic} methods.
  44  */
  45 public abstract class GeneratedNodeIntrinsicPlugin extends GeneratedPlugin {
  46 
  47     private final TypeMirror[] signature;
  48 
  49     public GeneratedNodeIntrinsicPlugin(ExecutableElement intrinsicMethod, TypeMirror[] signature) {
  50         super(intrinsicMethod);
  51         this.signature = signature;
  52     }
  53 
  54     private static TypeMirror valueNodeType(ProcessingEnvironment env) {
  55         return env.getElementUtils().getTypeElement("org.graalvm.compiler.nodes.ValueNode").asType();
  56     }
  57 
  58     protected abstract List<? extends VariableElement> getParameters();
  59 
  60     protected abstract void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount);
  61 
  62     @Override
  63     protected InjectedDependencies createExecute(ProcessingEnvironment env, PrintWriter out) {
  64         InjectedDependencies deps = new InjectedDependencies();
  65 
  66         List<? extends VariableElement> params = getParameters();
  67 
  68         int idx = 0;
  69         for (; idx < params.size(); idx++) {
  70             VariableElement param = params.get(idx);
  71             if (param.getAnnotation(InjectedNodeParameter.class) == null) {
  72                 break;
  73             }
  74 
  75             out.printf("            %s arg%d = %s;\n", param.asType(), idx, deps.use(env, (DeclaredType) param.asType()));
  76         }
  77 
  78         for (int i = 0; i < signature.length; i++, idx++) {
  79             if (intrinsicMethod.getParameters().get(i).getAnnotation(ConstantNodeParameter.class) != null) {
  80                 constantArgument(env, out, deps, idx, signature[i], i);
  81             } else {
  82                 if (signature[i].equals(valueNodeType(env))) {
  83                     out.printf("            ValueNode arg%d = args[%d];\n", idx, i);
  84                 } else {
  85                     out.printf("            %s arg%d = (%s) args[%d];\n", signature[i], idx, signature[i], i);
  86                 }
  87             }
  88         }
  89 
  90         factoryCall(env, out, deps, idx);
  91 
  92         return deps;
  93     }
  94 
  95     public static class ConstructorPlugin extends GeneratedNodeIntrinsicPlugin {
  96 
  97         private final ExecutableElement constructor;
  98 
  99         public ConstructorPlugin(ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature) {
 100             super(intrinsicMethod, signature);
 101             this.constructor = constructor;
 102         }
 103 
 104         @Override
 105         public void extraImports(Set<String> imports) {
 106             if (intrinsicMethod.getReturnType().getKind() != TypeKind.VOID) {
 107                 imports.add("jdk.vm.ci.meta.JavaKind");
 108             }
 109         }
 110 
 111         @Override
 112         protected List<? extends VariableElement> getParameters() {
 113             return constructor.getParameters();
 114         }
 115 
 116         @Override
 117         protected void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount) {
 118             out.printf("            %s node = new %s(", constructor.getEnclosingElement(), constructor.getEnclosingElement());
 119             if (argCount > 0) {
 120                 out.printf("arg0");
 121                 for (int i = 1; i < argCount; i++) {
 122                     out.printf(", arg%d", i);
 123                 }
 124             }
 125             out.printf(");\n");
 126 
 127             if (intrinsicMethod.getAnnotation(NodeIntrinsic.class).setStampFromReturnType()) {
 128                 out.printf("            node.setStamp(%s);\n", deps.use(WellKnownDependency.RETURN_STAMP));
 129             }
 130 
 131             if (intrinsicMethod.getReturnType().getKind() == TypeKind.VOID) {
 132                 out.printf("            b.add(node);\n");
 133             } else {
 134                 out.printf("            b.addPush(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod));
 135             }
 136             out.printf("            return true;\n");
 137         }
 138     }
 139 
 140     public static class CustomFactoryPlugin extends GeneratedNodeIntrinsicPlugin {
 141 
 142         private final ExecutableElement customFactory;
 143 
 144         public CustomFactoryPlugin(ExecutableElement intrinsicMethod, ExecutableElement customFactory, TypeMirror[] signature) {
 145             super(intrinsicMethod, signature);
 146             this.customFactory = customFactory;
 147         }
 148 
 149         @Override
 150         public void extraImports(Set<String> imports) {
 151         }
 152 
 153         @Override
 154         protected List<? extends VariableElement> getParameters() {
 155             List<? extends VariableElement> ret = customFactory.getParameters();
 156             // remove initial GraphBuilderContext and ResolvedJavaMethod parameters
 157             return ret.subList(2, ret.size());
 158         }
 159 
 160         @Override
 161         protected void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount) {
 162             out.printf("            return %s.%s(b, targetMethod", customFactory.getEnclosingElement(), customFactory.getSimpleName());
 163             for (int i = 0; i < argCount; i++) {
 164                 out.printf(", arg%d", i);
 165             }
 166             out.printf(");\n");
 167 
 168             if (intrinsicMethod.getAnnotation(NodeIntrinsic.class).setStampFromReturnType()) {
 169                 env.getMessager().printMessage(Kind.WARNING, "Ignoring setStampFromReturnType because a custom 'intrinsify' method is used.", intrinsicMethod);
 170             }
 171         }
 172     }
 173 }