Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/jdi/ConnectorImpl.java @ 2245:638119ce7cfd
7009309: JSR 292: compiler/6991596/Test6991596.java crashes on fastdebug JDK7/b122
Reviewed-by: kvn, never
author | twisti |
---|---|
date | Tue, 01 Feb 2011 03:38:44 -0800 |
parents | c18cbe5936b8 |
children | 37be97a58393 |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
2 * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
25 package sun.jvm.hotspot.jdi; | |
26 | |
27 import com.sun.jdi.connect.*; | |
28 import com.sun.jdi.InternalException; | |
29 | |
30 import java.io.*; | |
31 import java.lang.ref.*; | |
32 import java.lang.reflect.*; | |
33 import java.util.*; | |
34 | |
35 abstract class ConnectorImpl implements Connector { | |
36 Map defaultArguments = new LinkedHashMap(); | |
37 | |
38 // Used by BooleanArgument | |
39 static String trueString = null; | |
40 static String falseString; | |
41 | |
42 | |
43 /** This is not public in VirtualMachineManagerImpl | |
44 ThreadGroup mainGroupForJDI() { | |
45 return ((VirtualMachineManagerImpl)manager).mainGroupForJDI(); | |
46 } | |
47 ***/ | |
48 | |
49 // multiple debuggee support for SA/JDI | |
50 private static List freeVMClasses; // List<SoftReference<Class>> | |
51 private static ClassLoader myLoader; | |
52 // debug mode for SA/JDI connectors | |
53 static final protected boolean DEBUG; | |
54 static { | |
55 myLoader = ConnectorImpl.class.getClassLoader(); | |
56 freeVMClasses = new ArrayList(0); | |
57 DEBUG = System.getProperty("sun.jvm.hotspot.jdi.ConnectorImpl.DEBUG") != null; | |
58 } | |
59 | |
60 // add a new free VirtualMachineImpl class | |
61 private static synchronized void addFreeVMImplClass(Class clazz) { | |
62 if (DEBUG) { | |
63 System.out.println("adding free VirtualMachineImpl class"); | |
64 } | |
65 freeVMClasses.add(new SoftReference(clazz)); | |
66 } | |
67 | |
68 // returns null if we don't have anything free | |
69 private static synchronized Class getFreeVMImplClass() { | |
70 while (!freeVMClasses.isEmpty()) { | |
71 SoftReference ref = (SoftReference) freeVMClasses.remove(0); | |
72 Object o = ref.get(); | |
73 if (o != null) { | |
74 if (DEBUG) { | |
75 System.out.println("re-using loaded VirtualMachineImpl"); | |
76 } | |
77 return (Class) o; | |
78 } | |
79 } | |
80 return null; | |
81 } | |
82 | |
83 private static Class getVMImplClassFrom(ClassLoader cl) | |
84 throws ClassNotFoundException { | |
85 return Class.forName("sun.jvm.hotspot.jdi.VirtualMachineImpl", true, cl); | |
86 } | |
87 | |
88 /* SA has not been designed to support multiple debuggee VMs | |
89 * at-a-time. But, JDI supports multiple debuggee VMs. We | |
90 * support multiple debuggee VMs in SA/JDI, by creating a new | |
91 * class loader instance (refer to comment in SAJDIClassLoader | |
92 * for details). But, to avoid excessive class loading (and | |
93 * thereby resulting in larger footprint), we re-use 'dispose'd | |
94 * VirtualMachineImpl classes. | |
95 */ | |
96 protected static Class loadVirtualMachineImplClass() | |
97 throws ClassNotFoundException { | |
98 Class vmImplClass = getFreeVMImplClass(); | |
99 if (vmImplClass == null) { | |
100 ClassLoader cl = new SAJDIClassLoader(myLoader); | |
101 vmImplClass = getVMImplClassFrom(cl); | |
102 } | |
103 return vmImplClass; | |
104 } | |
105 | |
106 /* We look for System property sun.jvm.hotspot.jdi.<vm version>. | |
107 * This property should have the value of JDK HOME directory for | |
108 * the given <vm version>. | |
109 */ | |
110 private static String getSAClassPathForVM(String vmVersion) { | |
111 final String prefix = "sun.jvm.hotspot.jdi."; | |
112 // look for exact match of VM version | |
113 String jvmHome = System.getProperty(prefix + vmVersion); | |
114 if (DEBUG) { | |
115 System.out.println("looking for System property " + prefix + vmVersion); | |
116 } | |
117 | |
118 if (jvmHome == null) { | |
119 // omit chars after first '-' in VM version and try | |
120 // for example, in '1.5.0-b55' we take '1.5.0' | |
121 int index = vmVersion.indexOf('-'); | |
122 if (index != -1) { | |
123 vmVersion = vmVersion.substring(0, index); | |
124 if (DEBUG) { | |
125 System.out.println("looking for System property " + prefix + vmVersion); | |
126 } | |
127 jvmHome = System.getProperty(prefix + vmVersion); | |
128 } | |
129 | |
130 if (jvmHome == null) { | |
131 // System property is not set | |
132 if (DEBUG) { | |
133 System.out.println("can't locate JDK home for " + vmVersion); | |
134 } | |
135 return null; | |
136 } | |
137 } | |
138 | |
139 if (DEBUG) { | |
140 System.out.println("JDK home for " + vmVersion + " is " + jvmHome); | |
141 } | |
142 | |
143 // sa-jdi is in $JDK_HOME/lib directory | |
144 StringBuffer buf = new StringBuffer(); | |
145 buf.append(jvmHome); | |
146 buf.append(File.separatorChar); | |
147 buf.append("lib"); | |
148 buf.append(File.separatorChar); | |
149 buf.append("sa-jdi.jar"); | |
150 return buf.toString(); | |
151 } | |
152 | |
153 /* This method loads VirtualMachineImpl class by a ClassLoader | |
154 * configured with sa-jdi.jar path of given 'vmVersion'. This is | |
155 * used for cross VM version debugging. Refer to comments in | |
156 * SAJDIClassLoader as well. | |
157 */ | |
158 protected static Class loadVirtualMachineImplClass(String vmVersion) | |
159 throws ClassNotFoundException { | |
160 if (DEBUG) { | |
161 System.out.println("attemping to load sa-jdi.jar for version " + vmVersion); | |
162 } | |
163 String classPath = getSAClassPathForVM(vmVersion); | |
164 if (classPath != null) { | |
165 ClassLoader cl = new SAJDIClassLoader(myLoader, classPath); | |
166 return getVMImplClassFrom(cl); | |
167 } else { | |
168 return null; | |
169 } | |
170 } | |
171 | |
172 /* Is the given throwable an instanceof VMVersionMismatchException? | |
173 * Note that we can't do instanceof check because the exception | |
174 * class might have been loaded by a different class loader. | |
175 */ | |
176 private static boolean isVMVersionMismatch(Throwable throwable) { | |
177 String className = throwable.getClass().getName(); | |
178 return className.equals("sun.jvm.hotspot.runtime.VMVersionMismatchException"); | |
179 } | |
180 | |
181 /* gets target VM version from the given VMVersionMismatchException. | |
182 * Note that we need to reflectively call the method because of we may | |
183 * have got this from different classloader's namespace */ | |
184 private static String getVMVersion(Throwable throwable) | |
185 throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { | |
186 // assert isVMVersionMismatch(throwable), "not a VMVersionMismatch" | |
187 Class expClass = throwable.getClass(); | |
188 Method targetVersionMethod = expClass.getMethod("getTargetVersion", new Class[0]); | |
189 return (String) targetVersionMethod.invoke(throwable, null); | |
190 } | |
191 | |
192 /** If the causal chain has a sun.jvm.hotspot.runtime.VMVersionMismatchException, | |
193 attempt to load VirtualMachineImpl class for target VM version. */ | |
194 protected static Class handleVMVersionMismatch(InvocationTargetException ite) { | |
195 Throwable cause = ite.getCause(); | |
196 if (DEBUG) { | |
197 System.out.println("checking for version mismatch..."); | |
198 } | |
199 while (cause != null) { | |
200 try { | |
201 if (isVMVersionMismatch(cause)) { | |
202 if (DEBUG) { | |
203 System.out.println("Triggering cross VM version support..."); | |
204 } | |
205 return loadVirtualMachineImplClass(getVMVersion(cause)); | |
206 } | |
207 } catch (Exception exp) { | |
208 if (DEBUG) { | |
209 System.out.println("failed to load VirtualMachineImpl class"); | |
210 exp.printStackTrace(); | |
211 } | |
212 return null; | |
213 } | |
214 cause = cause.getCause(); | |
215 } | |
216 return null; | |
217 } | |
218 | |
219 protected void checkNativeLink(SecurityManager sm, String os) { | |
220 if (os.equals("SunOS") || os.equals("Linux")) { | |
221 // link "saproc" - SA native library on SunOS and Linux? | |
222 sm.checkLink("saproc"); | |
223 } else if (os.startsWith("Windows")) { | |
224 // link "sawindbg" - SA native library on Windows. | |
225 sm.checkLink("sawindbg"); | |
226 } else { | |
227 throw new RuntimeException(os + " is not yet supported"); | |
228 } | |
229 } | |
230 | |
231 // we set an observer to detect VirtualMachineImpl.dispose call | |
232 // and on dispose we add corresponding VirtualMachineImpl.class to | |
233 // free VirtualMachimeImpl Class list. | |
234 protected static void setVMDisposeObserver(final Object vm) { | |
235 try { | |
236 Method setDisposeObserverMethod = vm.getClass().getDeclaredMethod("setDisposeObserver", | |
237 new Class[] { java.util.Observer.class }); | |
238 setDisposeObserverMethod.setAccessible(true); | |
239 setDisposeObserverMethod.invoke(vm, | |
240 new Object[] { | |
241 new Observer() { | |
242 public void update(Observable o, Object data) { | |
243 if (DEBUG) { | |
244 System.out.println("got VM.dispose notification"); | |
245 } | |
246 addFreeVMImplClass(vm.getClass()); | |
247 } | |
248 } | |
249 }); | |
250 } catch (Exception exp) { | |
251 if (DEBUG) { | |
252 System.out.println("setVMDisposeObserver() got an exception:"); | |
253 exp.printStackTrace(); | |
254 } | |
255 } | |
256 } | |
257 | |
258 public Map defaultArguments() { | |
259 Map defaults = new LinkedHashMap(); | |
260 Collection values = defaultArguments.values(); | |
261 | |
262 Iterator iter = values.iterator(); | |
263 while (iter.hasNext()) { | |
264 ArgumentImpl argument = (ArgumentImpl)iter.next(); | |
265 defaults.put(argument.name(), argument.clone()); | |
266 } | |
267 return defaults; | |
268 } | |
269 | |
270 void addStringArgument(String name, String label, String description, | |
271 String defaultValue, boolean mustSpecify) { | |
272 defaultArguments.put(name, | |
273 new StringArgumentImpl(name, label, | |
274 description, | |
275 defaultValue, | |
276 mustSpecify)); | |
277 } | |
278 | |
279 void addBooleanArgument(String name, String label, String description, | |
280 boolean defaultValue, boolean mustSpecify) { | |
281 defaultArguments.put(name, | |
282 new BooleanArgumentImpl(name, label, | |
283 description, | |
284 defaultValue, | |
285 mustSpecify)); | |
286 } | |
287 | |
288 void addIntegerArgument(String name, String label, String description, | |
289 String defaultValue, boolean mustSpecify, | |
290 int min, int max) { | |
291 defaultArguments.put(name, | |
292 new IntegerArgumentImpl(name, label, | |
293 description, | |
294 defaultValue, | |
295 mustSpecify, | |
296 min, max)); | |
297 } | |
298 | |
299 void addSelectedArgument(String name, String label, String description, | |
300 String defaultValue, boolean mustSpecify, | |
301 List list) { | |
302 defaultArguments.put(name, | |
303 new SelectedArgumentImpl(name, label, | |
304 description, | |
305 defaultValue, | |
306 mustSpecify, list)); | |
307 } | |
308 | |
309 ArgumentImpl argument(String name, Map arguments) | |
310 throws IllegalConnectorArgumentsException { | |
311 | |
312 ArgumentImpl argument = (ArgumentImpl)arguments.get(name); | |
313 if (argument == null) { | |
314 throw new IllegalConnectorArgumentsException( | |
315 "Argument missing", name); | |
316 } | |
317 String value = argument.value(); | |
318 if (value == null || value.length() == 0) { | |
319 if (argument.mustSpecify()) { | |
320 throw new IllegalConnectorArgumentsException( | |
321 "Argument unspecified", name); | |
322 } | |
323 } else if(!argument.isValid(value)) { | |
324 throw new IllegalConnectorArgumentsException( | |
325 "Argument invalid", name); | |
326 } | |
327 | |
328 return argument; | |
329 } | |
330 | |
331 String getString(String key) { | |
332 //fixme jjh; needs i18n | |
333 // this is not public return ((VirtualMachineManagerImpl)manager).getString(key); | |
334 return key; | |
335 } | |
336 | |
337 public String toString() { | |
338 String string = name() + " (defaults: "; | |
339 Iterator iter = defaultArguments().values().iterator(); | |
340 boolean first = true; | |
341 while (iter.hasNext()) { | |
342 ArgumentImpl argument = (ArgumentImpl)iter.next(); | |
343 if (!first) { | |
344 string += ", "; | |
345 } | |
346 string += argument.toString(); | |
347 first = false; | |
348 } | |
349 return string + ")"; | |
350 } | |
351 | |
352 abstract class ArgumentImpl implements Connector.Argument, Cloneable, Serializable { | |
353 private String name; | |
354 private String label; | |
355 private String description; | |
356 private String value; | |
357 private boolean mustSpecify; | |
358 | |
359 ArgumentImpl(String name, String label, String description, | |
360 String value, | |
361 boolean mustSpecify) { | |
362 this.name = name; | |
363 this.label = label; | |
364 this.description = description; | |
365 this.value = value; | |
366 this.mustSpecify = mustSpecify; | |
367 } | |
368 | |
369 public abstract boolean isValid(String value); | |
370 | |
371 public String name() { | |
372 return name; | |
373 } | |
374 | |
375 public String label() { | |
376 return label; | |
377 } | |
378 | |
379 public String description() { | |
380 return description; | |
381 } | |
382 | |
383 public String value() { | |
384 return value; | |
385 } | |
386 | |
387 public void setValue(String value) { | |
388 if (value == null) { | |
389 throw new NullPointerException("Can't set null value"); | |
390 } | |
391 this.value = value; | |
392 } | |
393 | |
394 public boolean mustSpecify() { | |
395 return mustSpecify; | |
396 } | |
397 | |
398 public boolean equals(Object obj) { | |
399 if ((obj != null) && (obj instanceof Connector.Argument)) { | |
400 Connector.Argument other = (Connector.Argument)obj; | |
401 return (name().equals(other.name())) && | |
402 (description().equals(other.description())) && | |
403 (mustSpecify() == other.mustSpecify()) && | |
404 (value().equals(other.value())); | |
405 } else { | |
406 return false; | |
407 } | |
408 } | |
409 | |
410 public int hashCode() { | |
411 return description().hashCode(); | |
412 } | |
413 | |
414 public Object clone() { | |
415 try { | |
416 return super.clone(); | |
417 } catch (CloneNotSupportedException e) { | |
418 // Object should always support clone | |
419 throw (InternalException) new InternalException().initCause(e); | |
420 } | |
421 } | |
422 | |
423 public String toString() { | |
424 return name() + "=" + value(); | |
425 } | |
426 } | |
427 | |
428 class BooleanArgumentImpl extends ConnectorImpl.ArgumentImpl | |
429 implements Connector.BooleanArgument { | |
430 | |
431 BooleanArgumentImpl(String name, String label, String description, | |
432 boolean value, | |
433 boolean mustSpecify) { | |
434 super(name, label, description, null, mustSpecify); | |
435 if(trueString == null) { | |
436 trueString = getString("true"); | |
437 falseString = getString("false"); | |
438 } | |
439 setValue(value); | |
440 } | |
441 | |
442 /** | |
443 * Sets the value of the argument. | |
444 */ | |
445 public void setValue(boolean value) { | |
446 setValue(stringValueOf(value)); | |
447 } | |
448 | |
449 /** | |
450 * Performs basic sanity check of argument. | |
451 * @return <code>true</code> if value is a string | |
452 * representation of a boolean value. | |
453 * @see #stringValueOf(boolean) | |
454 */ | |
455 public boolean isValid(String value) { | |
456 return value.equals(trueString) || value.equals(falseString); | |
457 } | |
458 | |
459 /** | |
460 * Return the string representation of the <code>value</code> | |
461 * parameter. | |
462 * Does not set or examine the value or the argument. | |
463 * @return the localized String representation of the | |
464 * boolean value. | |
465 */ | |
466 public String stringValueOf(boolean value) { | |
467 return value? trueString : falseString; | |
468 } | |
469 | |
470 /** | |
471 * Return the value of the argument as a boolean. Since | |
472 * the argument may not have been set or may have an invalid | |
473 * value {@link #isValid(String)} should be called on | |
474 * {@link #value()} to check its validity. If it is invalid | |
475 * the boolean returned by this method is undefined. | |
476 * @return the value of the argument as a boolean. | |
477 */ | |
478 public boolean booleanValue() { | |
479 return value().equals(trueString); | |
480 } | |
481 } | |
482 | |
483 class IntegerArgumentImpl extends ConnectorImpl.ArgumentImpl | |
484 implements Connector.IntegerArgument { | |
485 | |
486 private final int min; | |
487 private final int max; | |
488 | |
489 IntegerArgumentImpl(String name, String label, String description, | |
490 String value, | |
491 boolean mustSpecify, int min, int max) { | |
492 super(name, label, description, value, mustSpecify); | |
493 this.min = min; | |
494 this.max = max; | |
495 } | |
496 | |
497 /** | |
498 * Sets the value of the argument. | |
499 * The value should be checked with {@link #isValid(int)} | |
500 * before setting it; invalid values will throw an exception | |
501 * when the connection is established - for example, | |
502 * on {@link LaunchingConnector#launch} | |
503 */ | |
504 public void setValue(int value) { | |
505 setValue(stringValueOf(value)); | |
506 } | |
507 | |
508 /** | |
509 * Performs basic sanity check of argument. | |
510 * @return <code>true</code> if value represents an int that is | |
511 * <code>{@link #min()} <= value <= {@link #max()}</code> | |
512 */ | |
513 public boolean isValid(String value) { | |
514 if (value == null) { | |
515 return false; | |
516 } | |
517 try { | |
518 return isValid(Integer.decode(value).intValue()); | |
519 } catch(NumberFormatException exc) { | |
520 return false; | |
521 } | |
522 } | |
523 | |
524 /** | |
525 * Performs basic sanity check of argument. | |
526 * @return <code>true</code> if | |
527 * <code>{@link #min()} <= value <= {@link #max()}</code> | |
528 */ | |
529 public boolean isValid(int value) { | |
530 return min <= value && value <= max; | |
531 } | |
532 | |
533 /** | |
534 * Return the string representation of the <code>value</code> | |
535 * parameter. | |
536 * Does not set or examine the value or the argument. | |
537 * @return the String representation of the | |
538 * int value. | |
539 */ | |
540 public String stringValueOf(int value) { | |
541 // *** Should this be internationalized???? | |
542 // *** Even Brian Beck was unsure if an Arabic programmer | |
543 // *** would expect port numbers in Arabic numerals, | |
544 // *** so punt for now. | |
545 return ""+value; | |
546 } | |
547 | |
548 /** | |
549 * Return the value of the argument as a int. Since | |
550 * the argument may not have been set or may have an invalid | |
551 * value {@link #isValid(String)} should be called on | |
552 * {@link #value()} to check its validity. If it is invalid | |
553 * the int returned by this method is undefined. | |
554 * @return the value of the argument as a int. | |
555 */ | |
556 public int intValue() { | |
557 if (value() == null) { | |
558 return 0; | |
559 } | |
560 try { | |
561 return Integer.decode(value()).intValue(); | |
562 } catch(NumberFormatException exc) { | |
563 return 0; | |
564 } | |
565 } | |
566 | |
567 /** | |
568 * The upper bound for the value. | |
569 * @return the maximum allowed value for this argument. | |
570 */ | |
571 public int max() { | |
572 return max; | |
573 } | |
574 | |
575 /** | |
576 * The lower bound for the value. | |
577 * @return the minimum allowed value for this argument. | |
578 */ | |
579 public int min() { | |
580 return min; | |
581 } | |
582 } | |
583 | |
584 class StringArgumentImpl extends ConnectorImpl.ArgumentImpl | |
585 implements Connector.StringArgument { | |
586 | |
587 StringArgumentImpl(String name, String label, String description, | |
588 String value, | |
589 boolean mustSpecify) { | |
590 super(name, label, description, value, mustSpecify); | |
591 } | |
592 | |
593 /** | |
594 * Performs basic sanity check of argument. | |
595 * @return <code>true</code> always | |
596 */ | |
597 public boolean isValid(String value) { | |
598 return true; | |
599 } | |
600 } | |
601 | |
602 class SelectedArgumentImpl extends ConnectorImpl.ArgumentImpl | |
603 implements Connector.SelectedArgument { | |
604 | |
605 private final List choices; | |
606 | |
607 SelectedArgumentImpl(String name, String label, String description, | |
608 String value, | |
609 boolean mustSpecify, List choices) { | |
610 super(name, label, description, value, mustSpecify); | |
611 this.choices = Collections.unmodifiableList( | |
612 new ArrayList(choices)); | |
613 } | |
614 | |
615 /** | |
616 * Return the possible values for the argument | |
617 * @return {@link List} of {@link String} | |
618 */ | |
619 public List choices() { | |
620 return choices; | |
621 } | |
622 | |
623 /** | |
624 * Performs basic sanity check of argument. | |
625 * @return <code>true</code> if value is one of {@link #choices()}. | |
626 */ | |
627 public boolean isValid(String value) { | |
628 return choices.contains(value); | |
629 } | |
630 } | |
631 } |