NashornTextifier.java revision 1298:776551a5b3a2
11541Srgrimes/* 21541Srgrimes * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. 31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41541Srgrimes * 51541Srgrimes * This code is free software; you can redistribute it and/or modify it 61541Srgrimes * under the terms of the GNU General Public License version 2 only, as 71541Srgrimes * published by the Free Software Foundation. Oracle designates this 81541Srgrimes * particular file as subject to the "Classpath" exception as provided 91541Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101541Srgrimes * 111541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151541Srgrimes * accompanied this code). 161541Srgrimes * 171541Srgrimes * You should have received a copy of the GNU General Public License version 181541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201541Srgrimes * 211541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221541Srgrimes * or visit www.oracle.com if you need additional information or have any 231541Srgrimes * questions. 241541Srgrimes */ 251541Srgrimes 261541Srgrimespackage jdk.nashorn.internal.ir.debug; 271541Srgrimes 281541Srgrimesimport static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT; 2914505Shsuimport static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.FLAGS_MASK; 3050477Speter 311541Srgrimesimport java.io.File; 321541Srgrimesimport java.io.FileNotFoundException; 332165Spaulimport java.io.FileOutputStream; 342165Spaulimport java.io.PrintWriter; 352165Spaulimport java.util.HashMap; 3615492Sbdeimport java.util.HashSet; 3770834Swollmanimport java.util.Iterator; 38130380Srwatsonimport java.util.LinkedHashSet; 39130380Srwatsonimport java.util.List; 401541Srgrimesimport java.util.Map; 411541Srgrimesimport java.util.Set; 421541Srgrimesimport jdk.internal.org.objectweb.asm.Attribute; 431541Srgrimesimport jdk.internal.org.objectweb.asm.Handle; 441541Srgrimesimport jdk.internal.org.objectweb.asm.Label; 451541Srgrimesimport jdk.internal.org.objectweb.asm.Opcodes; 461541Srgrimesimport jdk.internal.org.objectweb.asm.Type; 4736079Swollmanimport jdk.internal.org.objectweb.asm.signature.SignatureReader; 4836079Swollmanimport jdk.internal.org.objectweb.asm.util.Printer; 49129958Srwatsonimport jdk.internal.org.objectweb.asm.util.TraceSignatureVisitor; 50129958Srwatsonimport jdk.nashorn.internal.runtime.ScriptEnvironment; 51129958Srwatsonimport jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 52129958Srwatson 53129958Srwatson/** 54129958Srwatson * Pretty printer for --print-code. 55129958Srwatson * Also supports dot formats if --print-code has arguments 56129958Srwatson */ 57129958Srwatsonpublic final class NashornTextifier extends Printer { 58131168Srwatson 5995552Stanimura private String currentClassName; 601541Srgrimes private Iterator<Label> labelIter; 61130387Srwatson private Graph graph; 62129958Srwatson private String currentBlock; 6397658Stanimura 6497658Stanimura // Following variables are used to govern the state of collapsing long sequences of NOP. 65130818Srwatson /** True if the last instruction was a NOP. */ 66129979Srwatson private boolean lastWasNop = false; 6798993Salfred /** True if ellipse ("...") was emitted in place of a second NOP. */ 68129958Srwatson private boolean lastWasEllipse = false; 691541Srgrimes 7013765Smpp private static final int INTERNAL_NAME = 0; 711541Srgrimes private static final int FIELD_DESCRIPTOR = 1; 721541Srgrimes private static final int FIELD_SIGNATURE = 2; 7378913Sjlemon private static final int METHOD_DESCRIPTOR = 3; 7478913Sjlemon private static final int METHOD_SIGNATURE = 4; 751541Srgrimes private static final int CLASS_SIGNATURE = 5; 7678913Sjlemon 771541Srgrimes private final String tab = " "; 781541Srgrimes private final String tab2 = " "; 791541Srgrimes private final String tab3 = " "; 80129979Srwatson 81129979Srwatson private Map<Label, String> labelNames; 82129979Srwatson 83129979Srwatson private boolean localVarsStarted = false; 84140730Sglebius 85140730Sglebius private NashornClassReader cr; 8618787Spst private ScriptEnvironment env; 87140730Sglebius 88130527Srwatson /** 89131029Srwatson * Constructs a new {@link NashornTextifier}. <i>Subclasses must not use this 9097658Stanimura * constructor</i>. Instead, they must use the {@link #NashornTextifier(int)} 9141087Struckman * version. 92131017Srwatson * @param env script environment 9397658Stanimura * @param cr a customized classreader for gathering, among other things, label 941541Srgrimes * information 951541Srgrimes */ 961541Srgrimes public NashornTextifier(final ScriptEnvironment env, final NashornClassReader cr) { 9783421Sobrien this(Opcodes.ASM5); 98100591Sjdp this.env = env; 99130380Srwatson this.cr = cr; 100141052Sglebius } 101117708Srobert 102130527Srwatson private NashornTextifier(final ScriptEnvironment env, final NashornClassReader cr, final Iterator<Label> labelIter, final Graph graph) { 103130527Srwatson this(env, cr); 104130527Srwatson this.labelIter = labelIter; 105130527Srwatson this.graph = graph; 106130527Srwatson } 107130527Srwatson 108130527Srwatson /** 109130527Srwatson * Constructs a new {@link NashornTextifier}. 110130527Srwatson * 111130527Srwatson * @param api 112130527Srwatson * the ASM API version implemented by this visitor. Must be one 113130527Srwatson * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. 1141541Srgrimes */ 115130818Srwatson protected NashornTextifier(final int api) { 116130818Srwatson super(api); 117130818Srwatson } 1181541Srgrimes 119131022Srwatson @Override 120131022Srwatson public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { 121131022Srwatson final int major = version & 0xFFFF; 1221541Srgrimes final int minor = version >>> 16; 1231541Srgrimes 1241541Srgrimes currentClassName = name; 1251541Srgrimes 1261541Srgrimes final StringBuilder sb = new StringBuilder(); 12736527Speter sb.append("// class version "). 1281541Srgrimes append(major). 12955943Sjasone append('.'). 13059288Sjlemon append(minor).append(" ("). 1311541Srgrimes append(version). 13297658Stanimura append(")\n"); 13397658Stanimura 134130527Srwatson if ((access & Opcodes.ACC_DEPRECATED) != 0) { 135130398Srwatson sb.append("// DEPRECATED\n"); 136130398Srwatson } 13738482Swollman 138131168Srwatson sb.append("// access flags 0x"). //TODO TRANSLATE TO WHAT THEY MEAN 13997658Stanimura append(Integer.toHexString(access).toUpperCase()). 14097658Stanimura append('\n'); 14197658Stanimura 14297658Stanimura appendDescriptor(sb, CLASS_SIGNATURE, signature); 14397658Stanimura if (signature != null) { 14497658Stanimura final TraceSignatureVisitor sv = new TraceSignatureVisitor(access); 1451541Srgrimes final SignatureReader r = new SignatureReader(signature); 1461541Srgrimes r.accept(sv); 147121628Ssam sb.append("// declaration: "). 148121628Ssam append(name). 149121628Ssam append(sv.getDeclaration()). 150121628Ssam append('\n'); 151121628Ssam } 152121628Ssam 153121628Ssam appendAccess(sb, access & ~Opcodes.ACC_SUPER); 1541541Srgrimes if ((access & Opcodes.ACC_ANNOTATION) != 0) { 155129979Srwatson sb.append("@interface "); 156129979Srwatson } else if ((access & Opcodes.ACC_INTERFACE) != 0) { 157129979Srwatson sb.append("interface "); 158129979Srwatson } else if ((access & Opcodes.ACC_ENUM) == 0) { 159129979Srwatson sb.append("class "); 160129979Srwatson } 161136682Srwatson appendDescriptor(sb, INTERNAL_NAME, name); 162136682Srwatson 163130364Srwatson if (superName != null && !"java/lang/Object".equals(superName)) { 164130364Srwatson sb.append(" extends "); 165129979Srwatson appendDescriptor(sb, INTERNAL_NAME, superName); 166129979Srwatson sb.append(' '); 167130380Srwatson } 168130380Srwatson if (interfaces != null && interfaces.length > 0) { 169130380Srwatson sb.append(" implements "); 170130380Srwatson for (final String interface1 : interfaces) { 171130380Srwatson appendDescriptor(sb, INTERNAL_NAME, interface1); 172130380Srwatson sb.append(' '); 173130380Srwatson } 174130380Srwatson } 175130380Srwatson sb.append(" {\n"); 176130380Srwatson 177130380Srwatson addText(sb); 178136326Srwatson } 179130380Srwatson 180130380Srwatson @Override 181130380Srwatson public void visitSource(final String file, final String debug) { 182130380Srwatson final StringBuilder sb = new StringBuilder(); 183130380Srwatson if (file != null) { 184130380Srwatson sb.append(tab). 185130380Srwatson append("// compiled from: "). 186130380Srwatson append(file). 187130380Srwatson append('\n'); 188130380Srwatson } 189130380Srwatson if (debug != null) { 190130380Srwatson sb.append(tab). 191130492Srwatson append("// debug info: "). 1921541Srgrimes append(debug). 193130480Srwatson append('\n'); 194130480Srwatson } 195130480Srwatson if (sb.length() > 0) { 196130480Srwatson addText(sb); 197130480Srwatson } 198130480Srwatson } 199130480Srwatson 200130480Srwatson @Override 201130480Srwatson public void visitOuterClass(final String owner, final String name, final String desc) { 2021541Srgrimes final StringBuilder sb = new StringBuilder(); 20314547Sdg sb.append(tab).append("outer class "); 20414547Sdg appendDescriptor(sb, INTERNAL_NAME, owner); 20514547Sdg sb.append(' '); 20614547Sdg if (name != null) { 20714547Sdg sb.append(name).append(' '); 20814547Sdg } 20914547Sdg appendDescriptor(sb, METHOD_DESCRIPTOR, desc); 21043196Sfenner sb.append('\n'); 2111541Srgrimes addText(sb); 21236079Swollman } 213130480Srwatson 214130480Srwatson @Override 215130480Srwatson public NashornTextifier visitField(final int access, final String name, final String desc, final String signature, final Object value) { 216130480Srwatson final StringBuilder sb = new StringBuilder(); 217130480Srwatson// sb.append('\n'); 218130480Srwatson if ((access & Opcodes.ACC_DEPRECATED) != 0) { 219130480Srwatson sb.append(tab).append("// DEPRECATED\n"); 220129916Srwatson } 221129916Srwatson 222129916Srwatson/* sb.append(tab). 223129916Srwatson append("// access flags 0x"). 224129916Srwatson append(Integer.toHexString(access).toUpperCase()). 225129916Srwatson append('\n'); 22636079Swollman*/ 22736079Swollman 22883045Sobrien if (signature != null) { 22936079Swollman sb.append(tab); 23036079Swollman appendDescriptor(sb, FIELD_SIGNATURE, signature); 23136079Swollman 23236079Swollman final TraceSignatureVisitor sv = new TraceSignatureVisitor(0); 23336079Swollman final SignatureReader r = new SignatureReader(signature); 23436079Swollman r.acceptType(sv); 23536079Swollman sb.append(tab). 23636079Swollman append("// declaration: "). 23736079Swollman append(sv.getDeclaration()). 238140730Sglebius append('\n'); 239140730Sglebius } 240140730Sglebius 24136079Swollman sb.append(tab); 24236079Swollman appendAccess(sb, access); 24336079Swollman 24436079Swollman final String prunedDesc = desc.endsWith(";") ? desc.substring(0, desc.length() - 1) : desc; 24583421Sobrien appendDescriptor(sb, FIELD_DESCRIPTOR, prunedDesc); 246100591Sjdp sb.append(' ').append(name); 247100591Sjdp if (value != null) { 248100591Sjdp sb.append(" = "); 249100591Sjdp if (value instanceof String) { 250100591Sjdp sb.append('\"').append(value).append('\"'); 251100591Sjdp } else { 25236079Swollman sb.append(value); 25336079Swollman } 25436079Swollman } 25536079Swollman 25614547Sdg sb.append(";\n"); 257130393Srwatson addText(sb); 258130393Srwatson 2591541Srgrimes final NashornTextifier t = createNashornTextifier(); 2601541Srgrimes addText(t.getText()); 2611541Srgrimes 2621541Srgrimes return t; 2631541Srgrimes } 26436527Speter 26536527Speter @Override 26655943Sjasone public NashornTextifier visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) { 26759288Sjlemon 26836527Speter graph = new Graph(name); 26936527Speter 2701541Srgrimes final List<Label> extraLabels = cr.getExtraLabels(currentClassName, name, desc); 2711541Srgrimes this.labelIter = extraLabels == null ? null : extraLabels.iterator(); 2721541Srgrimes 2731541Srgrimes final StringBuilder sb = new StringBuilder(); 2741541Srgrimes 2751541Srgrimes sb.append('\n'); 2761541Srgrimes if ((access & Opcodes.ACC_DEPRECATED) != 0) { 2771541Srgrimes sb.append(tab). 2781541Srgrimes append("// DEPRECATED\n"); 2791541Srgrimes } 2801541Srgrimes 2811541Srgrimes sb.append(tab). 2821541Srgrimes append("// access flags 0x"). 2831541Srgrimes append(Integer.toHexString(access).toUpperCase()). 2841541Srgrimes append('\n'); 2851541Srgrimes 286130480Srwatson if (signature != null) { 28770536Sphk sb.append(tab); 2881541Srgrimes appendDescriptor(sb, METHOD_SIGNATURE, signature); 2891541Srgrimes 2901541Srgrimes final TraceSignatureVisitor v = new TraceSignatureVisitor(0); 2913304Sphk final SignatureReader r = new SignatureReader(signature); 2921541Srgrimes r.accept(v); 2933304Sphk final String genericDecl = v.getDeclaration(); 294130480Srwatson final String genericReturn = v.getReturnType(); 2951541Srgrimes final String genericExceptions = v.getExceptions(); 2961541Srgrimes 2971541Srgrimes sb.append(tab). 2981541Srgrimes append("// declaration: "). 2991541Srgrimes append(genericReturn). 300109098Stjr append(' '). 301109098Stjr append(name). 302106313Skbyanc append(genericDecl); 3031541Srgrimes 3041541Srgrimes if (genericExceptions != null) { 3051541Srgrimes sb.append(" throws ").append(genericExceptions); 3061541Srgrimes } 3071541Srgrimes sb.append('\n'); 3081541Srgrimes } 3091541Srgrimes 3101541Srgrimes sb.append(tab); 311109098Stjr appendAccess(sb, access); 312109098Stjr if ((access & Opcodes.ACC_NATIVE) != 0) { 313106313Skbyanc sb.append("native "); 3141541Srgrimes } 3151541Srgrimes if ((access & Opcodes.ACC_VARARGS) != 0) { 3161541Srgrimes sb.append("varargs "); 3171541Srgrimes } 3181541Srgrimes if ((access & Opcodes.ACC_BRIDGE) != 0) { 3191541Srgrimes sb.append("bridge "); 3201541Srgrimes } 3211541Srgrimes 3221541Srgrimes sb.append(name); 3231541Srgrimes appendDescriptor(sb, METHOD_DESCRIPTOR, desc); 3241541Srgrimes if (exceptions != null && exceptions.length > 0) { 325111119Simp sb.append(" throws "); 3261541Srgrimes for (final String exception : exceptions) { 3271541Srgrimes appendDescriptor(sb, INTERNAL_NAME, exception); 3281541Srgrimes sb.append(' '); 329130831Srwatson } 330130831Srwatson } 3311541Srgrimes 3321541Srgrimes sb.append('\n'); 3331541Srgrimes addText(sb); 334111748Sdes 3351541Srgrimes final NashornTextifier t = createNashornTextifier(); 336130831Srwatson addText(t.getText()); 3371541Srgrimes return t; 33886487Sdillon } 33986487Sdillon 34086487Sdillon @Override 34186487Sdillon public void visitClassEnd() { 34286487Sdillon addText("}\n"); 343130383Srwatson } 344130387Srwatson 345130383Srwatson @Override 346130383Srwatson public void visitFieldEnd() { 34786487Sdillon //empty 348130383Srwatson } 349136682Srwatson 350130387Srwatson @Override 351130383Srwatson public void visitParameter(final String name, final int access) { 352130383Srwatson final StringBuilder sb = new StringBuilder(); 353130383Srwatson sb.append(tab2).append("// parameter "); 354130383Srwatson appendAccess(sb, access); 355136682Srwatson sb.append(' ').append(name == null ? "<no name>" : name) 356130387Srwatson .append('\n'); 357136682Srwatson addText(sb); 358136682Srwatson } 359130383Srwatson 36086487Sdillon @Override 361130383Srwatson public void visitCode() { 362136682Srwatson //empty 363130387Srwatson } 364130383Srwatson 365130383Srwatson @Override 366136682Srwatson public void visitFrame(final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack) { 367130387Srwatson final StringBuilder sb = new StringBuilder(); 368136682Srwatson sb.append("frame "); 369136682Srwatson switch (type) { 370130383Srwatson case Opcodes.F_NEW: 37186487Sdillon case Opcodes.F_FULL: 372130831Srwatson sb.append("full ["); 373130831Srwatson appendFrameTypes(sb, nLocal, local); 374130831Srwatson sb.append("] ["); 375130831Srwatson appendFrameTypes(sb, nStack, stack); 376130831Srwatson sb.append(']'); 377130831Srwatson break; 378130831Srwatson case Opcodes.F_APPEND: 379130831Srwatson sb.append("append ["); 380130831Srwatson appendFrameTypes(sb, nLocal, local); 381130831Srwatson sb.append(']'); 382130383Srwatson break; 383130831Srwatson case Opcodes.F_CHOP: 384130831Srwatson sb.append("chop ").append(nLocal); 385130831Srwatson break; 386130383Srwatson case Opcodes.F_SAME: 3871541Srgrimes sb.append("same"); 388130831Srwatson break; 389130831Srwatson case Opcodes.F_SAME1: 390130831Srwatson sb.append("same1 "); 391130831Srwatson appendFrameTypes(sb, 1, stack); 392130831Srwatson break; 393130831Srwatson default: 394131029Srwatson assert false; 395130383Srwatson break; 396130383Srwatson } 397130831Srwatson sb.append('\n'); 398130831Srwatson sb.append('\n'); 399130383Srwatson addText(sb); 4001541Srgrimes } 401130831Srwatson 402130831Srwatson private StringBuilder appendOpcode(final StringBuilder sb, final int opcode) { 403130831Srwatson final Label next = getNextLabel(); 404130831Srwatson if (next instanceof NashornLabel) { 405130831Srwatson final int bci = next.getOffset(); 40638482Swollman if (bci != -1) { 40738482Swollman final String bcis = "" + bci; 40838482Swollman for (int i = 0; i < 5 - bcis.length(); i++) { 40938482Swollman sb.append(' '); 41038482Swollman } 41138482Swollman sb.append(bcis); 41238482Swollman sb.append(' '); 41338482Swollman } else { 41438482Swollman sb.append(" "); 41538482Swollman } 41638482Swollman } 41795959Salfred 41838482Swollman return sb.append(tab2).append(OPCODES[opcode].toLowerCase()); 41938482Swollman } 42061837Salfred 42161837Salfred private Label getNextLabel() { 42261837Salfred return labelIter == null ? null : labelIter.next(); 42392719Salfred } 42461837Salfred 42592719Salfred @Override 42661837Salfred public void visitInsn(final int opcode) { 42792719Salfred if(opcode == Opcodes.NOP) { 42895959Salfred if(lastWasEllipse) { 42982656Sjlemon getNextLabel(); 43061837Salfred return; 43131927Sbde } else if(lastWasNop) { 43295959Salfred getNextLabel(); 43331927Sbde addText(" ...\n"); 43431927Sbde lastWasEllipse = true; 43531927Sbde return; 43631927Sbde } else { 43795959Salfred lastWasNop = true; 4382112Swollman } 43995959Salfred } else { 44036079Swollman lastWasNop = lastWasEllipse = false; 44114505Shsu } 44215492Sbde final StringBuilder sb = new StringBuilder(); 44315492Sbde appendOpcode(sb, opcode).append('\n'); 44432995Sbde addText(sb); 44532995Sbde checkNoFallThru(opcode, null); 44615492Sbde } 4471541Srgrimes 4483304Sphk @Override 4493304Sphk public void visitIntInsn(final int opcode, final int operand) { 450142058Srwatson final StringBuilder sb = new StringBuilder(); 451132060Sdwmalone appendOpcode(sb, opcode) 452132060Sdwmalone .append(' ') 45392719Salfred .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer 45492719Salfred .toString(operand)).append('\n'); 45592719Salfred addText(sb); 456130831Srwatson } 457121628Ssam 458130831Srwatson @Override 459130050Srwatson public void visitVarInsn(final int opcode, final int var) { 46092719Salfred final StringBuilder sb = new StringBuilder(); 461130831Srwatson appendOpcode(sb, opcode).append(' ').append(var).append('\n'); 462130831Srwatson addText(sb); 46392719Salfred } 46492719Salfred 465130831Srwatson @Override 466130831Srwatson public void visitTypeInsn(final int opcode, final String type) { 46792719Salfred final StringBuilder sb = new StringBuilder(); 468130831Srwatson appendOpcode(sb, opcode).append(' '); 46992719Salfred appendDescriptor(sb, INTERNAL_NAME, type); 47092719Salfred sb.append('\n'); 47119670Sbde addText(sb); 47292719Salfred } 47392719Salfred 474130831Srwatson @Override 47592719Salfred public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) { 476130831Srwatson final StringBuilder sb = new StringBuilder(); 47792719Salfred appendOpcode(sb, opcode).append(' '); 478130831Srwatson appendDescriptor(sb, INTERNAL_NAME, owner); 47992719Salfred sb.append('.').append(name).append(" : "); 480130831Srwatson appendDescriptor(sb, FIELD_DESCRIPTOR, desc); 48192719Salfred sb.append('\n'); 482130831Srwatson addText(sb); 48392719Salfred } 48493008Sbde 485131006Srwatson @Override 486131006Srwatson public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf) { 48792719Salfred final StringBuilder sb = new StringBuilder(); 48892719Salfred appendOpcode(sb, opcode).append(' '); 48992719Salfred appendDescriptor(sb, INTERNAL_NAME, owner); 49092719Salfred sb.append('.').append(name); 49192719Salfred appendDescriptor(sb, METHOD_DESCRIPTOR, desc); 492126411Srwatson sb.append('\n'); 49395959Salfred addText(sb); 49492719Salfred } 49592719Salfred 496130831Srwatson @Override 49792719Salfred public void visitInvokeDynamicInsn(final String name, final String desc, final Handle bsm, final Object... bsmArgs) { 498130831Srwatson final StringBuilder sb = new StringBuilder(); 49992719Salfred 50092719Salfred appendOpcode(sb, Opcodes.INVOKEDYNAMIC).append(' '); 50192719Salfred sb.append(name); 50298849Sken appendDescriptor(sb, METHOD_DESCRIPTOR, desc); 50392719Salfred final int len = sb.length(); 50492719Salfred for (int i = 0; i < 80 - len ; i++) { 505106326Salc sb.append(' '); 50692719Salfred } 507126425Srwatson sb.append(" ["); 50892719Salfred appendHandle(sb, bsm); 50992719Salfred if (bsmArgs.length == 0) { 51092719Salfred sb.append("none"); 51192719Salfred } else { 51292719Salfred for (final Object cst : bsmArgs) { 51392719Salfred if (cst instanceof String) { 51492719Salfred appendStr(sb, (String)cst); 51592719Salfred } else if (cst instanceof Type) { 516142190Srwatson sb.append(((Type)cst).getDescriptor()).append(".class"); 517142190Srwatson } else if (cst instanceof Handle) { 51814505Shsu appendHandle(sb, (Handle)cst); 51992719Salfred } else if (cst instanceof Integer) { 52093008Sbde final int c = (Integer)cst; 521118453Shsu final int pp = c >> CALLSITE_PROGRAM_POINT_SHIFT; 52253541Sshin if (pp != 0) { 52353541Sshin sb.append(" pp=").append(pp); 52492719Salfred } 52592719Salfred sb.append(NashornCallSiteDescriptor.toString(c & FLAGS_MASK)); 52692719Salfred } else { 52753541Sshin sb.append(cst); 528101983Srwatson } 52993008Sbde sb.append(", "); 53093008Sbde } 53193008Sbde sb.setLength(sb.length() - 2); 53292719Salfred } 53392719Salfred 53492719Salfred sb.append("]\n"); 53593008Sbde addText(sb); 53693008Sbde } 53792719Salfred 53892719Salfred private static final boolean noFallThru(final int opcode) { 53992719Salfred switch (opcode) { 54092719Salfred case Opcodes.GOTO: 54131927Sbde case Opcodes.ATHROW: 542121628Ssam case Opcodes.ARETURN: 543121628Ssam case Opcodes.IRETURN: 544121628Ssam case Opcodes.LRETURN: 545121628Ssam case Opcodes.FRETURN: 546121628Ssam case Opcodes.DRETURN: 547121628Ssam return true; 548121628Ssam default: 549121628Ssam return false; 550121628Ssam } 551121628Ssam } 552121628Ssam 55395959Salfred private void checkNoFallThru(final int opcode, final String to) { 55495959Salfred if (noFallThru(opcode)) { 55595959Salfred graph.setNoFallThru(currentBlock); 55692719Salfred } 55792719Salfred 55895959Salfred if (currentBlock != null && to != null) { 55961837Salfred graph.addEdge(currentBlock, to); 56095959Salfred } 56165534Salfred } 56295959Salfred 56395959Salfred @Override 56495959Salfred public void visitJumpInsn(final int opcode, final Label label) { 56561837Salfred final StringBuilder sb = new StringBuilder(); 56655205Speter appendOpcode(sb, opcode).append(' '); 5672165Spaul final String to = appendLabel(sb, label); 56814505Shsu sb.append('\n'); 569 addText(sb); 570 checkNoFallThru(opcode, to); 571 } 572 573 private void addText(final Object t) { 574 text.add(t); 575 if (currentBlock != null) { 576 graph.addText(currentBlock, t.toString()); 577 } 578 } 579 580 @Override 581 public void visitLabel(final Label label) { 582 final StringBuilder sb = new StringBuilder(); 583 sb.append("\n"); 584 final String name = appendLabel(sb, label); 585 sb.append(" [bci="); 586 sb.append(label.info); 587 sb.append("]"); 588 sb.append("\n"); 589 590 graph.addNode(name); 591 if (currentBlock != null && !graph.isNoFallThru(currentBlock)) { 592 graph.addEdge(currentBlock, name); 593 } 594 currentBlock = name; 595 addText(sb); 596 } 597 598 @Override 599 public void visitLdcInsn(final Object cst) { 600 final StringBuilder sb = new StringBuilder(); 601 appendOpcode(sb, Opcodes.LDC).append(' '); 602 if (cst instanceof String) { 603 appendStr(sb, (String) cst); 604 } else if (cst instanceof Type) { 605 sb.append(((Type) cst).getDescriptor()).append(".class"); 606 } else { 607 sb.append(cst); 608 } 609 sb.append('\n'); 610 addText(sb); 611 } 612 613 @Override 614 public void visitIincInsn(final int var, final int increment) { 615 final StringBuilder sb = new StringBuilder(); 616 appendOpcode(sb, Opcodes.IINC).append(' '); 617 sb.append(var).append(' ') 618 .append(increment).append('\n'); 619 addText(sb); 620 } 621 622 @Override 623 public void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels) { 624 final StringBuilder sb = new StringBuilder(); 625 appendOpcode(sb, Opcodes.TABLESWITCH).append(' '); 626 for (int i = 0; i < labels.length; ++i) { 627 sb.append(tab3).append(min + i).append(": "); 628 final String to = appendLabel(sb, labels[i]); 629 graph.addEdge(currentBlock, to); 630 sb.append('\n'); 631 } 632 sb.append(tab3).append("default: "); 633 appendLabel(sb, dflt); 634 sb.append('\n'); 635 addText(sb); 636 } 637 638 @Override 639 public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { 640 final StringBuilder sb = new StringBuilder(); 641 appendOpcode(sb, Opcodes.LOOKUPSWITCH).append(' '); 642 for (int i = 0; i < labels.length; ++i) { 643 sb.append(tab3).append(keys[i]).append(": "); 644 final String to = appendLabel(sb, labels[i]); 645 graph.addEdge(currentBlock, to); 646 sb.append('\n'); 647 } 648 sb.append(tab3).append("default: "); 649 final String to = appendLabel(sb, dflt); 650 graph.addEdge(currentBlock, to); 651 sb.append('\n'); 652 addText(sb.toString()); 653 } 654 655 @Override 656 public void visitMultiANewArrayInsn(final String desc, final int dims) { 657 final StringBuilder sb = new StringBuilder(); 658 appendOpcode(sb, Opcodes.MULTIANEWARRAY).append(' '); 659 appendDescriptor(sb, FIELD_DESCRIPTOR, desc); 660 sb.append(' ').append(dims).append('\n'); 661 addText(sb); 662 } 663 664 @Override 665 public void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type) { 666 final StringBuilder sb = new StringBuilder(); 667 sb.append(tab2).append("try "); 668 final String from = appendLabel(sb, start); 669 sb.append(' '); 670 appendLabel(sb, end); 671 sb.append(' '); 672 final String to = appendLabel(sb, handler); 673 sb.append(' '); 674 appendDescriptor(sb, INTERNAL_NAME, type); 675 sb.append('\n'); 676 addText(sb); 677 graph.setIsCatch(to, type); 678 graph.addTryCatch(from, to); 679 } 680 681 @Override 682 public void visitLocalVariable(final String name, final String desc,final String signature, final Label start, final Label end, final int index) { 683 684 final StringBuilder sb = new StringBuilder(); 685 if (!localVarsStarted) { 686 text.add("\n"); 687 localVarsStarted = true; 688 graph.addNode("vars"); 689 currentBlock = "vars"; 690 } 691 692 sb.append(tab2).append("local ").append(name).append(' '); 693 final int len = sb.length(); 694 for (int i = 0; i < 25 - len; i++) { 695 sb.append(' '); 696 } 697 String label; 698 699 label = appendLabel(sb, start); 700 for (int i = 0; i < 5 - label.length(); i++) { 701 sb.append(' '); 702 } 703 label = appendLabel(sb, end); 704 for (int i = 0; i < 5 - label.length(); i++) { 705 sb.append(' '); 706 } 707 708 sb.append(index).append(tab2); 709 710 appendDescriptor(sb, FIELD_DESCRIPTOR, desc); 711 sb.append('\n'); 712 713 if (signature != null) { 714 sb.append(tab2); 715 appendDescriptor(sb, FIELD_SIGNATURE, signature); 716 717 final TraceSignatureVisitor sv = new TraceSignatureVisitor(0); 718 final SignatureReader r = new SignatureReader(signature); 719 r.acceptType(sv); 720 sb.append(tab2).append("// declaration: ") 721 .append(sv.getDeclaration()).append('\n'); 722 } 723 addText(sb.toString()); 724 } 725 726 @Override 727 public void visitLineNumber(final int line, final Label start) { 728 final StringBuilder sb = new StringBuilder(); 729 sb.append("<line "); 730 sb.append(line); 731 sb.append(">\n"); 732 addText(sb.toString()); 733 } 734 735 @Override 736 public void visitMaxs(final int maxStack, final int maxLocals) { 737 final StringBuilder sb = new StringBuilder(); 738 sb.append('\n'); 739 sb.append(tab2).append("max stack = ").append(maxStack); 740 sb.append(", max locals = ").append(maxLocals).append('\n'); 741 addText(sb.toString()); 742 } 743 744 private void printToDir(final Graph g) { 745 if (env._print_code_dir != null) { 746 final File dir = new File(env._print_code_dir); 747 if (!dir.exists() && !dir.mkdirs()) { 748 throw new RuntimeException(dir.toString()); 749 } 750 751 File file; 752 int uniqueId = 0; 753 do { 754 final String fileName = g.getName() + (uniqueId == 0 ? "" : "_" + uniqueId) + ".dot"; 755 file = new File(dir, fileName); 756 uniqueId++; 757 } while (file.exists()); 758 759 try (PrintWriter pw = new PrintWriter(new FileOutputStream(file))) { 760 pw.println(g); 761 } catch (final FileNotFoundException e) { 762 throw new RuntimeException(e); 763 } 764 } 765 } 766 767 @Override 768 public void visitMethodEnd() { 769 //here we need to do several bytecode guesses best upon the ldc instructions. 770 //for each instruction, assign bci. for an ldc/w/2w, guess a byte and keep 771 //iterating. if the next label is wrong, backtrack. 772 if (env._print_code_func == null || env._print_code_func.equals(graph.getName())) { 773 if (env._print_code_dir != null) { 774 printToDir(graph); 775 } 776 } 777 } 778 779 /** 780 * Creates a new TraceVisitor instance. 781 * 782 * @return a new TraceVisitor. 783 */ 784 protected NashornTextifier createNashornTextifier() { 785 return new NashornTextifier(env, cr, labelIter, graph); 786 } 787 788 private static void appendDescriptor(final StringBuilder sb, final int type, final String desc) { 789 if (desc != null) { 790 if (type == CLASS_SIGNATURE || type == FIELD_SIGNATURE || type == METHOD_SIGNATURE) { 791 sb.append("// signature ").append(desc).append('\n'); 792 } else { 793 appendShortDescriptor(sb, desc); 794 } 795 } 796 } 797 798 private String appendLabel(final StringBuilder sb, final Label l) { 799 if (labelNames == null) { 800 labelNames = new HashMap<>(); 801 } 802 String name = labelNames.get(l); 803 if (name == null) { 804 name = "L" + labelNames.size(); 805 labelNames.put(l, name); 806 } 807 sb.append(name); 808 return name; 809 } 810 811 private static void appendHandle(final StringBuilder sb, final Handle h) { 812 switch (h.getTag()) { 813 case Opcodes.H_GETFIELD: 814 sb.append("getfield"); 815 break; 816 case Opcodes.H_GETSTATIC: 817 sb.append("getstatic"); 818 break; 819 case Opcodes.H_PUTFIELD: 820 sb.append("putfield"); 821 break; 822 case Opcodes.H_PUTSTATIC: 823 sb.append("putstatic"); 824 break; 825 case Opcodes.H_INVOKEINTERFACE: 826 sb.append("interface"); 827 break; 828 case Opcodes.H_INVOKESPECIAL: 829 sb.append("special"); 830 break; 831 case Opcodes.H_INVOKESTATIC: 832 sb.append("static"); 833 break; 834 case Opcodes.H_INVOKEVIRTUAL: 835 sb.append("virtual"); 836 break; 837 case Opcodes.H_NEWINVOKESPECIAL: 838 sb.append("new_special"); 839 break; 840 default: 841 assert false; 842 break; 843 } 844 sb.append(" '"); 845 sb.append(h.getName()); 846 sb.append("'"); 847 } 848 849 private static void appendAccess(final StringBuilder sb, final int access) { 850 if ((access & Opcodes.ACC_PUBLIC) != 0) { 851 sb.append("public "); 852 } 853 if ((access & Opcodes.ACC_PRIVATE) != 0) { 854 sb.append("private "); 855 } 856 if ((access & Opcodes.ACC_PROTECTED) != 0) { 857 sb.append("protected "); 858 } 859 if ((access & Opcodes.ACC_FINAL) != 0) { 860 sb.append("final "); 861 } 862 if ((access & Opcodes.ACC_STATIC) != 0) { 863 sb.append("static "); 864 } 865 if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { 866 sb.append("synchronized "); 867 } 868 if ((access & Opcodes.ACC_VOLATILE) != 0) { 869 sb.append("volatile "); 870 } 871 if ((access & Opcodes.ACC_TRANSIENT) != 0) { 872 sb.append("transient "); 873 } 874 if ((access & Opcodes.ACC_ABSTRACT) != 0) { 875 sb.append("abstract "); 876 } 877 if ((access & Opcodes.ACC_STRICT) != 0) { 878 sb.append("strictfp "); 879 } 880 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 881 sb.append("synthetic "); 882 } 883 if ((access & Opcodes.ACC_MANDATED) != 0) { 884 sb.append("mandated "); 885 } 886 if ((access & Opcodes.ACC_ENUM) != 0) { 887 sb.append("enum "); 888 } 889 } 890 891 private void appendFrameTypes(final StringBuilder sb, final int n, final Object[] o) { 892 for (int i = 0; i < n; ++i) { 893 if (i > 0) { 894 sb.append(' '); 895 } 896 if (o[i] instanceof String) { 897 final String desc = (String) o[i]; 898 if (desc.startsWith("[")) { 899 appendDescriptor(sb, FIELD_DESCRIPTOR, desc); 900 } else { 901 appendDescriptor(sb, INTERNAL_NAME, desc); 902 } 903 } else if (o[i] instanceof Integer) { 904 switch (((Integer)o[i]).intValue()) { 905 case 0: 906 appendDescriptor(sb, FIELD_DESCRIPTOR, "T"); 907 break; 908 case 1: 909 appendDescriptor(sb, FIELD_DESCRIPTOR, "I"); 910 break; 911 case 2: 912 appendDescriptor(sb, FIELD_DESCRIPTOR, "F"); 913 break; 914 case 3: 915 appendDescriptor(sb, FIELD_DESCRIPTOR, "D"); 916 break; 917 case 4: 918 appendDescriptor(sb, FIELD_DESCRIPTOR, "J"); 919 break; 920 case 5: 921 appendDescriptor(sb, FIELD_DESCRIPTOR, "N"); 922 break; 923 case 6: 924 appendDescriptor(sb, FIELD_DESCRIPTOR, "U"); 925 break; 926 default: 927 assert false; 928 break; 929 } 930 } else { 931 appendLabel(sb, (Label) o[i]); 932 } 933 } 934 } 935 936 private static void appendShortDescriptor(final StringBuilder sb, final String desc) { 937 //final StringBuilder buf = new StringBuilder(); 938 if (desc.charAt(0) == '(') { 939 for (int i = 0; i < desc.length(); i++) { 940 if (desc.charAt(i) == 'L') { 941 int slash = i; 942 while (desc.charAt(i) != ';') { 943 i++; 944 if (desc.charAt(i) == '/') { 945 slash = i; 946 } 947 } 948 sb.append(desc.substring(slash + 1, i)).append(';'); 949 } else { 950 sb.append(desc.charAt(i)); 951 } 952 } 953 } else { 954 final int lastSlash = desc.lastIndexOf('/'); 955 final int lastBracket = desc.lastIndexOf('['); 956 if(lastBracket != -1) { 957 sb.append(desc, 0, lastBracket + 1); 958 } 959 sb.append(lastSlash == -1 ? desc : desc.substring(lastSlash + 1)); 960 } 961 } 962 963 private static void appendStr(final StringBuilder sb, final String s) { 964 sb.append('\"'); 965 for (int i = 0; i < s.length(); ++i) { 966 final char c = s.charAt(i); 967 if (c == '\n') { 968 sb.append("\\n"); 969 } else if (c == '\r') { 970 sb.append("\\r"); 971 } else if (c == '\\') { 972 sb.append("\\\\"); 973 } else if (c == '"') { 974 sb.append("\\\""); 975 } else if (c < 0x20 || c > 0x7f) { 976 sb.append("\\u"); 977 if (c < 0x10) { 978 sb.append("000"); 979 } else if (c < 0x100) { 980 sb.append("00"); 981 } else if (c < 0x1000) { 982 sb.append('0'); 983 } 984 sb.append(Integer.toString(c, 16)); 985 } else { 986 sb.append(c); 987 } 988 } 989 sb.append('\"'); 990 } 991 992 private static class Graph { 993 private final LinkedHashSet<String> nodes; 994 private final Map<String, StringBuilder> contents; 995 private final Map<String, Set<String>> edges; 996 private final Set<String> hasPreds; 997 private final Set<String> noFallThru; 998 private final Map<String, String> catches; 999 private final Map<String, Set<String>> exceptionMap; //maps catch nodes to all their trys that can reach them 1000 private final String name; 1001 1002 private static final String LEFT_ALIGN = "\\l"; 1003 private static final String COLOR_CATCH = "\"#ee9999\""; 1004 private static final String COLOR_ORPHAN = "\"#9999bb\""; 1005 private static final String COLOR_DEFAULT = "\"#99bb99\""; 1006 private static final String COLOR_LOCALVARS = "\"#999999\""; 1007 1008 Graph(final String name) { 1009 this.name = name; 1010 this.nodes = new LinkedHashSet<>(); 1011 this.contents = new HashMap<>(); 1012 this.edges = new HashMap<>(); 1013 this.hasPreds = new HashSet<>(); 1014 this.catches = new HashMap<>(); 1015 this.noFallThru = new HashSet<>(); 1016 this.exceptionMap = new HashMap<>(); 1017 } 1018 1019 void addEdge(final String from, final String to) { 1020 Set<String> edgeSet = edges.get(from); 1021 if (edgeSet == null) { 1022 edgeSet = new LinkedHashSet<>(); 1023 edges.put(from, edgeSet); 1024 } 1025 edgeSet.add(to); 1026 hasPreds.add(to); 1027 } 1028 1029 void addTryCatch(final String tryNode, final String catchNode) { 1030 Set<String> tryNodes = exceptionMap.get(catchNode); 1031 if (tryNodes == null) { 1032 tryNodes = new HashSet<>(); 1033 exceptionMap.put(catchNode, tryNodes); 1034 } 1035 if (!tryNodes.contains(tryNode)) { 1036 addEdge(tryNode, catchNode); 1037 } 1038 tryNodes.add(tryNode); 1039 } 1040 1041 void addNode(final String node) { 1042 assert !nodes.contains(node); 1043 nodes.add(node); 1044 } 1045 1046 void setNoFallThru(final String node) { 1047 noFallThru.add(node); 1048 } 1049 1050 boolean isNoFallThru(final String node) { 1051 return noFallThru.contains(node); 1052 } 1053 1054 void setIsCatch(final String node, final String exception) { 1055 catches.put(node, exception); 1056 } 1057 1058 String getName() { 1059 return name; 1060 } 1061 1062 void addText(final String node, final String text) { 1063 StringBuilder sb = contents.get(node); 1064 if (sb == null) { 1065 sb = new StringBuilder(); 1066 } 1067 1068 for (int i = 0; i < text.length(); i++) { 1069 switch (text.charAt(i)) { 1070 case '\n': 1071 sb.append(LEFT_ALIGN); 1072 break; 1073 case '"': 1074 sb.append("'"); 1075 break; 1076 default: 1077 sb.append(text.charAt(i)); 1078 break; 1079 } 1080 } 1081 1082 contents.put(node, sb); 1083 } 1084 1085 private static String dottyFriendly(final String name) { 1086 return name.replace(':', '_'); 1087 } 1088 1089 @Override 1090 public String toString() { 1091 1092 final StringBuilder sb = new StringBuilder(); 1093 sb.append("digraph " + dottyFriendly(name) + " {"); 1094 sb.append("\n"); 1095 sb.append("\tgraph [fontname=courier]\n"); 1096 sb.append("\tnode [style=filled,color="+COLOR_DEFAULT+",fontname=courier]\n"); 1097 sb.append("\tedge [fontname=courier]\n\n"); 1098 1099 for (final String node : nodes) { 1100 sb.append("\t"); 1101 sb.append(node); 1102 sb.append(" ["); 1103 sb.append("id="); 1104 sb.append(node); 1105 sb.append(", label=\""); 1106 String c = contents.get(node).toString(); 1107 if (c.startsWith(LEFT_ALIGN)) { 1108 c = c.substring(LEFT_ALIGN.length()); 1109 } 1110 final String ex = catches.get(node); 1111 if (ex != null) { 1112 sb.append("*** CATCH: ").append(ex).append(" ***\\l"); 1113 } 1114 sb.append(c); 1115 sb.append("\"]\n"); 1116 } 1117 1118 for (final String from : edges.keySet()) { 1119 for (final String to : edges.get(from)) { 1120 sb.append("\t"); 1121 sb.append(from); 1122 sb.append(" -> "); 1123 sb.append(to); 1124 sb.append("[label=\""); 1125 sb.append(to); 1126 sb.append("\""); 1127 if (catches.get(to) != null) { 1128 sb.append(", color=red, style=dashed"); 1129 } 1130 sb.append(']'); 1131 sb.append(";\n"); 1132 } 1133 } 1134 1135 sb.append("\n"); 1136 for (final String node : nodes) { 1137 sb.append("\t"); 1138 sb.append(node); 1139 sb.append(" [shape=box"); 1140 if (catches.get(node) != null) { 1141 sb.append(", color=" + COLOR_CATCH); 1142 } else if ("vars".equals(node)) { 1143 sb.append(", shape=hexagon, color=" + COLOR_LOCALVARS); 1144 } else if (!hasPreds.contains(node)) { 1145 sb.append(", color=" + COLOR_ORPHAN); 1146 } 1147 sb.append("]\n"); 1148 } 1149 1150 sb.append("}\n"); 1151 return sb.toString(); 1152 } 1153 } 1154 1155 static class NashornLabel extends Label { 1156 final Label label; 1157 final int bci; 1158 final int opcode; 1159 1160 NashornLabel(final Label label, final int bci) { 1161 this.label = label; 1162 this.bci = bci; 1163 this.opcode = -1; 1164 } 1165 1166 //not an ASM label 1167 NashornLabel(final int opcode, final int bci) { 1168 this.opcode = opcode; 1169 this.bci = bci; 1170 this.label = null; 1171 } 1172 1173 Label getLabel() { 1174 return label; 1175 } 1176 1177 @Override 1178 public int getOffset() { 1179 return bci; 1180 } 1181 1182 @Override 1183 public String toString() { 1184 return "label " + bci; 1185 } 1186 } 1187 1188 @Override 1189 public Printer visitAnnotationDefault() { 1190 throw new AssertionError(); 1191 } 1192 1193 @Override 1194 public Printer visitClassAnnotation(final String arg0, final boolean arg1) { 1195 return this; 1196 } 1197 1198 @Override 1199 public void visitClassAttribute(final Attribute arg0) { 1200 throw new AssertionError(); 1201 } 1202 1203 @Override 1204 public Printer visitFieldAnnotation(final String arg0, final boolean arg1) { 1205 throw new AssertionError(); 1206 } 1207 1208 @Override 1209 public void visitFieldAttribute(final Attribute arg0) { 1210 throw new AssertionError(); 1211 } 1212 1213 @Override 1214 public Printer visitMethodAnnotation(final String arg0, final boolean arg1) { 1215 return this; 1216 } 1217 1218 @Override 1219 public void visitMethodAttribute(final Attribute arg0) { 1220 throw new AssertionError(); 1221 } 1222 1223 @Override 1224 public Printer visitParameterAnnotation(final int arg0, final String arg1, final boolean arg2) { 1225 throw new AssertionError(); 1226 } 1227 1228 @Override 1229 public void visit(final String arg0, final Object arg1) { 1230 throw new AssertionError(); 1231 } 1232 1233 @Override 1234 public Printer visitAnnotation(final String arg0, final String arg1) { 1235 throw new AssertionError(); 1236 } 1237 1238 @Override 1239 public void visitAnnotationEnd() { 1240 //empty 1241 } 1242 1243 @Override 1244 public Printer visitArray(final String arg0) { 1245 throw new AssertionError(); 1246 } 1247 1248 @Override 1249 public void visitEnum(final String arg0, final String arg1, final String arg2) { 1250 throw new AssertionError(); 1251 } 1252 1253 @Override 1254 public void visitInnerClass(final String arg0, final String arg1, final String arg2, final int arg3) { 1255 throw new AssertionError(); 1256 } 1257} 1258