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.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 InjectedDependencies deps = createExecute(processor, out); 77 out.printf(" }\n"); 78 out.printf(" @Override\n"); 79 out.printf(" public Class<? extends Annotation> getSource() {\n"); 80 out.printf(" return %s.class;\n", getAnnotationClass(processor).getQualifiedName().toString().replace('$', '.')); 81 out.printf(" }\n"); 82 83 createPrivateMembers(processor, out, deps); 84 85 out.printf("}\n"); 86 } 87 88 public void register(PrintWriter out) { 89 out.printf(" plugins.register(new %s(", pluginName); 90 if (needInjectionProvider) { 91 out.printf("injection"); 92 } 93 out.printf("), %s.class, \"%s\"", intrinsicMethod.getEnclosingElement(), intrinsicMethod.getSimpleName()); 94 if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) { 95 out.printf(", InvocationPlugin.Receiver.class"); 96 } 97 for (VariableElement arg : intrinsicMethod.getParameters()) { 98 out.printf(", %s.class", getErasedType(arg.asType())); 99 } 100 out.printf(");\n"); 101 } 102 103 public abstract void extraImports(Set<String> imports); 104 105 protected abstract InjectedDependencies createExecute(AbstractProcessor processor, PrintWriter out); 106 107 static String getErasedType(TypeMirror type) { 108 switch (type.getKind()) { 109 case DECLARED: 110 DeclaredType declared = (DeclaredType) type; 111 TypeElement element = (TypeElement) declared.asElement(); 112 return element.getQualifiedName().toString(); 113 case TYPEVAR: 114 return getErasedType(((TypeVariable) type).getUpperBound()); 115 case WILDCARD: 116 return getErasedType(((WildcardType) type).getExtendsBound()); 117 case ARRAY: 118 return getErasedType(((ArrayType) type).getComponentType()) + "[]"; 119 default: 120 return type.toString(); 121 } 122 } 123 124 static boolean hasRawtypeWarning(TypeMirror type) { 125 switch (type.getKind()) { 126 case DECLARED: 127 DeclaredType declared = (DeclaredType) type; 128 return declared.getTypeArguments().size() > 0; 129 case TYPEVAR: 130 return false; 131 case WILDCARD: 132 return false; 133 case ARRAY: 134 return hasRawtypeWarning(((ArrayType) type).getComponentType()); 135 default: 136 return false; 137 } 138 } 139 140 static boolean hasUncheckedWarning(TypeMirror type) { 141 switch (type.getKind()) { 142 case DECLARED: 143 DeclaredType declared = (DeclaredType) type; 144 for (TypeMirror typeParam : declared.getTypeArguments()) { 145 if (hasUncheckedWarning(typeParam)) { 146 return true; 147 } 148 } 149 return false; 150 case TYPEVAR: 151 return true; 152 case WILDCARD: 153 return ((WildcardType) type).getExtendsBound() != null; 154 case ARRAY: 155 return hasUncheckedWarning(((ArrayType) type).getComponentType()); 156 default: 157 return false; 158 } 159 } 160 161 private void createPrivateMembers(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps) { 162 if (!deps.isEmpty()) { 163 out.printf("\n"); 164 for (Dependency dep : deps) { 165 out.printf(" private final %s %s;\n", dep.type, dep.name); 166 } 167 168 out.printf("\n"); 169 out.printf(" %s(NodeIntrinsicPluginFactory.InjectionProvider injection) {\n", pluginName); 170 for (Dependency dep : deps) { 171 out.printf(" this.%s = %s;\n", dep.name, dep.inject(processor, intrinsicMethod)); 172 } 173 out.printf(" }\n"); 174 175 needInjectionProvider = true; 176 } 177 } 178 179 protected static String getReturnKind(ExecutableElement method) { 180 switch (method.getReturnType().getKind()) { 181 case BOOLEAN: 182 case BYTE: 183 case SHORT: 184 case CHAR: 185 case INT: 186 return "Int"; 187 case LONG: 188 return "Long"; 189 case FLOAT: 190 return "Float"; 191 case DOUBLE: 192 return "Double"; 193 case VOID: 194 return "Void"; 195 case ARRAY: 196 case TYPEVAR: 197 case DECLARED: 198 return "Object"; 199 default: 200 throw new IllegalArgumentException(method.getReturnType().toString()); 201 } 202 } 203 204 protected static void constantArgument(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps, int argIdx, TypeMirror type, int nodeIdx) { 205 if (hasRawtypeWarning(type)) { 206 out.printf(" @SuppressWarnings({\"rawtypes\"})\n"); 207 } 208 out.printf(" %s arg%d;\n", getErasedType(type), argIdx); 209 out.printf(" if (args[%d].isConstant()) {\n", nodeIdx); 210 if (type.equals(processor.getType("jdk.vm.ci.meta.ResolvedJavaType"))) { 211 out.printf(" arg%d = %s.asJavaType(args[%d].asConstant());\n", argIdx, deps.use(WellKnownDependency.CONSTANT_REFLECTION), nodeIdx); 212 } else { 213 switch (type.getKind()) { 214 case BOOLEAN: 215 out.printf(" arg%d = args[%d].asJavaConstant().asInt() != 0;\n", argIdx, nodeIdx); 216 break; 217 case BYTE: 218 out.printf(" arg%d = (byte) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); 219 break; 220 case CHAR: 221 out.printf(" arg%d = (char) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); 222 break; 223 case SHORT: 224 out.printf(" arg%d = (short) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); 225 break; 226 case INT: 227 out.printf(" arg%d = args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); 228 break; 229 case LONG: 230 out.printf(" arg%d = args[%d].asJavaConstant().asLong();\n", argIdx, nodeIdx); 231 break; 232 case FLOAT: 233 out.printf(" arg%d = args[%d].asJavaConstant().asFloat();\n", argIdx, nodeIdx); 234 break; 235 case DOUBLE: 236 out.printf(" arg%d = args[%d].asJavaConstant().asDouble();\n", argIdx, nodeIdx); 237 break; 238 case ARRAY: 239 case DECLARED: 240 out.printf(" arg%d = %s.asObject(%s.class, args[%d].asJavaConstant());\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION), getErasedType(type), nodeIdx); 241 break; 242 default: 243 throw new IllegalArgumentException(type.toString()); 244 } 245 } 246 out.printf(" } else {\n"); 247 out.printf(" assert b.canDeferPlugin(this) : b.getClass().toString();\n"); 248 out.printf(" return false;\n"); 249 out.printf(" }\n"); 250 } 251 }