com.offbynull.coroutines.instrumenter.generators.DebugGenerators.java Source code

Java tutorial

Introduction

Here is the source code for com.offbynull.coroutines.instrumenter.generators.DebugGenerators.java

Source

/*
 * Copyright (c) 2016, Kasra Faghihi, All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3.0 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.
 */
package com.offbynull.coroutines.instrumenter.generators;

import org.apache.commons.lang3.Validate;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;

/**
 * Utility class to generate bytecode instructions that help debug instrumented code.
 * @author Kasra Faghihi
 */
public final class DebugGenerators {

    private DebugGenerators() {
        // do nothing
    }

    /**
     * Generates instructions for generating marker instructions. These marker instructions are meant to be is useful for debugging
     * instrumented code. For example, you can spot a specific portion of instrumented code by looking for specific markers in the assembly
     * output.
     * @param markerType marker type (determines what kind of instructions are generated)
     * @param text text to print out
     * @return instructions to call System.out.println with a string constant
     * @throws NullPointerException if any argument is {@code null}
     */
    public static InsnList debugMarker(MarkerType markerType, String text) {
        Validate.notNull(markerType);
        Validate.notNull(text);

        InsnList ret = new InsnList();

        switch (markerType) {
        case NONE:
            break;
        case CONSTANT:
            ret.add(new LdcInsnNode(text));
            ret.add(new InsnNode(Opcodes.POP));
            break;
        case STDOUT:
            ret.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
            ret.add(new LdcInsnNode(text));
            ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
                    "(Ljava/lang/String;)V", false));
            break;
        default:
            throw new IllegalStateException();
        }

        return ret;
    }

    /**
     * Debug marker type.
     */
    public enum MarkerType {
        /**
         * Generate no instructions.
         */
        NONE,
        /**
         * Generate instructions to load text as string constant and immediately pop it off the stack.
         */
        CONSTANT,
        /**
         * Generate instructions to print text to standard out.
         */
        STDOUT
    }

    /**
     * Generates instructions for printing out a string using {@link System#out}. This is useful for debugging. For example, you
     * can print out lines around your instrumented code to make sure that what you think is being run is actually being run.
     * @param text debug text generation instruction list -- must leave a String on the stack
     * @return instructions to call System.out.println with a string constant
     * @throws NullPointerException if any argument is {@code null}
     */
    public static InsnList debugPrint(InsnList text) {
        Validate.notNull(text);

        InsnList ret = new InsnList();

        ret.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
        ret.add(text);
        ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V",
                false));

        return ret;
    }
}