1 /* 2 * Copyright (c) 2015, 2019, 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.replacements.processor; 26 27 import java.io.PrintWriter; 28 import java.util.Set; 29 30 import javax.lang.model.element.ExecutableElement; 31 import javax.lang.model.element.Modifier; 32 import javax.lang.model.element.TypeElement; 33 import javax.lang.model.element.VariableElement; 34 import javax.lang.model.type.ArrayType; 35 import javax.lang.model.type.DeclaredType; 36 import javax.lang.model.type.TypeMirror; 37 import javax.lang.model.type.TypeVariable; 38 import javax.lang.model.type.WildcardType; 39 40 import org.graalvm.compiler.processor.AbstractProcessor; 41 import org.graalvm.compiler.replacements.processor.InjectedDependencies.Dependency; 42 import org.graalvm.compiler.replacements.processor.InjectedDependencies.WellKnownDependency; 43 44 public abstract class GeneratedPlugin { 45 46 protected final ExecutableElement intrinsicMethod; 47 private boolean needInjectionProvider; 48 49 private String pluginName; 50 51 public GeneratedPlugin(ExecutableElement intrinsicMethod) { 52 this.intrinsicMethod = intrinsicMethod; 53 this.needInjectionProvider = false; 54 // Lets keep generated class names short to mitigate hitting file name length limits. 55 this.pluginName = "Plugin_" + intrinsicMethod.getEnclosingElement().getSimpleName() + "_" + intrinsicMethod.getSimpleName().toString(); 56 } 57 58 protected abstract TypeElement getAnnotationClass(AbstractProcessor processor); 59 60 public String getPluginName() { 61 return pluginName; 62 } 63 64 public void setPluginName(String pluginName) { 65 this.pluginName = pluginName; 66 } 67 68 public void generate(AbstractProcessor processor, PrintWriter out) { 69 out.printf("// class: %s\n", intrinsicMethod.getEnclosingElement()); 70 out.printf("// method: %s\n", intrinsicMethod); 71 out.printf("// generated-by: %s\n", getClass().getName()); 72 out.printf("final class %s extends GeneratedInvocationPlugin {\n", pluginName); 73 out.printf("\n"); 74 out.printf(" @Override\n"); 75 out.printf(" public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {\n"); 76 out.printf(" if (!b.isPluginEnabled(this)) {\n"); 77 out.printf(" return false;\n"); 78 out.printf(" }\n"); 79 InjectedDependencies deps = createExecute(processor, out); 80 out.printf(" }\n"); 81 out.printf(" @Override\n"); 82 out.printf(" public Class<? extends Annotation> getSource() {\n"); 83 out.printf(" return %s.class;\n", getAnnotationClass(processor).getQualifiedName().toString().replace('$', '.')); 84 out.printf(" }\n"); 85 86 createPrivateMembers(processor, out, deps); 87 88 out.printf("}\n"); 89 } 90 91 public void register(PrintWriter out) { 92 out.printf(" plugins.register(new %s(", pluginName); 93 if (needInjectionProvider) { 94 out.printf("injection"); 95 } 96 out.printf("), %s.class, \"%s\"", intrinsicMethod.getEnclosingElement(), intrinsicMethod.getSimpleName()); 97 if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) { 98 out.printf(", InvocationPlugin.Receiver.class"); 99 } 100 for (VariableElement arg : intrinsicMethod.getParameters()) { 101 out.printf(", %s.class", getErasedType(arg.asType())); 102 } 103 out.printf(");\n"); 104 } 105 106 public abstract void extraImports(Set<String> imports); 107 108 protected abstract InjectedDependencies createExecute(AbstractProcessor processor, PrintWriter out); 109 110 static String getErasedType(TypeMirror type) { 111 switch (type.getKind()) { 112 case DECLARED: 113 DeclaredType declared = (DeclaredType) type; 114 TypeElement element = (TypeElement) declared.asElement(); 115 return element.getQualifiedName().toString(); 116 case TYPEVAR: 117 return getErasedType(((TypeVariable) type).getUpperBound()); 118 case WILDCARD: 119 return getErasedType(((WildcardType) type).getExtendsBound()); 120 case ARRAY: 121 return getErasedType(((ArrayType) type).getComponentType()) + "[]"; 122 default: 123 return type.toString(); 124 } 125 } 126 127 static boolean hasRawtypeWarning(TypeMirror type) { 128 switch (type.getKind()) { 129 case DECLARED: 130 DeclaredType declared = (DeclaredType) type; 131 return declared.getTypeArguments().size() > 0; 132 case TYPEVAR: 133 return false; 134 case WILDCARD: 135 return false; 136 case ARRAY: 137 return hasRawtypeWarning(((ArrayType) type).getComponentType()); 138 default: 139 return false; 140 } 141 } 142 143 static boolean hasUncheckedWarning(TypeMirror type) { 144 switch (type.getKind()) { 145 case DECLARED: 146 DeclaredType declared = (DeclaredType) type; 147 for (TypeMirror typeParam : declared.getTypeArguments()) { 148 if (hasUncheckedWarning(typeParam)) { 149 return true; 150 } 151 } 152 return false; 153 case TYPEVAR: 154 return true; 155 case WILDCARD: 156 return ((WildcardType) type).getExtendsBound() != null; 157 case ARRAY: 158 return hasUncheckedWarning(((ArrayType) type).getComponentType()); 159 default: 160 return false; 161 } 162 } 163 164 private void createPrivateMembers(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps) { 165 if (!deps.isEmpty()) { 166 out.printf("\n"); 167 for (Dependency dep : deps) { 168 out.printf(" private final %s %s;\n", dep.type, dep.name); 169 } 170 171 out.printf("\n"); 172 out.printf(" %s(NodeIntrinsicPluginFactory.InjectionProvider injection) {\n", pluginName); 173 for (Dependency dep : deps) { 174 out.printf(" this.%s = %s;\n", dep.name, dep.inject(processor, intrinsicMethod)); 175 } 176 out.printf(" }\n"); 177 178 needInjectionProvider = true; 179 } 180 } 181 182 protected static String getReturnKind(ExecutableElement method) { 183 switch (method.getReturnType().getKind()) { 184 case BOOLEAN: 185 case BYTE: 186 case SHORT: 187 case CHAR: 188 case INT: 189 return "Int"; 190 case LONG: 191 return "Long"; 192 case FLOAT: 193 return "Float"; 194 case DOUBLE: 195 return "Double"; 196 case VOID: 197 return "Void"; 198 case ARRAY: 199 case TYPEVAR: 200 case DECLARED: 201 return "Object"; 202 default: 203 throw new IllegalArgumentException(method.getReturnType().toString()); 204 } 205 } 206 207 protected static void constantArgument(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps, int argIdx, TypeMirror type, int nodeIdx) { 208 if (hasRawtypeWarning(type)) { 209 out.printf(" @SuppressWarnings({\"rawtypes\"})\n"); 210 } 211 out.printf(" %s arg%d;\n", getErasedType(type), argIdx); 212 out.printf(" if (args[%d].isConstant()) {\n", nodeIdx); 213 if (type.equals(processor.getType("jdk.vm.ci.meta.ResolvedJavaType"))) { 214 out.printf(" jdk.vm.ci.meta.JavaConstant cst = args[%d].asJavaConstant();\n", nodeIdx); 215 out.printf(" arg%d = %s.asJavaType(cst);\n", argIdx, deps.use(WellKnownDependency.CONSTANT_REFLECTION)); 216 out.printf(" if (arg%d == null) {\n", argIdx); 217 out.printf(" arg%d = %s.asObject(jdk.vm.ci.meta.ResolvedJavaType.class, cst);\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION)); 218 out.printf(" }\n"); 219 } else { 220 switch (type.getKind()) { 221 case BOOLEAN: 222 out.printf(" arg%d = args[%d].asJavaConstant().asInt() != 0;\n", argIdx, nodeIdx); 223 break; 224 case BYTE: 225 out.printf(" arg%d = (byte) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); 226 break; 227 case CHAR: 228 out.printf(" arg%d = (char) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); 229 break; 230 case SHORT: 231 out.printf(" arg%d = (short) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); 232 break; 233 case INT: 234 out.printf(" arg%d = args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); 235 break; 236 case LONG: 237 out.printf(" arg%d = args[%d].asJavaConstant().asLong();\n", argIdx, nodeIdx); 238 break; 239 case FLOAT: 240 out.printf(" arg%d = args[%d].asJavaConstant().asFloat();\n", argIdx, nodeIdx); 241 break; 242 case DOUBLE: 243 out.printf(" arg%d = args[%d].asJavaConstant().asDouble();\n", argIdx, nodeIdx); 244 break; 245 case ARRAY: 246 case DECLARED: 247 out.printf(" arg%d = %s.asObject(%s.class, args[%d].asJavaConstant());\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION), getErasedType(type), nodeIdx); 248 break; 249 default: 250 throw new IllegalArgumentException(type.toString()); 251 } 252 } 253 out.printf(" } else {\n"); 254 out.printf(" assert b.canDeferPlugin(this) : b.getClass().toString();\n"); 255 out.printf(" return false;\n"); 256 out.printf(" }\n"); 257 } 258 }