1/* 2 * Copyright (c) 2014, 2017, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.jdi; 27 28import java.util.ArrayList; 29import java.util.Iterator; 30import java.util.List; 31import java.util.Map; 32import java.util.Set; 33 34import com.sun.jdi.ClassNotLoadedException; 35import com.sun.jdi.ClassType; 36import com.sun.jdi.IncompatibleThreadStateException; 37import com.sun.jdi.InterfaceType; 38import com.sun.jdi.InvalidTypeException; 39import com.sun.jdi.InvocationException; 40import com.sun.jdi.Method; 41import com.sun.jdi.ReferenceType; 42import com.sun.jdi.ThreadReference; 43import com.sun.jdi.VMCannotBeModifiedException; 44import com.sun.jdi.Value; 45import com.sun.jdi.VirtualMachine; 46 47/** 48 * A supertype for ReferenceTypes allowing method invocations 49 */ 50abstract class InvokableTypeImpl extends ReferenceTypeImpl { 51 52 /** 53 * The invocation result wrapper 54 * It is necessary because both ClassType and InterfaceType 55 * use their own type to represent the invocation result 56 */ 57 static interface InvocationResult { 58 ObjectReferenceImpl getException(); 59 ValueImpl getResult(); 60 } 61 62 InvokableTypeImpl(VirtualMachine aVm, long aRef) { 63 super(aVm, aRef); 64 } 65 66 /** 67 * Method invocation support. 68 * Shared by ClassType and InterfaceType 69 * @param threadIntf the thread in which to invoke. 70 * @param methodIntf method the {@link Method} to invoke. 71 * @param origArguments the list of {@link Value} arguments bound to the 72 * invoked method. Values from the list are assigned to arguments 73 * in the order they appear in the method signature. 74 * @param options the integer bit flag options. 75 * @return a {@link Value} mirror of the invoked method's return value. 76 * @throws java.lang.IllegalArgumentException if the method is not 77 * a member of this type, if the size of the argument list 78 * does not match the number of declared arguments for the method, or 79 * if the method is not static or is a static initializer. 80 * @throws InvalidTypeException if any argument in the 81 * argument list is not assignable to the corresponding method argument 82 * type. 83 * @throws ClassNotLoadedException if any argument type has not yet been loaded 84 * through the appropriate class loader. 85 * @throws IncompatibleThreadStateException if the specified thread has not 86 * been suspended by an event. 87 * @throws InvocationException if the method invocation resulted in 88 * an exception in the target VM. 89 * @throws InvalidTypeException If the arguments do not meet this requirement -- 90 * Object arguments must be assignment compatible with the argument 91 * type. This implies that the argument type must be 92 * loaded through the enclosing class's class loader. 93 * Primitive arguments must be either assignment compatible with the 94 * argument type or must be convertible to the argument type without loss 95 * of information. See JLS section 5.2 for more information on assignment 96 * compatibility. 97 * @throws VMCannotBeModifiedException if the VirtualMachine is read-only - see {@link VirtualMachine#canBeModified()}. 98 */ 99 final public Value invokeMethod(ThreadReference threadIntf, Method methodIntf, 100 List<? extends Value> origArguments, int options) 101 throws InvalidTypeException, 102 ClassNotLoadedException, 103 IncompatibleThreadStateException, 104 InvocationException { 105 validateMirror(threadIntf); 106 validateMirror(methodIntf); 107 validateMirrorsOrNulls(origArguments); 108 MethodImpl method = (MethodImpl) methodIntf; 109 ThreadReferenceImpl thread = (ThreadReferenceImpl) threadIntf; 110 validateMethodInvocation(method); 111 List<? extends Value> arguments = method.validateAndPrepareArgumentsForInvoke(origArguments); 112 ValueImpl[] args = arguments.toArray(new ValueImpl[0]); 113 InvocationResult ret; 114 try { 115 PacketStream stream = sendInvokeCommand(thread, method, args, options); 116 ret = waitForReply(stream); 117 } catch (JDWPException exc) { 118 if (exc.errorCode() == JDWP.Error.INVALID_THREAD) { 119 throw new IncompatibleThreadStateException(); 120 } else { 121 throw exc.toJDIException(); 122 } 123 } 124 /* 125 * There is an implict VM-wide suspend at the conclusion 126 * of a normal (non-single-threaded) method invoke 127 */ 128 if ((options & ClassType.INVOKE_SINGLE_THREADED) == 0) { 129 vm.notifySuspend(); 130 } 131 if (ret.getException() != null) { 132 throw new InvocationException(ret.getException()); 133 } else { 134 return ret.getResult(); 135 } 136 } 137 138 @Override 139 boolean isAssignableTo(ReferenceType type) { 140 ClassTypeImpl superclazz = (ClassTypeImpl) superclass(); 141 if (this.equals(type)) { 142 return true; 143 } else if ((superclazz != null) && superclazz.isAssignableTo(type)) { 144 return true; 145 } else { 146 List<InterfaceType> interfaces = interfaces(); 147 Iterator<InterfaceType> iter = interfaces.iterator(); 148 while (iter.hasNext()) { 149 InterfaceTypeImpl interfaze = (InterfaceTypeImpl) iter.next(); 150 if (interfaze.isAssignableTo(type)) { 151 return true; 152 } 153 } 154 return false; 155 } 156 } 157 158 @Override 159 final void addVisibleMethods(Map<String, Method> methodMap, Set<InterfaceType> seenInterfaces) { 160 /* 161 * Add methods from 162 * parent types first, so that the methods in this class will 163 * overwrite them in the hash table 164 */ 165 Iterator<InterfaceType> iter = interfaces().iterator(); 166 while (iter.hasNext()) { 167 InterfaceTypeImpl interfaze = (InterfaceTypeImpl) iter.next(); 168 if (!seenInterfaces.contains(interfaze)) { 169 interfaze.addVisibleMethods(methodMap, seenInterfaces); 170 seenInterfaces.add(interfaze); 171 } 172 } 173 ClassTypeImpl clazz = (ClassTypeImpl) superclass(); 174 if (clazz != null) { 175 clazz.addVisibleMethods(methodMap, seenInterfaces); 176 } 177 addToMethodMap(methodMap, methods()); 178 } 179 180 final void addInterfaces(List<InterfaceType> list) { 181 List<InterfaceType> immediate = interfaces(); 182 list.addAll(interfaces()); 183 Iterator<InterfaceType> iter = immediate.iterator(); 184 while (iter.hasNext()) { 185 InterfaceTypeImpl interfaze = (InterfaceTypeImpl) iter.next(); 186 interfaze.addInterfaces(list); 187 } 188 ClassTypeImpl superclass = (ClassTypeImpl) superclass(); 189 if (superclass != null) { 190 superclass.addInterfaces(list); 191 } 192 } 193 194 /** 195 * Returns all the implemented interfaces recursively 196 * @return A list of all the implemented interfaces (recursively) 197 */ 198 final List<InterfaceType> getAllInterfaces() { 199 List<InterfaceType> all = new ArrayList<>(); 200 addInterfaces(all); 201 return all; 202 } 203 204 /** 205 * Shared implementation of {@linkplain ClassType#allMethods()} and 206 * {@linkplain InterfaceType#allMethods()} 207 * @return A list of all methods (recursively) 208 */ 209 public final List<Method> allMethods() { 210 ArrayList<Method> list = new ArrayList<>(methods()); 211 ClassType clazz = superclass(); 212 while (clazz != null) { 213 list.addAll(clazz.methods()); 214 clazz = clazz.superclass(); 215 } 216 /* 217 * Avoid duplicate checking on each method by iterating through 218 * duplicate-free allInterfaces() rather than recursing 219 */ 220 for (InterfaceType interfaze : getAllInterfaces()) { 221 list.addAll(interfaze.methods()); 222 } 223 return list; 224 } 225 226 @Override 227 final List<ReferenceType> inheritedTypes() { 228 List<ReferenceType> inherited = new ArrayList<>(); 229 if (superclass() != null) { 230 inherited.add(0, superclass()); /* insert at front */ 231 } 232 for (ReferenceType rt : interfaces()) { 233 inherited.add(rt); 234 } 235 return inherited; 236 } 237 238 private PacketStream sendInvokeCommand(final ThreadReferenceImpl thread, 239 final MethodImpl method, 240 final ValueImpl[] args, 241 final int options) { 242 /* 243 * Cache the values of args when TRACE_SENDS is enabled, for later printing. 244 * If not cached, printing causes a remote call while synchronized, and deadlock. 245 */ 246 if ((vm.traceFlags & VirtualMachine.TRACE_SENDS) != 0) { 247 for (ValueImpl arg: args) { 248 arg.toString(); 249 } 250 } 251 CommandSender sender = getInvokeMethodSender(thread, method, args, options); 252 PacketStream stream; 253 if ((options & ClassType.INVOKE_SINGLE_THREADED) != 0) { 254 stream = thread.sendResumingCommand(sender); 255 } else { 256 stream = vm.sendResumingCommand(sender); 257 } 258 return stream; 259 } 260 261 private void validateMethodInvocation(Method method) 262 throws InvalidTypeException, 263 InvocationException { 264 if (!canInvoke(method)) { 265 throw new IllegalArgumentException("Invalid method"); 266 } 267 /* 268 * Method must be a static and not a static initializer 269 */ 270 if (!method.isStatic()) { 271 throw new IllegalArgumentException("Cannot invoke instance method on a class/interface type"); 272 } else if (method.isStaticInitializer()) { 273 throw new IllegalArgumentException("Cannot invoke static initializer"); 274 } 275 } 276 277 /** 278 * A subclass will provide specific {@linkplain CommandSender} 279 * @param thread the current invocation thread 280 * @param method the method to invoke 281 * @param args the arguments to pass to the method 282 * @param options the integer bit flag options 283 * @return the specific {@literal CommandSender} instance 284 */ 285 abstract CommandSender getInvokeMethodSender(ThreadReferenceImpl thread, 286 MethodImpl method, 287 ValueImpl[] args, 288 int options); 289 290 /** 291 * Waits for the reply to the last sent command 292 * @param stream the stream to listen for the reply on 293 * @return the {@linkplain InvocationResult} instance 294 * @throws JDWPException when something goes wrong in JDWP 295 */ 296 abstract InvocationResult waitForReply(PacketStream stream) throws JDWPException; 297 298 /** 299 * Get the {@linkplain ReferenceType} superclass 300 * @return the superclass or null 301 */ 302 abstract ClassType superclass(); 303 304 /** 305 * Get the implemented/extended interfaces 306 * @return the list of implemented/extended interfaces 307 */ 308 abstract List<InterfaceType> interfaces(); 309 310 /** 311 * Checks the provided method whether it can be invoked 312 * @param method the method to check 313 * @return {@code TRUE} if the implementation knows how to invoke the method, 314 * {@code FALSE} otherwise 315 */ 316 abstract boolean canInvoke(Method method); 317} 318