1/* 2 * Copyright (c) 1998, 2011, 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 com.sun.jdi.*; 29 30import java.util.*; 31 32final public class ClassTypeImpl extends InvokableTypeImpl 33 implements ClassType 34{ 35 private static class IResult implements InvocationResult { 36 final private JDWP.ClassType.InvokeMethod rslt; 37 38 public IResult(JDWP.ClassType.InvokeMethod rslt) { 39 this.rslt = rslt; 40 } 41 42 @Override 43 public ObjectReferenceImpl getException() { 44 return rslt.exception; 45 } 46 47 @Override 48 public ValueImpl getResult() { 49 return rslt.returnValue; 50 } 51 } 52 53 private boolean cachedSuperclass = false; 54 private ClassType superclass = null; 55 private int lastLine = -1; 56 private List<InterfaceType> interfaces = null; 57 58 protected ClassTypeImpl(VirtualMachine aVm,long aRef) { 59 super(aVm, aRef); 60 } 61 62 public ClassType superclass() { 63 if(!cachedSuperclass) { 64 ClassTypeImpl sup = null; 65 try { 66 sup = JDWP.ClassType.Superclass. 67 process(vm, this).superclass; 68 } catch (JDWPException exc) { 69 throw exc.toJDIException(); 70 } 71 72 /* 73 * If there is a superclass, cache its 74 * ClassType here. Otherwise, 75 * leave the cache reference null. 76 */ 77 if (sup != null) { 78 superclass = sup; 79 } 80 cachedSuperclass = true; 81 } 82 83 return superclass; 84 } 85 86 @Override 87 public List<InterfaceType> interfaces() { 88 if (interfaces == null) { 89 interfaces = getInterfaces(); 90 } 91 return interfaces; 92 } 93 94 @Override 95 public List<InterfaceType> allInterfaces() { 96 return getAllInterfaces(); 97 } 98 99 public List<ClassType> subclasses() { 100 List<ClassType> subs = new ArrayList<ClassType>(); 101 for (ReferenceType refType : vm.allClasses()) { 102 if (refType instanceof ClassType) { 103 ClassType clazz = (ClassType)refType; 104 ClassType superclass = clazz.superclass(); 105 if ((superclass != null) && superclass.equals(this)) { 106 subs.add((ClassType)refType); 107 } 108 } 109 } 110 111 return subs; 112 } 113 114 public boolean isEnum() { 115 ClassType superclass = superclass(); 116 if (superclass != null && 117 superclass.name().equals("java.lang.Enum")) { 118 return true; 119 } 120 return false; 121 } 122 123 public void setValue(Field field, Value value) 124 throws InvalidTypeException, ClassNotLoadedException { 125 126 validateMirror(field); 127 validateMirrorOrNull(value); 128 validateFieldSet(field); 129 130 // More validation specific to setting from a ClassType 131 if(!field.isStatic()) { 132 throw new IllegalArgumentException( 133 "Must set non-static field through an instance"); 134 } 135 136 try { 137 JDWP.ClassType.SetValues.FieldValue[] values = 138 new JDWP.ClassType.SetValues.FieldValue[1]; 139 values[0] = new JDWP.ClassType.SetValues.FieldValue( 140 ((FieldImpl)field).ref(), 141 // validate and convert if necessary 142 ValueImpl.prepareForAssignment(value, (FieldImpl)field)); 143 144 try { 145 JDWP.ClassType.SetValues.process(vm, this, values); 146 } catch (JDWPException exc) { 147 throw exc.toJDIException(); 148 } 149 } catch (ClassNotLoadedException e) { 150 /* 151 * Since we got this exception, 152 * the field type must be a reference type. The value 153 * we're trying to set is null, but if the field's 154 * class has not yet been loaded through the enclosing 155 * class loader, then setting to null is essentially a 156 * no-op, and we should allow it without an exception. 157 */ 158 if (value != null) { 159 throw e; 160 } 161 } 162 } 163 164 PacketStream sendNewInstanceCommand(final ThreadReferenceImpl thread, 165 final MethodImpl method, 166 final ValueImpl[] args, 167 final int options) { 168 CommandSender sender = 169 new CommandSender() { 170 public PacketStream send() { 171 return JDWP.ClassType.NewInstance.enqueueCommand( 172 vm, ClassTypeImpl.this, thread, 173 method.ref(), args, options); 174 } 175 }; 176 177 PacketStream stream; 178 if ((options & INVOKE_SINGLE_THREADED) != 0) { 179 stream = thread.sendResumingCommand(sender); 180 } else { 181 stream = vm.sendResumingCommand(sender); 182 } 183 return stream; 184 } 185 186 public ObjectReference newInstance(ThreadReference threadIntf, 187 Method methodIntf, 188 List<? extends Value> origArguments, 189 int options) 190 throws InvalidTypeException, 191 ClassNotLoadedException, 192 IncompatibleThreadStateException, 193 InvocationException { 194 validateMirror(threadIntf); 195 validateMirror(methodIntf); 196 validateMirrorsOrNulls(origArguments); 197 198 MethodImpl method = (MethodImpl)methodIntf; 199 ThreadReferenceImpl thread = (ThreadReferenceImpl)threadIntf; 200 201 validateConstructorInvocation(method); 202 203 List<Value> arguments = method.validateAndPrepareArgumentsForInvoke( 204 origArguments); 205 ValueImpl[] args = arguments.toArray(new ValueImpl[0]); 206 JDWP.ClassType.NewInstance ret = null; 207 try { 208 PacketStream stream = 209 sendNewInstanceCommand(thread, method, args, options); 210 ret = JDWP.ClassType.NewInstance.waitForReply(vm, stream); 211 } catch (JDWPException exc) { 212 if (exc.errorCode() == JDWP.Error.INVALID_THREAD) { 213 throw new IncompatibleThreadStateException(); 214 } else { 215 throw exc.toJDIException(); 216 } 217 } 218 219 /* 220 * There is an implict VM-wide suspend at the conclusion 221 * of a normal (non-single-threaded) method invoke 222 */ 223 if ((options & INVOKE_SINGLE_THREADED) == 0) { 224 vm.notifySuspend(); 225 } 226 227 if (ret.exception != null) { 228 throw new InvocationException(ret.exception); 229 } else { 230 return ret.newObject; 231 } 232 } 233 234 public Method concreteMethodByName(String name, String signature) { 235 Method method = null; 236 for (Method candidate : visibleMethods()) { 237 if (candidate.name().equals(name) && 238 candidate.signature().equals(signature) && 239 !candidate.isAbstract()) { 240 241 method = candidate; 242 break; 243 } 244 } 245 return method; 246 } 247 248 void validateConstructorInvocation(Method method) 249 throws InvalidTypeException, 250 InvocationException { 251 /* 252 * Method must be in this class. 253 */ 254 ReferenceTypeImpl declType = (ReferenceTypeImpl)method.declaringType(); 255 if (!declType.equals(this)) { 256 throw new IllegalArgumentException("Invalid constructor"); 257 } 258 259 /* 260 * Method must be a constructor 261 */ 262 if (!method.isConstructor()) { 263 throw new IllegalArgumentException("Cannot create instance with non-constructor"); 264 } 265 } 266 267 268 public String toString() { 269 return "class " + name() + " (" + loaderString() + ")"; 270 } 271 272 @Override 273 CommandSender getInvokeMethodSender(ThreadReferenceImpl thread, 274 MethodImpl method, 275 ValueImpl[] args, 276 int options) { 277 return () -> 278 JDWP.ClassType.InvokeMethod.enqueueCommand(vm, 279 ClassTypeImpl.this, 280 thread, 281 method.ref(), 282 args, 283 options); 284 } 285 286 @Override 287 InvocationResult waitForReply(PacketStream stream) throws JDWPException { 288 return new IResult(JDWP.ClassType.InvokeMethod.waitForReply(vm, stream)); 289 } 290 291 @Override 292 boolean canInvoke(Method method) { 293 // Method must be in this class or a superclass. 294 return ((ReferenceTypeImpl)method.declaringType()).isAssignableFrom(this); 295 } 296} 297