comparison agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js @ 6782:5a98bf7d847b

6879063: SA should use hsdis for disassembly Summary: We should in SA to use hsdis for it like the JVM does to replace the current java based disassembler. Reviewed-by: twisti, jrose, sla Contributed-by: yumin.qi@oracle.com
author minqi
date Mon, 24 Sep 2012 12:44:00 -0700
parents da91efe96a93
children 5ed317b25e23
comparison
equal deleted inserted replaced
6780:8440414b0fd8 6782:5a98bf7d847b
219 // tool exposes Unix-style commands. 219 // tool exposes Unix-style commands.
220 220
221 // if "registerCommand" function is defined 221 // if "registerCommand" function is defined
222 // then register few global functions as "commands". 222 // then register few global functions as "commands".
223 if (typeof(registerCommand) == 'function') { 223 if (typeof(registerCommand) == 'function') {
224 this.printDis = function(addr, len) {
225 if (!addr) {
226 writeln("Usage: dis address [ length ]");
227 } else {
228 dis(addr, len);
229 }
230 }
231 registerCommand("dis", "dis address [ length ]", "printDis");
232
233 this.jclass = function(name) { 224 this.jclass = function(name) {
234 if (typeof(name) == "string") { 225 if (typeof(name) == "string") {
235 var clazz = sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name); 226 var clazz = sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name);
236 if (clazz) { 227 if (clazz) {
237 writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString()); 228 writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString());
249 writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString()); 240 writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString());
250 }); 241 });
251 } 242 }
252 registerCommand("classes", "classes", "jclasses"); 243 registerCommand("classes", "classes", "jclasses");
253 244
254 this.printJDis = function(addr) {
255 if (!addr) {
256 writeln("Usage: jdis address");
257 } else {
258 jdis(addr);
259 }
260 }
261 registerCommand("jdis", "jdis address", "printJDis");
262
263 this.dclass = function(clazz, dir) { 245 this.dclass = function(clazz, dir) {
264 if (!clazz) { 246 if (!clazz) {
265 writeln("Usage: dumpclass { address | name } [ directory ]"); 247 writeln("Usage: dumpclass { address | name } [ directory ]");
266 } else { 248 } else {
267 if (!dir) { dir = "."; } 249 if (!dir) { dir = "."; }
393 } else { 375 } else {
394 return addr2str(addr); 376 return addr2str(addr);
395 } 377 }
396 } 378 }
397 379
398 // read 'num' bytes at 'addr' and return an array as result.
399 // returns Java byte[] type result and not a JavaScript array.
400 function readBytesAt(addr, num) {
401 addr = any2addr(addr);
402 var res = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, num);
403 var i;
404 for (i = 0; i < num; i++) {
405 res[i] = addr.getJByteAt(i);
406 }
407 return res;
408 }
409
410 // read 'num' words at 'addr' and return an array as result. 380 // read 'num' words at 'addr' and return an array as result.
411 // returns Java long[] type result and not a JavaScript array. 381 // returns Java long[] type result and not a JavaScript array.
412 function readWordsAt(addr, num) { 382 function readWordsAt(addr, num) {
413 addr = any2addr(addr); 383 addr = any2addr(addr);
414 var res = java.lang.reflect.Array.newInstance(java.lang.Long.TYPE, num); 384 var res = java.lang.reflect.Array.newInstance(java.lang.Long.TYPE, num);
504 addr = addr.addOffsetTo(addressSize); 474 addr = addr.addOffsetTo(addressSize);
505 } 475 }
506 writeln(); 476 writeln();
507 } 477 }
508 478
509 // return the disassemble class for current CPU
510 function disassemblerClass() {
511 var DisAsmClass;
512 if (CPU == 'x86') {
513 DisAsmClass = sapkg.asm.x86.X86Disassembler;
514 } else if (CPU == 'sparc') {
515 DisAsmClass = sapkg.asm.sparc.SPARCV9Disassembler;
516 }
517 return DisAsmClass;
518 }
519
520 // print native code disassembly of 'num' bytes at 'addr'
521 function dis(addr, num) {
522 addr = any2addr(addr);
523 var nmethod = findNMethod(addr);
524 if (nmethod != null) {
525 // disassemble it as nmethod
526 nmethoddis(nmethod);
527 } else {
528 // raw disassembly
529 if (num == undefined) {
530 // size of one SPARC instruction and
531 // unknown number of Intel instructions.
532 num = 4;
533 }
534 DisAsmClass = disassemblerClass();
535 if (DisAsmClass == undefined) {
536 // unsupported CPU
537 writeln(CPU + " is not yet supported!");
538 return;
539 }
540
541 var bytes = readBytesAt(addr, num);
542 var disAsm = new DisAsmClass(addr2num(addr), bytes);
543 disAsm.decode(new sapkg.asm.InstructionVisitor() {
544 visit: function (pc, instr) {
545 write(addr2sym(num2addr(pc)) + ':', '\t');
546 writeln(instr.asString(pc,
547 new sapkg.asm.SymbolFinder() {
548 getSymbolFor: function(addr) {
549 return addr2sym(num2addr(addr));
550 }
551 }));
552 }
553 });
554 }
555 }
556
557 // System dictionary functions 479 // System dictionary functions
558 480
559 // find InstanceKlass by name 481 // find InstanceKlass by name
560 function findInstanceKlass(name) { 482 function findInstanceKlass(name) {
561 return sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name); 483 return sapkg.utilities.SystemDictionaryHelper.findInstanceKlass(name);
582 504
583 // iterate system dictionary for each primitive array klass 505 // iterate system dictionary for each primitive array klass
584 function forEachPrimArrayKlass(callback) { 506 function forEachPrimArrayKlass(callback) {
585 var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor; 507 var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor;
586 sa.sysDict.primArrayClassesDo(new VisitorClass() { visit: callback }); 508 sa.sysDict.primArrayClassesDo(new VisitorClass() { visit: callback });
587 }
588
589 // (hotspot) symbol table functions
590
591 // String-to-Symbol
592 function str2sym(str) {
593 return sa.symTbl.probe(str);
594 }
595
596 // Symbol-to-String
597 function sym2str(sym) {
598 return sym.asString();
599 }
600
601 // oop functions
602
603 // Address-to-Oop
604 function addr2oop(addr) {
605 addr = any2addr(addr);
606 return sa.objHeap.newOop(addr.addOffsetToAsOopHandle(0));
607 }
608
609 // Oop-to-Address
610 function oop2addr(oop) {
611 return oop.handle;
612 } 509 }
613 510
614 // 'oop' to higher-level java object wrapper in which for(i in o) 511 // 'oop' to higher-level java object wrapper in which for(i in o)
615 // works by iterating java level fields and javaobject.javafield 512 // works by iterating java level fields and javaobject.javafield
616 // syntax works. 513 // syntax works.
642 includeSubtypes = true; 539 includeSubtypes = true;
643 } 540 }
644 sa.objHeap.iterateObjectsOfKlass( 541 sa.objHeap.iterateObjectsOfKlass(
645 new sapkg.oops.HeapVisitor() { doObj: callback }, 542 new sapkg.oops.HeapVisitor() { doObj: callback },
646 klass, includeSubtypes); 543 klass, includeSubtypes);
647 }
648
649 // code cache functions
650
651 // iterates CodeCache for each 'CodeBlob'
652 function forEachCodeBlob(callback) {
653 var VisitorClass = sapkg.code.CodeCacheVisitor;
654 sa.codeCache.iterate(new VisitorClass() { visit: callback });
655 }
656
657 // find the ClodBlob (if any) that contains given address
658 function findCodeBlob(addr) {
659 addr = any2addr(addr);
660 return sa.codeCache.findBlobUnsafe(addr);
661 }
662
663 // find the NMethod (if any) that contains given address
664 function findNMethod(addr) {
665 var codeBlob = findCodeBlob(addr);
666 return (codeBlob != null && codeBlob.isNMethod())? codeBlob : null;
667 }
668
669 // returns PcDesc at given address or null
670 function pcDescAt(addr) {
671 addr = any2addr(addr);
672 var nmethod = findNMethod(addr);
673 return (nmethod != null)? nmethod.safepoints.get(addr) : null;
674 }
675
676 // helpers for nmethod disassembler
677 function printScope(scopeDesc) {
678 if (scopeDesc == null) {
679 return;
680 }
681 printScope(scopeDesc.sender());
682 var method = scopeDesc.method;
683 var bci = scopeDesc.BCI;
684 var line = -1;
685 if (method.hasLineNumberTable()) {
686 line = method.getLineNumberFromBCI(bci);
687 }
688
689 write('\t', method.externalNameAndSignature(), '@', method.handle, 'bci=' + bci);
690 if (line != -1) {
691 write('line=' + line);
692 }
693 writeln();
694 }
695
696 function printSafepointInfo(nmethod, pcDesc) {
697 var scopeDesc = nmethod.getScopeDescAt(
698 pcDesc.getRealPC(nmethod),
699 pcDesc.isAtCall());
700 printScope(scopeDesc);
701 }
702
703 // print disassembly for a given nmethod
704 function nmethoddis(nmethod) {
705 var DisAsmClass = disassemblerClass();
706 if (DisAsmClass == undefined) {
707 writeln(CPU + " is not yet supported!");
708 return;
709 }
710
711 var method = nmethod.method;
712 writeln('NMethod:', method.externalNameAndSignature(), '@', method.handle);
713
714 var codeBegin = nmethod.codeBegin();
715 var codeEnd = nmethod.codeEnd();
716 var size = codeEnd.minus(codeBegin);
717 var code = readBytesAt(codeBegin, size);
718 var startPc = addr2num(codeBegin);
719 var verifiedEntryPoint = addr2num(nmethod.verifiedEntryPoint);
720 var entryPoint = addr2num(nmethod.entryPoint);
721 var interpreterEntryPoint = addr2num(nmethod.interpreterEntryPointOrNull);
722 var safepoints = nmethod.safepoints;
723 var disAsm = new DisAsmClass(startPc, code);
724 disAsm.decode(new sapkg.asm.InstructionVisitor() {
725 visit: function(curPc, instr) {
726 if (curPc == verifiedEntryPoint) {
727 writeln();
728 writeln("Verified Entry Point:");
729 }
730 if (curPc == entryPoint) {
731 writeln();
732 writeln("Entry Point:");
733 }
734 if (curPc == interpreterEntryPoint) {
735 writeln("");
736 writeln("Interpreter Entry Point:");
737 }
738
739 var pcDesc = safepoints.get(num2addr(curPc));
740 var isSafepoint = (pcDesc != null);
741 if (isSafepoint && pcDesc.isAtCall()) {
742 printSafepointInfo(nmethod, pcDesc);
743 }
744
745 write(num2addr(curPc) + ':', '\t');
746 writeln(instr.asString(curPc,
747 new sapkg.asm.SymbolFinder() {
748 getSymbolFor: function(addr) {
749 return addr2sym(num2addr(addr));
750 }
751 }));
752
753 if (isSafepoint && !pcDesc.isAtCall()) {
754 printSafepointInfo(nmethod, pcDesc);
755 }
756 }
757 });
758 }
759
760 // bytecode interpreter functions
761
762 // iterates interpreter codelets for each interpreter codelet
763 function forEachInterpCodelet(callback) {
764 var stubQueue = sa.interpreter.code;
765 var stub = stubQueue.first;
766 while (stub != null) {
767 if (callback(stub) == false) return;
768 stub = stubQueue.getNext(stub);
769 }
770 }
771
772 // helper for bytecode disassembler
773 function printExceptionTable(method) {
774 var expTbl = method.getExceptionTable();
775 var len = expTbl.getLength();
776 if (len != 0) {
777 var i;
778 var cpool = method.constants;
779 writeln("start", '\t', "end", '\t', "handler", '\t', "exception");
780 writeln("");
781 for (i = 0; i < len; i += 4) {
782 write(expTbl.getIntAt(i), '\t',
783 expTbl.getIntAt(i + 1), '\t',
784 expTbl.getIntAt(i + 2), '\t');
785 var cpIndex = expTbl.getIntAt(i + 3);
786 var oop = (cpIndex == 0)? null : cpool.getObjAt(cpIndex);
787 if (oop == null) {
788 writeln("<any>");
789 } else if (oop.isSymbol()) {
790 writeln(oop.asString().replace('/', '.'));
791 } else if (oop.isKlass()) {
792 writeln(oop.name.asString().replace('/', '.'));
793 } else {
794 writeln(cpIndex);
795 }
796 }
797 }
798 }
799
800 // print Java bytecode disassembly
801 function jdis(method) {
802 if (method.getByteCode == undefined) {
803 // method oop may be specified by address
804 method = addr2oop(any2addr(method));
805 }
806 writeln(method, '-', method.externalNameAndSignature());
807 if (method.isNative()) {
808 writeln("native method");
809 return;
810 }
811 if (method.isAbstract()) {
812 writeln("abstract method");
813 return;
814 }
815
816 writeln();
817 var BytecodeDisAsmClass = sapkg.interpreter.BytecodeDisassembler;
818 var disAsm = new BytecodeDisAsmClass(method);
819 var bci = 0;
820 var hasLines = method.hasLineNumberTable();
821 if (hasLines) {
822 writeln("bci", '\t', "line", '\t', "instruction");
823 } else {
824 writeln("bci", '\t', "instruction");
825 }
826 writeln("");
827 disAsm.decode(new sapkg.interpreter.BytecodeVisitor() {
828 prologue: function(method) { },
829 epilogue: function() { },
830 visit: function(bytecode) {
831 if (hasLines) {
832 var line = method.getLineNumberFromBCI(bci);
833 writeln(bci, '\t', line, '\t', bytecode);
834 } else {
835 writeln(bci, '\t', bytecode);
836 }
837 bci++;
838 }
839 });
840
841 writeln();
842 printExceptionTable(method);
843 } 544 }
844 545
845 // Java thread 546 // Java thread
846 547
847 // iterates each Thread 548 // iterates each Thread