--- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java 2019-12-19 16:53:37.508940400 +0900 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java 2019-12-19 16:53:37.252190100 +0900 @@ -24,6 +24,9 @@ package sun.jvm.hotspot; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.nio.file.Path; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; @@ -34,14 +37,20 @@ import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.ServiceLoader; +import java.util.Set; import java.util.Stack; +import java.util.stream.Collectors; import java.util.regex.Matcher; import java.util.regex.Pattern; +import sun.jvm.hotspot.api.Command; +import sun.jvm.hotspot.api.Tokens; import sun.jvm.hotspot.ci.ciEnv; import sun.jvm.hotspot.code.CodeBlob; import sun.jvm.hotspot.code.CodeCacheVisitor; @@ -138,132 +147,41 @@ } } - static class Tokens { - final String input; - int i; - String[] tokens; - int length; - - String[] splitWhitespace(String cmd) { - String[] t = cmd.split("\\s"); - if (t.length == 1 && t[0].length() == 0) { - return new String[0]; - } - return t; - } - - void add(String s, ArrayList t) { - if (s.length() > 0) { - t.add(s); - } - } - - Tokens(String cmd) { - input = cmd; - - // check for quoting - int quote = cmd.indexOf('"'); - ArrayList t = new ArrayList(); - if (quote != -1) { - while (cmd.length() > 0) { - if (quote != -1) { - int endquote = cmd.indexOf('"', quote + 1); - if (endquote == -1) { - throw new RuntimeException("mismatched quotes: " + input); - } - - String before = cmd.substring(0, quote).trim(); - String quoted = cmd.substring(quote + 1, endquote); - cmd = cmd.substring(endquote + 1).trim(); - if (before.length() > 0) { - String[] w = splitWhitespace(before); - for (int i = 0; i < w.length; i++) { - add(w[i], t); - } - } - add(quoted, t); - quote = cmd.indexOf('"'); - } else { - String[] w = splitWhitespace(cmd); - for (int i = 0; i < w.length; i++) { - add(w[i], t); - } - cmd = ""; - - } - } - } else { - String[] w = splitWhitespace(cmd); - for (int i = 0; i < w.length; i++) { - add(w[i], t); - } - } - tokens = (String[])t.toArray(new String[0]); - i = 0; - length = tokens.length; - - //for (int i = 0; i < tokens.length; i++) { - // System.out.println("\"" + tokens[i] + "\""); - //} - } - - String nextToken() { - return tokens[i++]; - } - boolean hasMoreTokens() { - return i < length; - } - int countTokens() { - return length - i; - } - void trim(int n) { - if (length >= n) { - length -= n; - } else { - throw new IndexOutOfBoundsException(String.valueOf(n)); - } - } - String join(String sep) { - StringBuffer result = new StringBuffer(); - for (int w = i; w < length; w++) { - result.append(tokens[w]); - if (w + 1 < length) { - result.append(sep); - } - } - return result.toString(); - } - - String at(int i) { - if (i < 0 || i >= length) { - throw new IndexOutOfBoundsException(String.valueOf(i)); - } - return tokens[i]; - } - } - - - abstract class Command { - Command(String n, String u, boolean ok) { + abstract class ClhsdbCommand implements Command { + ClhsdbCommand(String n, String u, boolean ok) { name = n; usage = u; okIfDisconnected = ok; } - Command(String n, boolean ok) { + ClhsdbCommand(String n, boolean ok) { name = n; usage = n; okIfDisconnected = ok; } - final String name; - final String usage; - final boolean okIfDisconnected; - abstract void doit(Tokens t); - void usage() { - out.println("Usage: " + usage); + private final String name; + private final String usage; + private final boolean okIfDisconnected; + + @Override + public String name() { + return name; + } + + @Override + public String usage() { + return "Usage: " + usage; + } + + @Override + public boolean okIfDisconnected() { + return okIfDisconnected; } + @Override + public abstract void doit(Tokens t, PrintStream out); + void printOopValue(Oop oop) { if (oop != null) { Klass k = oop.getKlass(); @@ -390,8 +308,9 @@ } private final Command[] commandList = { - new Command("reattach", true) { - public void doit(Tokens t) { + new ClhsdbCommand("reattach", true) { + @Override + public void doit(Tokens t, PrintStream out) { int tokens = t.countTokens(); if (tokens != 0) { usage(); @@ -402,8 +321,9 @@ postAttach(); } }, - new Command("attach", "attach pid | exec core", true) { - public void doit(Tokens t) { + new ClhsdbCommand("attach", "attach pid | exec core", true) { + @Override + public void doit(Tokens t, PrintStream out) { int tokens = t.countTokens(); if (tokens == 1) { preAttach(); @@ -418,8 +338,9 @@ } } }, - new Command("detach", false) { - public void doit(Tokens t) { + new ClhsdbCommand("detach", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 0) { usage(); } else { @@ -427,7 +348,7 @@ } } }, - new Command("examine", "examine [ address/count ] | [ address,address]", false) { + new ClhsdbCommand("examine", "examine [ address/count ] | [ address,address]", false) { Pattern args1 = Pattern.compile("^(0x[0-9a-f]+)(/([0-9]*)([a-z]*))?$"); Pattern args2 = Pattern.compile("^(0x[0-9a-f]+),(0x[0-9a-f]+)(/[a-z]*)?$"); @@ -442,7 +363,8 @@ return s; } - public void doit(Tokens t) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -501,11 +423,12 @@ } } }, - new Command("dumpreplaydata", "dumpreplaydata {
| -a | }", false) { + new ClhsdbCommand("dumpreplaydata", "dumpreplaydata {
| -a | }", false) { // This is used to dump replay data from ciInstanceKlass, ciMethodData etc // default file name is replay.txt, also if java crashes in compiler // thread, this file will be dumped in error processing. - public void doit(Tokens t) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); return; @@ -552,12 +475,13 @@ } } }, - new Command("buildreplayjars", "buildreplayjars [ all | app | boot ] | [ prefix ]", false) { + new ClhsdbCommand("buildreplayjars", "buildreplayjars [ all | app | boot ] | [ prefix ]", false) { // This is used to dump jar files of all the classes // loaded in the core. Everything with null classloader // will go in boot.jar and everything else will go in // app.jar. boot.jar usually not needed, unless changed by jvmti. - public void doit(Tokens t) { + @Override + public void doit(Tokens t, PrintStream out) { int tcount = t.countTokens(); if (tcount > 2) { usage(); @@ -606,8 +530,9 @@ } } }, - new Command("findpc", "findpc address", false) { - public void doit(Tokens t) { + new ClhsdbCommand("findpc", "findpc address", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -617,8 +542,9 @@ } } }, - new Command("symbol", "symbol address", false) { - public void doit(Tokens t) { + new ClhsdbCommand("symbol", "symbol address", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -628,8 +554,9 @@ } } }, - new Command("flags", "flags [ flag | -nd ]", false) { - public void doit(Tokens t) { + new ClhsdbCommand("flags", "flags [ flag | -nd ]", false) { + @Override + public void doit(Tokens t, PrintStream out) { int tokens = t.countTokens(); if (tokens != 0 && tokens != 1) { usage(); @@ -665,8 +592,9 @@ } } }, - new Command("help", "help [ command ]", true) { - public void doit(Tokens t) { + new ClhsdbCommand("help", "help [ command ]", true) { + @Override + public void doit(Tokens t, PrintStream out) { int tokens = t.countTokens(); Command cmd = null; if (tokens == 1) { @@ -685,13 +613,14 @@ }); for (int i = 0; i < keys.length; i++) { out.print(" "); - out.println(((Command)commands.get(keys[i])).usage); + out.println(((Command)commands.get(keys[i])).usage()); } } } }, - new Command("history", "history", true) { - public void doit(Tokens t) { + new ClhsdbCommand("history", "history", true) { + @Override + public void doit(Tokens t, PrintStream out) { int tokens = t.countTokens(); if (tokens != 0 && (tokens != 1 || !t.nextToken().equals("-h"))) { usage(); @@ -705,8 +634,9 @@ } }, // decode raw address - new Command("dis", "dis address [length]", false) { - public void doit(Tokens t) { + new ClhsdbCommand("dis", "dis address [length]", false) { + @Override + public void doit(Tokens t, PrintStream out) { int tokens = t.countTokens(); if (tokens != 1 && tokens != 2) { usage(); @@ -735,8 +665,9 @@ }, // decode codeblob or nmethod - new Command("disassemble", "disassemble address", false) { - public void doit(Tokens t) { + new ClhsdbCommand("disassemble", "disassemble address", false) { + @Override + public void doit(Tokens t, PrintStream out) { int tokens = t.countTokens(); if (tokens != 1) { usage(); @@ -756,8 +687,9 @@ } }, // print Java bytecode disassembly - new Command("jdis", "jdis address", false) { - public void doit(Tokens t) { + new ClhsdbCommand("jdis", "jdis address", false) { + @Override + public void doit(Tokens t, PrintStream out) { int tokens = t.countTokens(); if (tokens != 1) { usage(); @@ -769,8 +701,9 @@ out.println(html.genHTML(m)); } }, - new Command("revptrs", "revptrs address", false) { - public void doit(Tokens t) { + new ClhsdbCommand("revptrs", "revptrs address", false) { + @Override + public void doit(Tokens t, PrintStream out) { int tokens = t.countTokens(); if (tokens != 1 && (tokens != 2 || !t.nextToken().equals("-c"))) { usage(); @@ -831,9 +764,10 @@ } } }, - new Command("printmdo", "printmdo [ -a | expression ]", false) { + new ClhsdbCommand("printmdo", "printmdo [ -a | expression ]", false) { // Print every MDO in the heap or the one referenced by expression. - public void doit(Tokens t) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -867,9 +801,10 @@ } } }, - new Command("printall", "printall", false) { + new ClhsdbCommand("printall", "printall", false) { // Print every MDO in the heap or the one referenced by expression. - public void doit(Tokens t) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 0) { usage(); } else { @@ -890,9 +825,10 @@ } } }, - new Command("dumpideal", "dumpideal { -a | id }", false) { + new ClhsdbCommand("dumpideal", "dumpideal { -a | id }", false) { // Do a full dump of the nodes reachabile from root in each compiler thread. - public void doit(Tokens t) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -920,9 +856,10 @@ } } }, - new Command("dumpcfg", "dumpcfg { -a | id }", false) { + new ClhsdbCommand("dumpcfg", "dumpcfg { -a | id }", false) { // Dump the PhaseCFG for every compiler thread that has one live. - public void doit(Tokens t) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -948,9 +885,10 @@ } } }, - new Command("dumpilt", "dumpilt { -a | id }", false) { + new ClhsdbCommand("dumpilt", "dumpilt { -a | id }", false) { // dumps the InlineTree of a C2 compile - public void doit(Tokens t) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -978,8 +916,9 @@ } } }, - new Command("vmstructsdump", "vmstructsdump", false) { - public void doit(Tokens t) { + new ClhsdbCommand("vmstructsdump", "vmstructsdump", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 0) { usage(); return; @@ -1014,8 +953,9 @@ } }, - new Command("inspect", "inspect expression", false) { - public void doit(Tokens t) { + new ClhsdbCommand("inspect", "inspect expression", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -1054,14 +994,16 @@ } } }, - new Command("jhisto", "jhisto", false) { - public void doit(Tokens t) { + new ClhsdbCommand("jhisto", "jhisto", false) { + @Override + public void doit(Tokens t, PrintStream out) { ObjectHistogram histo = new ObjectHistogram(); histo.run(out, err); } }, - new Command("jstack", "jstack [-v]", false) { - public void doit(Tokens t) { + new ClhsdbCommand("jstack", "jstack [-v]", false) { + @Override + public void doit(Tokens t, PrintStream out) { boolean verbose = false; if (t.countTokens() > 0 && t.nextToken().equals("-v")) { verbose = true; @@ -1070,8 +1012,9 @@ jstack.run(out); } }, - new Command("print", "print expression", false) { - public void doit(Tokens t) { + new ClhsdbCommand("print", "print expression", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -1081,8 +1024,9 @@ } } }, - new Command("printas", "printas type expression", false) { - public void doit(Tokens t) { + new ClhsdbCommand("printas", "printas type expression", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 2) { usage(); } else { @@ -1096,8 +1040,9 @@ } } }, - new Command("printstatics", "printstatics [ type ]", false) { - public void doit(Tokens t) { + new ClhsdbCommand("printstatics", "printstatics [ type ]", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() > 1) { usage(); } else { @@ -1112,14 +1057,16 @@ } } }, - new Command("pmap", "pmap", false) { - public void doit(Tokens t) { + new ClhsdbCommand("pmap", "pmap", false) { + @Override + public void doit(Tokens t, PrintStream out) { PMap pmap = new PMap(); pmap.run(out, debugger.getAgent().getDebugger()); } }, - new Command("pstack", "pstack [-v]", false) { - public void doit(Tokens t) { + new ClhsdbCommand("pstack", "pstack [-v]", false) { + @Override + public void doit(Tokens t, PrintStream out) { boolean verbose = false; if (t.countTokens() > 0 && t.nextToken().equals("-v")) { verbose = true; @@ -1128,8 +1075,9 @@ pstack.run(out, debugger.getAgent().getDebugger()); } }, - new Command("quit", true) { - public void doit(Tokens t) { + new ClhsdbCommand("quit", true) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 0) { usage(); } else { @@ -1138,8 +1086,9 @@ } } }, - new Command("echo", "echo [ true | false ]", true) { - public void doit(Tokens t) { + new ClhsdbCommand("echo", "echo [ true | false ]", true) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() == 0) { out.println("echo is " + doEcho); } else if (t.countTokens() == 1) { @@ -1149,8 +1098,9 @@ } } }, - new Command("versioncheck", "versioncheck [ true | false ]", true) { - public void doit(Tokens t) { + new ClhsdbCommand("versioncheck", "versioncheck [ true | false ]", true) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() == 0) { out.println("versioncheck is " + (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null)); @@ -1165,8 +1115,9 @@ } } }, - new Command("scanoops", "scanoops start end [ type ]", false) { - public void doit(Tokens t) { + new ClhsdbCommand("scanoops", "scanoops start end [ type ]", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 2 && t.countTokens() != 3) { usage(); } else { @@ -1201,8 +1152,9 @@ } } }, - new Command("intConstant", "intConstant [ name [ value ] ]", true) { - public void doit(Tokens t) { + new ClhsdbCommand("intConstant", "intConstant [ name [ value ] ]", true) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) { usage(); return; @@ -1224,8 +1176,9 @@ } } }, - new Command("longConstant", "longConstant [ name [ value ] ]", true) { - public void doit(Tokens t) { + new ClhsdbCommand("longConstant", "longConstant [ name [ value ] ]", true) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 2) { usage(); return; @@ -1247,8 +1200,9 @@ } } }, - new Command("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) { - public void doit(Tokens t) { + new ClhsdbCommand("field", "field [ type [ name fieldtype isStatic offset address ] ]", true) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { usage(); return; @@ -1282,19 +1236,19 @@ Field f = (Field) i.next(); if (f.getName().equals(fieldName)) { if (f.isStatic() != isStatic) { - throw new RuntimeException("static/nonstatic mismatch: " + t.input); + throw new RuntimeException("static/nonstatic mismatch: " + t.getInput()); } if (!isStatic) { if (f.getOffset() != offset) { - throw new RuntimeException("bad redefinition of field offset: " + t.input); + throw new RuntimeException("bad redefinition of field offset: " + t.getInput()); } } else { if (!f.getStaticFieldAddress().equals(staticAddress)) { - throw new RuntimeException("bad redefinition of field location: " + t.input); + throw new RuntimeException("bad redefinition of field location: " + t.getInput()); } } if (f.getType() != fieldType) { - throw new RuntimeException("bad redefinition of field type: " + t.input); + throw new RuntimeException("bad redefinition of field type: " + t.getInput()); } return; } @@ -1312,15 +1266,17 @@ } }, - new Command("tokenize", "tokenize ...", true) { - public void doit(Tokens t) { + new ClhsdbCommand("tokenize", "tokenize ...", true) { + @Override + public void doit(Tokens t, PrintStream out) { while (t.hasMoreTokens()) { out.println("\"" + t.nextToken() + "\""); } } }, - new Command("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) { - public void doit(Tokens t) { + new ClhsdbCommand("type", "type [ type [ name super isOop isInteger isUnsigned size ] ]", true) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1 && t.countTokens() != 0 && t.countTokens() != 6) { usage(); return; @@ -1343,35 +1299,35 @@ } if (type != null) { if (type.isOopType() != isOop) { - throw new RuntimeException("oop mismatch in type definition: " + t.input); + throw new RuntimeException("oop mismatch in type definition: " + t.getInput()); } if (type.isCIntegerType() != isInteger) { - throw new RuntimeException("integer type mismatch in type definition: " + t.input); + throw new RuntimeException("integer type mismatch in type definition: " + t.getInput()); } if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) { - throw new RuntimeException("unsigned mismatch in type definition: " + t.input); + throw new RuntimeException("unsigned mismatch in type definition: " + t.getInput()); } if (type.getSuperclass() == null) { if (superclassName != null) { if (type.getSize() == -1) { type.setSuperclass(agent.getTypeDataBase().lookupType(superclassName)); } else { - throw new RuntimeException("unexpected superclass in type definition: " + t.input); + throw new RuntimeException("unexpected superclass in type definition: " + t.getInput()); } } } else { if (superclassName == null) { - throw new RuntimeException("missing superclass in type definition: " + t.input); + throw new RuntimeException("missing superclass in type definition: " + t.getInput()); } if (!type.getSuperclass().getName().equals(superclassName)) { - throw new RuntimeException("incorrect superclass in type definition: " + t.input); + throw new RuntimeException("incorrect superclass in type definition: " + t.getInput()); } } if (type.getSize() != size) { if (type.getSize() == -1) { type.setSize(size); } - throw new RuntimeException("size mismatch in type definition: " + t.input); + throw new RuntimeException("size mismatch in type definition: " + t.getInput()); } return; } @@ -1407,8 +1363,9 @@ } }, - new Command("source", "source filename", true) { - public void doit(Tokens t) { + new ClhsdbCommand("source", "source filename", true) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); return; @@ -1430,8 +1387,9 @@ } }, - new Command("search", "search [ heap | perm | rawheap | codecache | threads ] value", false) { - public void doit(Tokens t) { + new ClhsdbCommand("search", "search [ heap | perm | rawheap | codecache | threads ] value", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 2) { usage(); return; @@ -1536,8 +1494,9 @@ } } }, - new Command("dumpcodecache", "dumpcodecache", false) { - public void doit(Tokens t) { + new ClhsdbCommand("dumpcodecache", "dumpcodecache", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 0) { usage(); } else { @@ -1558,8 +1517,9 @@ } } }, - new Command("where", "where { -a | id }", false) { - public void doit(Tokens t) { + new ClhsdbCommand("where", "where { -a | id }", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -1588,8 +1548,9 @@ } } }, - new Command("thread", "thread { -a | id }", false) { - public void doit(Tokens t) { + new ClhsdbCommand("thread", "thread { -a | id }", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -1614,8 +1575,8 @@ } }, - new Command("threads", false) { - public void doit(Tokens t) { + new ClhsdbCommand("threads", false) { + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 0) { usage(); } else { @@ -1631,8 +1592,9 @@ } }, - new Command("livenmethods", false) { - public void doit(Tokens t) { + new ClhsdbCommand("livenmethods", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 0) { usage(); } else { @@ -1658,8 +1620,9 @@ } } }, - new Command("g1regiondetails", false) { - public void doit(Tokens t) { + new ClhsdbCommand("g1regiondetails", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 0) { usage(); } else { @@ -1673,8 +1636,9 @@ } } }, - new Command("universe", false) { - public void doit(Tokens t) { + new ClhsdbCommand("universe", false) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 0) { usage(); } else { @@ -1684,8 +1648,9 @@ } } }, - new Command("verbose", "verbose true | false", true) { - public void doit(Tokens t) { + new ClhsdbCommand("verbose", "verbose true | false", true) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -1693,8 +1658,9 @@ } } }, - new Command("assert", "assert true | false", true) { - public void doit(Tokens t) { + new ClhsdbCommand("assert", "assert true | false", true) { + @Override + public void doit(Tokens t, PrintStream out) { if (t.countTokens() != 1) { usage(); } else { @@ -1702,6 +1668,16 @@ } } }, + new ClhsdbCommand("load_plugin", "load_plugin [path]", true) { + @Override + public void doit(Tokens t, PrintStream out) { + if (t.countTokens() != 1) { + usage(); + } else { + registerCommand(Path.of(t.nextToken())); + } + } + }, }; private boolean verboseExceptions = false; @@ -1780,8 +1756,9 @@ } public void registerCommand(String cmd, String usage, final String func) { - commands.put(cmd, new Command(cmd, usage, false) { - public void doit(Tokens t) { + commands.put(cmd, new ClhsdbCommand(cmd, usage, false) { + @Override + public void doit(Tokens t, PrintStream out) { final int len = t.countTokens(); Object[] args = new Object[len]; for (int i = 0; i < len; i++) { @@ -1792,6 +1769,37 @@ }); } + public void registerCommand(Path path) { + Module saModule = this.getClass().getModule(); + ModuleLayer saLayer = saModule.getLayer(); + + // Create new module for the path + ModuleFinder finder = ModuleFinder.of(path); + Set moduleNames = finder.findAll() + .stream() + .map(r -> r.descriptor().name()) + .peek(m -> System.out.println("Module found: " + m)) + .collect(Collectors.toSet()); + + Configuration conf = saLayer.configuration() + .resolveAndBind(finder, ModuleFinder.of(), moduleNames); + ModuleLayer layer = saLayer.defineModulesWithOneLoader(conf, saModule.getClassLoader()); + + // Export all SA packages to the new module + layer.modules() + .stream() + .forEach(m -> saModule.getPackages() + .stream() + .forEach(p -> saModule.addExports(p, m))); + + // Register command in the new module + ServiceLoader.load(layer, Command.class) + .stream() + .map(ServiceLoader.Provider::get) + .peek(s -> System.out.println("Installing: " + s.name())) + .forEach(s -> commands.put(s.name(), s)); + } + public void setOutput(PrintStream o) { out = o; } @@ -1808,10 +1816,10 @@ this.err = err; for (int i = 0; i < commandList.length; i++) { Command c = commandList[i]; - if (commands.get(c.name) != null) { - throw new InternalError(c.name + " has multiple definitions"); + if (commands.get(c.name()) != null) { + throw new InternalError(c.name() + " has multiple definitions"); } - commands.put(c.name, c); + commands.put(c.name(), c); } if (debugger.isAttached()) { postAttach(); @@ -1979,11 +1987,11 @@ */ if (doit == null) { out.println("Unrecognized command. Try help..."); - } else if (!debugger.isAttached() && !doit.okIfDisconnected) { + } else if (!debugger.isAttached() && !doit.okIfDisconnected()) { out.println("Command not valid until attached to a VM"); } else { try { - doit.doit(args); + doit.doit(args, out); } catch (Exception e) { out.println("Error: " + e); if (verboseExceptions) {