GeneratedPlugin.java revision 12657:6ef01bd40ce2
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 DECLARED:
234                    out.printf("                arg%d = %s.asObject(%s.class, args[%d].asJavaConstant());\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION), getErasedType(type), nodeIdx);
235                    break;
236                default:
237                    throw new IllegalArgumentException();
238            }
239        }
240        out.printf("            } else {\n");
241        out.printf("                return false;\n");
242        out.printf("            }\n");
243    }
244}
245