Mercurial > hg > truffle
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 |