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