1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dx.rop.cst;
18 
19 import com.android.dx.rop.type.Prototype;
20 import com.android.dx.rop.type.Type;
21 import java.util.ArrayList;
22 import java.util.List;
23 
24 /**
25  * Constants of type {@code InvokeDynamic}. These are present in the class file.
26  */
27 public final class CstInvokeDynamic extends Constant {
28 
29     /** The index of the bootstrap method in the bootstrap method table */
30     private final int bootstrapMethodIndex;
31 
32     /** {@code non-null;} the name and type */
33     private final CstNat nat;
34 
35     /** {@code non-null;} the prototype derived from {@code nat} */
36     private final Prototype prototype;
37 
38     /** {@code null-ok;} the class declaring invoke dynamic instance */
39     private CstType declaringClass;
40 
41     /** {@code null-ok;} the associated call site */
42     private CstCallSite callSite;
43 
44     /** {@code non-null;} list of references to this {@code CstInvokeDynamic} constant */
45     private final List<CstCallSiteRef> references;
46 
47     /**
48      * Makes an instance for the given value. This may (but does not
49      * necessarily) return an already-allocated instance.
50      *
51      * @param bootstrapMethodIndex The index of the bootstrap method in the bootstrap method table
52      * @param nat the name and type
53      * @return {@code non-null;} the appropriate instance
54      */
make(int bootstrapMethodIndex, CstNat nat)55     public static CstInvokeDynamic make(int bootstrapMethodIndex, CstNat nat) {
56         return new CstInvokeDynamic(bootstrapMethodIndex, nat);
57     }
58 
59     /**
60      * Constructs an instance. This constructor is private; use {@link #make}.
61      *
62      * @param bootstrapMethodIndex The index of the bootstrap method in the bootstrap method table
63      * @param nat the name and type
64      */
CstInvokeDynamic(int bootstrapMethodIndex, CstNat nat)65     private CstInvokeDynamic(int bootstrapMethodIndex, CstNat nat) {
66         this.bootstrapMethodIndex = bootstrapMethodIndex;
67         this.nat = nat;
68         this.prototype = Prototype.fromDescriptor(nat.getDescriptor().toHuman());
69         this.references = new ArrayList<>();
70     }
71 
72     /**
73      * Creates a {@code CstCallSiteRef} that refers to this instance.
74      *
75      * @return {@code non-null;} a reference to this instance
76      */
addReference()77     public CstCallSiteRef addReference() {
78         CstCallSiteRef ref = new CstCallSiteRef(this, references.size());
79         references.add(ref);
80         return ref;
81     }
82 
83     /**
84      * Gets the list of references to this instance.
85      *
86      * @return {@code non-null;} the list of references to this instance
87      */
getReferences()88     public List<CstCallSiteRef> getReferences() {
89         return references;
90     }
91 
92     /** {@inheritDoc} */
93     @Override
toString()94     public String toString() {
95         return toHuman();
96     }
97 
98     /** {@inheritDoc} */
99     @Override
typeName()100     public String typeName() {
101         return "InvokeDynamic";
102     }
103 
104     /** {@inheritDoc} */
105     @Override
toHuman()106     public String toHuman() {
107         String klass = (declaringClass != null) ? declaringClass.toHuman() : "Unknown";
108         return "InvokeDynamic(" + klass + ":" + bootstrapMethodIndex + ", " + nat.toHuman() + ")";
109     }
110 
111     /** {@inheritDoc} */
112     @Override
isCategory2()113     public boolean isCategory2() {
114         return false;
115     }
116 
117     /** {@inheritDoc} */
118     @Override
compareTo0(Constant other)119     protected int compareTo0(Constant other) {
120         CstInvokeDynamic otherInvoke = (CstInvokeDynamic) other;
121         int result = Integer.compare(bootstrapMethodIndex, otherInvoke.getBootstrapMethodIndex());
122         if (result != 0) {
123             return result;
124         }
125 
126         result = nat.compareTo(otherInvoke.getNat());
127         if (result != 0) {
128             return result;
129         }
130 
131         result = declaringClass.compareTo(otherInvoke.getDeclaringClass());
132         if (result != 0) {
133             return result;
134         }
135 
136         return callSite.compareTo(otherInvoke.getCallSite());
137     }
138 
139     /**
140      * Gets the bootstrap method index.
141      *
142      * @return the bootstrap method index
143      */
getBootstrapMethodIndex()144     public int getBootstrapMethodIndex() {
145         return bootstrapMethodIndex;
146     }
147 
148     /**
149      * Gets the {@code CstNat} value.
150      *
151      * @return the name and type
152      */
getNat()153     public CstNat getNat() {
154         return nat;
155     }
156 
157     /**
158      * Gets the {@code Prototype} of the {@code invokedynamic} call site.
159      *
160      * @return the {@code invokedynamic} call site prototype
161      */
getPrototype()162     public Prototype getPrototype() {
163         return prototype;
164     }
165 
166     /**
167      * Gets the return type.
168      *
169      * @return {@code non-null;} the return type
170      */
getReturnType()171     public Type getReturnType() {
172         return prototype.getReturnType();
173     }
174 
175     /**
176      * Sets the declaring class of this instance.
177      *
178      * This is a set-once property.
179      *
180      * @param declaringClass {@code non-null;} the declaring class
181      */
setDeclaringClass(CstType declaringClass)182     public void setDeclaringClass(CstType declaringClass) {
183         if (this.declaringClass != null) {
184             throw new IllegalArgumentException("already added declaring class");
185         } else if (declaringClass == null) {
186             throw new NullPointerException("declaringClass == null");
187         }
188         this.declaringClass = declaringClass;
189     }
190 
191     /**
192      * Gets the declaring class of this instance.
193      *
194      * @return the declaring class
195      */
getDeclaringClass()196     public CstType getDeclaringClass() {
197         return declaringClass;
198     }
199 
200     /**
201      * Sets the call site associated with this instance.
202      *
203      * This is set-once property.
204      *
205      * @param callSite {@code non-null;} the call site created for this instance
206      */
setCallSite(CstCallSite callSite)207     public void setCallSite(CstCallSite callSite) {
208         if (this.callSite != null) {
209             throw new IllegalArgumentException("already added call site");
210         } else if (callSite == null) {
211             throw new NullPointerException("callSite == null");
212         }
213         this.callSite = callSite;
214     }
215 
216     /**
217      * Gets the call site associated with this instance.
218      *
219      * @return the call site associated with this instance
220      */
getCallSite()221     public CstCallSite getCallSite() {
222         return callSite;
223     }
224 }
225