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