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.util.HashMap;
26import java.util.Iterator;
27
28import javax.annotation.processing.ProcessingEnvironment;
29import javax.lang.model.element.ExecutableElement;
30import javax.lang.model.type.DeclaredType;
31import javax.lang.model.type.TypeMirror;
32
33import org.graalvm.compiler.graph.Node.NodeIntrinsic;
34import org.graalvm.compiler.replacements.verifier.InjectedDependencies.Dependency;
35
36public class InjectedDependencies implements Iterable<Dependency> {
37
38    public abstract static class Dependency {
39
40        public final String name;
41        public final String type;
42
43        private Dependency(String name, String type) {
44            this.name = name;
45            this.type = type;
46        }
47
48        public abstract String inject(ExecutableElement inject);
49    }
50
51    private static final class InjectedDependency extends Dependency {
52
53        private InjectedDependency(String name, String type) {
54            super(name, type);
55        }
56
57        @Override
58        public String inject(ExecutableElement inject) {
59            return String.format("injection.getInjectedArgument(%s.class)", type);
60        }
61    }
62
63    private static final class InjectedStampDependency extends Dependency {
64
65        private InjectedStampDependency() {
66            super("stamp", "org.graalvm.compiler.core.common.type.Stamp");
67        }
68
69        @Override
70        public String inject(ExecutableElement inject) {
71            NodeIntrinsic nodeIntrinsic = inject.getAnnotation(NodeIntrinsic.class);
72            boolean nonNull = nodeIntrinsic != null && nodeIntrinsic.injectedStampIsNonNull();
73            return String.format("injection.getInjectedStamp(%s.class, %s)", GeneratedPlugin.getErasedType(inject.getReturnType()), nonNull);
74        }
75    }
76
77    public enum WellKnownDependency {
78        CONSTANT_REFLECTION("b.getConstantReflection()", "jdk.vm.ci.meta.ConstantReflectionProvider"),
79        META_ACCESS("b.getMetaAccess()", "jdk.vm.ci.meta.MetaAccessProvider"),
80        INJECTED_STAMP(new InjectedStampDependency()),
81        SNIPPET_REFLECTION(new InjectedDependency("snippetReflection", "org.graalvm.compiler.api.replacements.SnippetReflectionProvider")),
82        STAMP_PROVIDER("b.getStampProvider()", "org.graalvm.compiler.nodes.spi.StampProvider"),
83        STRUCTURED_GRAPH("b.getGraph()", "org.graalvm.compiler.nodes.StructuredGraph");
84
85        private final String expr;
86        private final String type;
87        private final Dependency generateMember;
88
89        WellKnownDependency(String expr, String type) {
90            this.expr = expr;
91            this.type = type;
92            this.generateMember = null;
93        }
94
95        WellKnownDependency(Dependency generateMember) {
96            this.expr = generateMember.name;
97            this.type = generateMember.type;
98            this.generateMember = generateMember;
99        }
100
101        private TypeMirror getType(ProcessingEnvironment env) {
102            return env.getElementUtils().getTypeElement(type).asType();
103        }
104    }
105
106    private final HashMap<String, Dependency> deps;
107
108    public InjectedDependencies() {
109        deps = new HashMap<>();
110    }
111
112    public String use(WellKnownDependency wellKnown) {
113        if (wellKnown.generateMember != null) {
114            deps.put(wellKnown.type, wellKnown.generateMember);
115        }
116        return wellKnown.expr;
117    }
118
119    public String use(ProcessingEnvironment env, DeclaredType type) {
120        for (WellKnownDependency wellKnown : WellKnownDependency.values()) {
121            if (env.getTypeUtils().isAssignable(wellKnown.getType(env), type)) {
122                return use(wellKnown);
123            }
124        }
125
126        String typeName = type.toString();
127        Dependency ret = deps.get(typeName);
128        if (ret == null) {
129            ret = new InjectedDependency("injected" + type.asElement().getSimpleName(), typeName);
130            deps.put(typeName, ret);
131        }
132        return ret.name;
133    }
134
135    @Override
136    public Iterator<Dependency> iterator() {
137        return deps.values().iterator();
138    }
139
140    public boolean isEmpty() {
141        return deps.isEmpty();
142    }
143}
144