root/trunk/src/java/org/jcoderz/commons/tracing/MethodTracingInjector.java

Revision 1628, 22.8 kB (checked in by amandel, 2 years ago)

Add work in progress tracing components.
- Extended TracingProxy? that allows different Traces to be used
- TracingInjector? that allows aspect like injection of the tracing aspect.

Please note that this is still work in progress.

  • Property svn:mime-type set to text/plain
Line 
1/*
2 * $Id: ArraysUtil.java 1011 2008-06-16 17:57:36Z amandel $
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.commons.tracing;
34
35import java.util.ArrayList;
36import java.util.Iterator;
37import java.util.logging.Level;
38import java.util.logging.Logger;
39
40import org.jcoderz.commons.util.Assert;
41import org.objectweb.asm.Opcodes;
42import org.objectweb.asm.Type;
43import org.objectweb.asm.tree.AbstractInsnNode;
44import org.objectweb.asm.tree.FieldInsnNode;
45import org.objectweb.asm.tree.InsnList;
46import org.objectweb.asm.tree.InsnNode;
47import org.objectweb.asm.tree.JumpInsnNode;
48import org.objectweb.asm.tree.LabelNode;
49import org.objectweb.asm.tree.LdcInsnNode;
50import org.objectweb.asm.tree.LineNumberNode;
51import org.objectweb.asm.tree.LocalVariableNode;
52import org.objectweb.asm.tree.MethodInsnNode;
53import org.objectweb.asm.tree.MethodNode;
54import org.objectweb.asm.tree.TryCatchBlockNode;
55import org.objectweb.asm.tree.TypeInsnNode;
56import org.objectweb.asm.tree.VarInsnNode;
57
58/**
59 * Takes care to add Tracing to the methods.
60 * @author mandelan
61 */
62public class MethodTracingInjector
63{
64  private static final String CLASSNAME
65    = MethodTracingInjector.class.getName();
66  private static final Logger logger
67    = Logger.getLogger(CLASSNAME);
68  private static final String JAVA_LOGGER = "java/util/logging/Logger";
69
70  /** Link to the class injector where this method belongs to. */
71  private final ClassTracingInjector mClassInjector;
72  /** The asm MethodNode of the method under injection. */
73  private final MethodNode mMethodNode;
74  /** Method name as it is used in the logger calls. */
75  private final String mMethodName;
76  /** The local variable that is used to sore the is loggable boolean. */
77  private LocalVariableNode mIsLoggableVar;
78  /** Method start label - after logging injection */
79  private LabelNode mMethodStart;
80  /**
81   * Method start label - before logging injection - after the
82   * isLoggable assignment.
83   */
84  private LabelNode mOldMethodStart;
85  /** Label at the very end of the method. */
86  private LabelNode mMethodEnd;
87
88  /**
89   * Create a new MethodTracingInjector.
90   * @param mn the method node where to inject the tracing logging.
91   * @param ci the class injector where this method belongs to
92   */
93  public MethodTracingInjector(MethodNode mn, ClassTracingInjector ci)
94  {
95    mClassInjector = ci;
96    mMethodNode = mn;
97    mMethodName = mn.name;
98  }
99
100  /**
101   * Do the job.
102   */
103  public void inject ()
104  {
105    // NO abstract nor native methods
106    if ((mMethodNode.access
107        & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) == 0)
108    {
109      int lineNumber = getLineNumber();
110      if (logger.isLoggable(Level.FINEST))
111      {
112        logger.finest("Injecting tracing into "
113            + AsmUtil.toString(mMethodNode) + "at line " + lineNumber
114            +  '.');
115      }
116      mMethodStart = new LabelNode();
117      mOldMethodStart = getOrCreateStartLabel();
118      mMethodEnd = getOrCreateEndLabel();
119
120
121      final InsnList cmd = new InsnList();
122      cmd.add(mMethodStart);
123      if (lineNumber != -1)
124      {
125        cmd.add(new LineNumberNode(lineNumber - 1, mMethodStart));
126      }
127      if ("<clinit>".equals(mMethodNode.name))
128      { // Refactor??
129        mClassInjector.injectStaticLoggerMember(cmd);
130      }
131
132      ensureLocalVariablesAreSet();
133
134      // Create boolean method var isLoggable....
135      injectIsLoggableVariable(cmd);
136
137      final LabelNode labelAfterEnteringLogging = isLoggable(cmd);
138      injectEnteringLogging(cmd);
139      cmd.add(labelAfterEnteringLogging);
140
141      // TAKE CARE FOR LABEL!
142      // Must be shifted down for tryCatchBlocks
143      // MUST stay for Variables -> Move Variables!
144      // fix var map:
145      final Iterator i = mMethodNode.localVariables.iterator();
146      while (i.hasNext())
147      {
148        final LocalVariableNode var = (LocalVariableNode) i.next();
149
150        if (var.start.equals(mOldMethodStart))
151        {
152          var.start = mMethodStart;
153        }
154      }
155      mMethodNode.instructions.insertBefore(mOldMethodStart, cmd);
156      cmd.clear();
157
158      final TryCatchBlockNode tryCatch
159        = injectThrowingLogging(cmd,
160          labelAfterEnteringLogging);
161      if (tryCatch != null)
162      {
163        mMethodNode.tryCatchBlocks.add(tryCatch);
164        mMethodNode.instructions.insertBefore(mMethodEnd, cmd);
165      }
166      cmd.clear();
167
168      injectExitingLogger();
169    }
170    else
171    {
172      if (logger.isLoggable(Level.FINEST))
173      {
174        logger.finest("No tracing in native / abstract methods! "
175            + AsmUtil.toString(mMethodNode));
176      }
177    }
178  }
179
180  private int getLineNumber()
181  {
182    int result = -1;
183    final Iterator i = mMethodNode.instructions.iterator();
184    while (i.hasNext())
185    {
186      final AbstractInsnNode current = (AbstractInsnNode) i.next();
187      if (current.getType() == AbstractInsnNode.LINE)
188      {
189        final LineNumberNode lineNumber = (LineNumberNode) current;
190        result = lineNumber.line;
191        break;
192      }
193    }
194    return result;
195  }
196
197  private int getLastLineNumber()
198  {
199    int result = -1;
200    final Iterator i = mMethodNode.instructions.iterator();
201    while (i.hasNext())
202    {
203      final AbstractInsnNode current = (AbstractInsnNode) i.next();
204      if (current.getType() == AbstractInsnNode.LINE)
205      {
206        final LineNumberNode lineNumber = (LineNumberNode) current;
207        result = Math.max(lineNumber.line, result);
208      }
209    }
210    return result;
211  }
212
213  private void injectEnteringLogging(InsnList cmd)
214  {
215    // Check arguments
216    final Type[] arguments;
217    if (mMethodNode.desc != null)
218    {
219      arguments = Type.getArgumentTypes(mMethodNode.desc);
220    }
221    else
222    {
223      arguments = new Type[0];
224    }
225
226    mClassInjector.getStaticLoggerOnStack(cmd);
227    mClassInjector.getClassNameOnStack(cmd);
228    getMethodNameOnStack(cmd);
229    if (arguments == null || arguments.length == 0)
230    {
231      cmd.add(new MethodInsnNode(
232          Opcodes.INVOKEVIRTUAL,
233          JAVA_LOGGER,
234          "entering",
235          "(Ljava/lang/String;Ljava/lang/String;)V"));
236    }
237    else  if (arguments.length == 1)
238    {
239      boxMe(cmd, isStatic() ? 0 : 1, arguments[0]);
240      cmd.add(new MethodInsnNode(
241          Opcodes.INVOKEVIRTUAL,
242          JAVA_LOGGER,
243          "entering",
244          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V"));
245    }
246    else
247    {
248      AsmUtil.loadConstant(cmd, arguments.length);
249      cmd.add(new TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/Object"));
250
251      final int[] argPos = getArguments(arguments);
252      for (int i = 0; i < arguments.length; i++)
253      {
254        cmd.add(new InsnNode(Opcodes.DUP));
255        AsmUtil.loadConstant(cmd, i);
256        boxMe(cmd, argPos[i], arguments[i]);
257        cmd.add(new InsnNode(Opcodes.AASTORE));
258      }
259      cmd.add(new MethodInsnNode(
260          Opcodes.INVOKEVIRTUAL,
261          JAVA_LOGGER,
262          "entering",
263          "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V"));
264    }
265  }
266
267  private void injectExitingLogger()
268  {
269    final Iterator i = mMethodNode.instructions.iterator();
270    while (i.hasNext())
271    {
272      final AbstractInsnNode current = (AbstractInsnNode) i.next();
273      final int opcode = current.getOpcode();
274
275      LabelNode labelAfterLogging = null;
276      InsnList cmd = null;
277      switch (opcode)
278      {
279        case Opcodes.RETURN:
280          cmd = new InsnList();
281          labelAfterLogging = isLoggable(cmd);
282          mClassInjector.getStaticLoggerOnStack(cmd);
283          mClassInjector.getClassNameOnStack(cmd);
284          getMethodNameOnStack(cmd);
285          cmd.add(new MethodInsnNode(
286              Opcodes.INVOKEVIRTUAL,
287              JAVA_LOGGER,
288              "exiting",
289              "(Ljava/lang/String;Ljava/lang/String;)V"));
290          cmd.add(labelAfterLogging);
291          mMethodNode.instructions.insertBefore(current, cmd);
292          break;
293        case Opcodes.IRETURN:
294        case Opcodes.LRETURN:
295        case Opcodes.FRETURN:
296        case Opcodes.DRETURN:
297        case Opcodes.ARETURN:
298          cmd = new InsnList();
299          final Type type = Type.getReturnType(mMethodNode.desc);
300          labelAfterLogging = isLoggable(cmd);
301          final LocalVariableNode resultVar
302            = storeTypeOnStackInNewVariable(cmd, labelAfterLogging,
303              type);
304
305          mClassInjector.getStaticLoggerOnStack(cmd);
306          mClassInjector.getClassNameOnStack(cmd);
307          getMethodNameOnStack(cmd);
308
309          boxMe(cmd, resultVar);
310          cmd.add(new MethodInsnNode(
311              Opcodes.INVOKEVIRTUAL,
312              JAVA_LOGGER,
313              "exiting",
314              "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V"));
315          cmd.add(labelAfterLogging);
316          mMethodNode.instructions.insertBefore(current, cmd);
317          break;
318        default:
319          // stepping forward in method
320          break;
321      }
322    }
323  }
324
325  private TryCatchBlockNode injectThrowingLogging(InsnList cmd,
326      LabelNode labelAfterEnteringLogging)
327  {
328    final LabelNode lastStatement = beforeLastStatement();
329    TryCatchBlockNode result = null;
330    if (!near(lastStatement, labelAfterEnteringLogging))
331    {
332      final LabelNode methodEnd = new LabelNode();
333      cmd.add(methodEnd);
334      final LabelNode labelAfterThrowingLogging = isLoggable(cmd);
335
336
337      final LocalVariableNode exVar
338        = storeTypeOnStackInNewVariable(
339            cmd, labelAfterThrowingLogging, TracingInjector.THROWABLE_TYPE);
340
341      mClassInjector.getStaticLoggerOnStack(cmd);
342      mClassInjector.getClassNameOnStack(cmd);
343      getMethodNameOnStack(cmd);
344      cmd.add(new VarInsnNode(Opcodes.ALOAD, exVar.index));
345      cmd.add(new MethodInsnNode(
346                Opcodes.INVOKEVIRTUAL,
347                JAVA_LOGGER,
348                "throwing",
349                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V"));
350      cmd.add(labelAfterThrowingLogging);
351
352      cmd.add(new InsnNode(Opcodes.ATHROW));
353      final LabelNode theEnd = new LabelNode();
354      cmd.add(theEnd);
355  //    mIsLoggableVar.end = theEnd;
356
357      result  = new TryCatchBlockNode(labelAfterEnteringLogging,
358          lastStatement, methodEnd,
359          TracingInjector.THROWABLE_TYPE.getInternalName());
360    }
361    return result;
362  }
363
364  /**
365   * Checks if the 2 labels are near to each other (not separated by code).
366   * @return true if the 2 labels are near to each other
367   */
368  private boolean near(LabelNode labelA, LabelNode labelB)
369  {
370    boolean result = false;
371    AbstractInsnNode a = labelA;
372    while (a != null &&
373        ( a.getType() == AbstractInsnNode.LABEL
374            || a.getType() == AbstractInsnNode.LINE))
375    {
376      if (a == labelB)
377      {
378        result = true;
379        break;
380      }
381      a = a.getNext();
382    }
383    if (!result)
384    {
385      a = labelA;
386      while (a != null &&
387          ( a.getType() == AbstractInsnNode.LABEL
388              || a.getType() == AbstractInsnNode.LINE))
389      {
390        if (a == labelB)
391        {
392          result = true;
393          break;
394        }
395        a = a.getPrevious();
396      }
397    }
398    return result;
399  }
400
401  private LabelNode beforeLastStatement()
402  {
403    AbstractInsnNode last = mMethodNode.instructions.getLast();
404
405    while (last != null &&
406        (last.getType() == AbstractInsnNode.LINE
407            || last.getType() == AbstractInsnNode.LABEL))
408    {
409      last = last.getPrevious();
410    }
411
412    // now check for a label...
413    AbstractInsnNode label
414      = (last == null ? mMethodNode.instructions.getLast() : last);
415    while (label != null && label.getType() == AbstractInsnNode.LINE)
416    {
417      label = label.getPrevious();
418    }
419
420    final LabelNode result;
421    if (label != null && label.getType() == AbstractInsnNode.LABEL)
422    {
423      result = (LabelNode) label;
424    }
425    else if (last == null)
426    {
427      result = new LabelNode();
428      mMethodNode.instructions.insert(result);
429    }
430    else
431    {
432      result = new LabelNode();
433      mMethodNode.instructions.insertBefore(last, result);
434    }
435    return result;
436  }
437
438  /**
439   *
440   */
441  private void ensureLocalVariablesAreSet()
442  {
443    if (mMethodNode.localVariables == null)
444    {
445      mMethodNode.localVariables = new ArrayList();
446    }
447  }
448
449  private void injectIsLoggableVariable (InsnList cmd)
450  {
451    final int varIndex = getFreeLocalIndex();
452
453    final LabelNode varStartNode = new LabelNode();
454    mIsLoggableVar
455      = new LocalVariableNode(
456          TracingInjector.IS_LOGGABLE_FIELD_NAME + varIndex,
457          Type.BOOLEAN_TYPE.getDescriptor(),
458          (String) null, varStartNode, mMethodEnd, varIndex);
459    mMethodNode.localVariables.add(mIsLoggableVar);
460
461    mClassInjector.getStaticLoggerOnStack(cmd);
462    cmd.add(new FieldInsnNode(
463        Opcodes.GETSTATIC,
464        "java/util/logging/Level",
465        "FINER", "Ljava/util/logging/Level;"));
466    cmd.add(new MethodInsnNode(
467        Opcodes.INVOKEVIRTUAL,
468        JAVA_LOGGER,
469        "isLoggable",
470        "(Ljava/util/logging/Level;)Z"));
471    cmd.add(new VarInsnNode(Opcodes.ISTORE, mIsLoggableVar.index));
472    cmd.add(varStartNode);
473  }
474
475  /**
476   * Returns an array holding the Variable index of the corresponding Argument.
477   * @param types an array holding the argument Types.
478   * @return
479   */
480  private int[] getArguments(Type[] types)
481  {
482    final int[] result = new int[types.length];
483    int cur = isStatic() ? 0 : 1;
484    for (int pos = 0; pos < types.length; pos++)
485    {
486      result[pos] = cur;
487      cur += types[pos].getSize();
488    }
489    return result;
490  }
491
492  /**
493   *
494   * @param cmd
495   */
496  private void getMethodNameOnStack(InsnList cmd)
497  {
498    cmd.add(new LdcInsnNode(mMethodName));
499  }
500
501  /**
502   *
503   * @return
504   */
505  private int getFreeLocalIndex ()
506  {
507    final Iterator i = mMethodNode.localVariables.iterator();
508    int maxIndex = -1;
509    while (i.hasNext())
510    {
511      final LocalVariableNode node = (LocalVariableNode) i.next();
512      if (node.index >= maxIndex)
513        // >= needed because index could be reused with larger type
514      {
515        if (node.desc.equals(Type.DOUBLE_TYPE.getDescriptor())
516            || node.desc.equals(Type.LONG_TYPE.getDescriptor()))
517        {
518          maxIndex = node.index + 1;
519        }
520        else
521        {
522          maxIndex = node.index;
523        }
524      }
525    }
526    maxIndex++;
527
528    final int other = getFreeLocalByCode();
529    return Math.max(other, maxIndex);
530  }
531
532  /**
533   *
534   * @return
535   */
536  private int getFreeLocalByCode ()
537  {
538     int maxIndex = -1;
539     final Iterator i = mMethodNode.instructions.iterator();
540     while (i.hasNext())
541     {
542       final AbstractInsnNode insn = (AbstractInsnNode) i.next();
543       if (insn instanceof VarInsnNode)
544       {
545         final VarInsnNode varInsnNode = (VarInsnNode) insn;
546         if (varInsnNode.var >= maxIndex)
547         { // >= needed because index could be reused with larger type
548           switch (varInsnNode.getOpcode())
549           {
550             case Opcodes.ILOAD:
551             case Opcodes.FLOAD:
552             case Opcodes.ALOAD:
553             case Opcodes.ISTORE:
554             case Opcodes.FSTORE:
555             case Opcodes.ASTORE:
556               maxIndex = varInsnNode.var;
557               break;
558
559             case Opcodes.LLOAD:
560             case Opcodes.DLOAD:
561             case Opcodes.LSTORE:
562             case Opcodes.DSTORE:
563               maxIndex = varInsnNode.var + 1;
564               break;
565             case Opcodes.RET:
566               // ignore already covered with the ASTORE
567               break;
568             default:
569               Assert.assertTrue(
570                   "Unexpected opcode " + insn.getOpcode()
571                   + " in VarInsnNode operation.", false);
572             break;
573           }
574         }
575       }
576     }
577
578     return maxIndex + 1;
579  }
580
581  /**
582   * Expects data of type type on the Stacks and stores it in a new Variable,
583   * the stack content stays unchanged!
584   * @param cmd the instruction list to add the commands.
585   * @param end intended end label for the validity of the variable
586   * @param type the type of the data to store
587   * @return the new generated variable
588   */
589  private LocalVariableNode storeTypeOnStackInNewVariable(InsnList cmd,
590      LabelNode end, final Type type)
591  {
592    // TODO: Could be more efficient in reusing free indexes
593    // But we can not relay on the localVariables table...
594
595    // CREATE VAR
596    // The label is the position AFTER the xSTORE cmd.
597    final LabelNode startLabel = new LabelNode();
598    final int index = getFreeLocalIndex();
599    final LocalVariableNode resultVar
600      = new LocalVariableNode(
601          TracingInjector.RESULT_VAR_FIELD_NAME + index,
602        type.getDescriptor(), (String) null, startLabel, end,
603        index);
604    mMethodNode.localVariables.add(resultVar);
605
606    // CREATE CODE
607    cmd.add(new InsnNode(type.getSize() == 1 ? Opcodes.DUP : Opcodes.DUP2));
608    cmd.add(new VarInsnNode(
609        type.getOpcode(Opcodes.ISTORE), resultVar.index));
610    cmd.add(startLabel);
611    // Load the var again (could use the DUP above)
612//    cmd.add(new VarInsnNode(
613//        type.getOpcode(Opcodes.ILOAD), resultVar.index));
614    return resultVar;
615  }
616
617  /**
618   *
619   * @return
620   */
621  private boolean isStatic ()
622  {
623    return (mMethodNode.access & Opcodes.ACC_STATIC) != 0;
624  }
625
626  /**
627   *
628   * @param cmd
629   * @param var
630   */
631  private void boxMe(InsnList cmd, LocalVariableNode var)
632  {
633    Assert.notNull(cmd, "cmd");
634    Assert.notNull(var, "var");
635    boxMe(cmd, var.index, Type.getType(var.desc));
636  }
637
638  /**
639   *
640   * @param cmd
641   * @param index
642   * @param type
643   */
644  private void boxMe(InsnList cmd, int index, Type type)
645  {
646    switch (type.getSort())
647    {
648      case Type.SHORT:
649        boxMe(cmd, type, "java/lang/Short", index);
650        break;
651      case Type.INT:
652        boxMe(cmd, type, "java/lang/Integer", index);
653        break;
654      case Type.CHAR:
655        boxMe(cmd, type, "java/lang/Character", index);
656        break;
657      case Type.BOOLEAN:
658        boxMe(cmd, type, "java/lang/Boolean", index);
659        break;
660      case Type.LONG:
661        boxMe(cmd, type, "java/lang/Long", index);
662        break;
663      case Type.FLOAT:
664        boxMe(cmd, type, "java/lang/Float", index);
665        break;
666      case Type.DOUBLE:
667        boxMe(cmd, type, "java/lang/Double", index);
668        break;
669      case Type.BYTE:
670        boxMe(cmd, type, "java/lang/Byte", index);
671        break;
672      case Type.ARRAY:
673      case Type.OBJECT:
674        cmd.add(new VarInsnNode(
675            type.getOpcode(Opcodes.ILOAD), index));
676        break;
677      default:
678        throw new RuntimeException("Unexpected type " + type.getDescriptor());
679    }
680  }
681
682  /**
683   *
684   * @param instr
685   * @param type
686   * @param boxClassName
687   * @param index
688   */
689  private void boxMe(InsnList instr, Type type, String boxClassName,
690      int index)
691  {
692    if (!(type.getSort() == Type.BOOLEAN) && !mClassInjector.isJava5())
693    {
694      // new Xxxxx(...)
695      instr.add(new TypeInsnNode(Opcodes.NEW, boxClassName));
696      instr.add(new InsnNode(Opcodes.DUP));
697      instr.add(new VarInsnNode(type.getOpcode(Opcodes.ILOAD), index));
698      instr.add(new MethodInsnNode(
699        Opcodes.INVOKESPECIAL, boxClassName, "<init>",
700        "(" + type.getDescriptor() + ")V"));
701    }
702    else
703    { // since JDK 1.5 version (except for boolean):
704      // Xxxxx.valueOf(...)
705      instr.add(new VarInsnNode(
706        type.getOpcode(Opcodes.ILOAD), index));
707      instr.add(new MethodInsnNode(
708          Opcodes.INVOKESTATIC, boxClassName, "valueOf",
709          "(" + type.getDescriptor() +  ")L" + boxClassName + ";"));
710    }
711  }
712
713  /**
714   *
715   * @return
716   */
717  private LabelNode getOrCreateEndLabel ()
718  {
719    final AbstractInsnNode last = mMethodNode.instructions.getLast();
720    final LabelNode result;
721    if (last.getType() == AbstractInsnNode.LABEL)
722    {
723      result = (LabelNode) last;
724    }
725    else
726    {
727      // need a new end Label...
728      result = new LabelNode();
729      mMethodNode.instructions.add(result);
730    }
731    return result;
732  }
733
734  /**
735   *
736   * @return
737   */
738  private LabelNode getOrCreateStartLabel ()
739  {
740    final AbstractInsnNode first = mMethodNode.instructions.getFirst();
741    final LabelNode result;
742    if (first.getType() == AbstractInsnNode.LABEL)
743    {
744      result = (LabelNode) first;
745    }
746    else
747    { // need a start Label...
748      result = new LabelNode();
749      mMethodNode.instructions.insertBefore(first, result);
750    }
751    return result;
752  }
753
754  /**
755   * Create ifLoggable code and return a label to jump to
756   * in case of a false result.
757   * @param cmd the instruction list to add the instructions to.
758   * @return the node that is used as target if the isLoggable
759   *  evaluates to false.
760   */
761  private LabelNode isLoggable (InsnList cmd)
762  {
763    cmd.add(new VarInsnNode(Opcodes.ILOAD, mIsLoggableVar.index));
764    final LabelNode afterLogging = new LabelNode();
765    cmd.add(new JumpInsnNode(Opcodes.IFEQ, afterLogging));
766    return afterLogging;
767  }
768}
Note: See TracBrowser for help on using the browser.