All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xapi.bytecode.attributes.StackMap Maven / Gradle / Ivy

Go to download

Everything needed to run a comprehensive dev environment. Just type X_ and pick a service from autocomplete; new dev modules will be added as they are built. The only dev service not included in the uber jar is xapi-dev-maven, as it includes all runtime dependencies of maven, adding ~4 seconds to build time, and 6 megabytes to the final output jar size (without xapi-dev-maven, it's ~1MB).

The newest version!
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * MODIFIED BY James Nelson of We The Internet, 2013.
 * Repackaged to avoid conflicts with different versions of Javassist,
 * and modified Javassist APIs to make them more accessible to outside code.
 */
package xapi.bytecode.attributes;

import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.IOException;
import java.util.Map;

import xapi.bytecode.BadBytecode;
import xapi.bytecode.CannotCompileException;
import xapi.bytecode.ConstPool;
import xapi.util.X_Byte;


public class StackMap extends AttributeInfo {
    /**
     * The name of this attribute "StackMap".
     */
    public static final String tag = "StackMap";


    /**
     * Constructs a stack_map attribute.
     */
    StackMap(ConstPool cp, byte[] newInfo) {
        super(cp, tag, newInfo);
    }

    StackMap(ConstPool cp, int name_id, DataInput in)
        throws IOException
    {
        super(cp, name_id, in);
    }

    /**
     * Returns number_of_entries.
     */
    public int numOfEntries() {
      return X_Byte.readU16bit(info, 0);
    }

    /**
     * Top_variable_info.tag.
     */
    public static final int TOP = 0;

    /**
     * Integer_variable_info.tag.
     */
    public static final int INTEGER = 1;

    /**
     * Float_variable_info.tag.
     */
    public static final int FLOAT = 2;

    /**
     * Double_variable_info.tag.
     */
    public static final int DOUBLE = 3;

    /**
     * Long_variable_info.tag.
     */
    public static final int LONG = 4;

    /**
     * Null_variable_info.tag.
     */
    public static final int NULL = 5;

    /**
     * UninitializedThis_variable_info.tag.
     */
    public static final int THIS = 6;

    /**
     * Object_variable_info.tag.
     */
    public static final int OBJECT = 7;

    /**
     * Uninitialized_variable_info.tag.
     */
    public static final int UNINIT = 8;

    /**
     * Makes a copy.
     */
    @Override
    public AttributeInfo copy(ConstPool newCp, Map classnames) {
        Copier copier = new Copier(this, newCp, classnames);
        copier.visit();
        return copier.getStackMap();
    }

    /**
     * A code walker for a StackMap attribute.
     */
    public static class Walker {
        byte[] info;

        /**
         * Constructs a walker.
         */
        public Walker(StackMap sm) {
            info = sm.get();
        }

        /**
         * Visits each entry of the stack map frames.
         */
        public void visit() {
            int num = X_Byte.readU16bit(info, 0);
            int pos = 2;
            for (int i = 0; i < num; i++) {
                int offset = X_Byte.readU16bit(info, pos);
                int numLoc = X_Byte.readU16bit(info, pos + 2);
                pos = locals(pos + 4, offset, numLoc);
                int numStack = X_Byte.readU16bit(info, pos);
                pos = stack(pos + 2, offset, numStack);
            }
        }

        /**
         * Invoked when locals of stack_map_frame
         * is visited.
         */
        public int locals(int pos, int offset, int num) {
            return typeInfoArray(pos, offset, num, true);
        }

        /**
         * Invoked when stack of stack_map_frame
         * is visited.
         */
        public int stack(int pos, int offset, int num) {
            return typeInfoArray(pos, offset, num, false);
        }

        /**
         * Invoked when an array of verification_type_info is
         * visited.
         *
         * @param num       the number of elements.
         * @param isLocals  true if this array is for locals.
         *                  false if it is for stack.
         */
        public int typeInfoArray(int pos, int offset, int num, boolean isLocals) {
            for (int k = 0; k < num; k++) {
              pos = typeInfoArray2(k, pos);
            }

            return pos;
        }

        int typeInfoArray2(int k, int pos) {
            byte tag = info[pos];
            if (tag == OBJECT) {
                int clazz = X_Byte.readU16bit(info, pos + 1);
                objectVariable(pos, clazz);
                pos += 3;
            }
            else if (tag == UNINIT) {
                int offsetOfNew = X_Byte.readU16bit(info, pos + 1);
                uninitialized(pos, offsetOfNew);
                pos += 3;
            }
            else {
                typeInfo(pos, tag);
                pos++;
            }

            return pos;
        }

        /**
         * Invoked when an element of verification_type_info
         * (except Object_variable_info and
         * Uninitialized_variable_info) is visited.
         */
        public void typeInfo(int pos, byte tag) {}

        /**
         * Invoked when an element of type Object_variable_info
         * is visited.
         */
        public void objectVariable(int pos, int clazz) {}

        /**
         * Invoked when an element of type Uninitialized_variable_info
         * is visited.
         */
        public void uninitialized(int pos, int offset) {}
    }

    static class Copier extends Walker {
        byte[] dest;
        ConstPool srcCp, destCp;
        Map classnames;

        Copier(StackMap map, ConstPool newCp, Map classnames) {
            super(map);
            srcCp = map.getConstPool();
            dest = new byte[info.length];
            destCp = newCp;
            this.classnames = classnames;
        }

        @Override
        public void visit() {
            int num = X_Byte.readU16bit(info, 0);
            X_Byte.write16bit(num, dest, 0);
            super.visit();
        }

        @Override
        public int locals(int pos, int offset, int num) {
            X_Byte.write16bit(offset, dest, pos - 4);
            return super.locals(pos, offset, num);
        }

        @Override
        public int typeInfoArray(int pos, int offset, int num, boolean isLocals) {
            X_Byte.write16bit(num, dest, pos - 2);
            return super.typeInfoArray(pos, offset, num, isLocals);
        }

        @Override
        public void typeInfo(int pos, byte tag) {
            dest[pos] = tag;
        }

        @Override
        public void objectVariable(int pos, int clazz) {
            dest[pos] = OBJECT;
            int newClazz = srcCp.copy(clazz, destCp, classnames);
            X_Byte.write16bit(newClazz, dest, pos + 1);
        }

        @Override
        public void uninitialized(int pos, int offset) {
            dest[pos] = UNINIT;
            X_Byte.write16bit(offset, dest, pos + 1);
        }

        public StackMap getStackMap() {
            return new StackMap(destCp, dest);
        }
    }

    /**
     * Updates this stack map table when a new local variable is inserted
     * for a new parameter.
     *
     * @param index          the index of the added local variable.
     * @param tag            the type tag of that local variable.
     *                       It is available by StackMapTable.typeTagOf(char).
     * @param classInfo      the index of the CONSTANT_Class_info structure
     *                       in a constant pool table.  This should be zero unless the tag
     *                       is ITEM_Object.
     * @throws BadBytecode
     *
     * @see javassist.CtBehavior#addParameter(javassist.CtClass)
     * @see StackMapTable#typeTagOf(char)
     * @see ConstPool
     */
    public void insertLocal(int index, int tag, int classInfo)
        throws BadBytecode
    {
        byte[] data = new InsertLocal(this, index, tag, classInfo).doit();
        this.set(data);
    }

    static class SimpleCopy extends Walker {
        Writer writer;

        SimpleCopy(StackMap map) {
            super(map);
            writer = new Writer();
        }

        byte[] doit() {
            visit();
            return writer.toByteArray();
        }

        @Override
        public void visit() {
            int num = X_Byte.readU16bit(info, 0);
            writer.write16bit(num);
            super.visit();
        }

        @Override
        public int locals(int pos, int offset, int num) {
            writer.write16bit(offset);
            return super.locals(pos, offset, num);
        }

        @Override
        public int typeInfoArray(int pos, int offset, int num, boolean isLocals) {
            writer.write16bit(num);
            return super.typeInfoArray(pos, offset, num, isLocals);
        }

        @Override
        public void typeInfo(int pos, byte tag) {
            writer.writeVerifyTypeInfo(tag, 0);
        }

        @Override
        public void objectVariable(int pos, int clazz) {
            writer.writeVerifyTypeInfo(OBJECT, clazz);
        }

        @Override
        public void uninitialized(int pos, int offset) {
            writer.writeVerifyTypeInfo(UNINIT, offset);
        }
    }

    static class InsertLocal extends SimpleCopy {
        private int varIndex;
        private int varTag, varData;

        InsertLocal(StackMap map, int varIndex, int varTag, int varData) {
            super(map);
            this.varIndex = varIndex;
            this.varTag = varTag;
            this.varData = varData;
        }

        @Override
        public int typeInfoArray(int pos, int offset, int num, boolean isLocals) {
            if (!isLocals || num < varIndex) {
              return super.typeInfoArray(pos, offset, num, isLocals);
            }

            writer.write16bit(num + 1);
            for (int k = 0; k < num; k++) {
                if (k == varIndex) {
                  writeVarTypeInfo();
                }

                pos = typeInfoArray2(k, pos);
            }

            if (num == varIndex) {
              writeVarTypeInfo();
            }

            return pos;
        }

        private void writeVarTypeInfo() {
            if (varTag == OBJECT) {
              writer.writeVerifyTypeInfo(OBJECT, varData);
            } else if (varTag == UNINIT) {
              writer.writeVerifyTypeInfo(UNINIT, varData);
            } else {
              writer.writeVerifyTypeInfo(varTag, 0);
            }
        }
    }

    /**
     * @throws BadBytecode
     */
    public void shiftPc(int where, int gapSize, boolean exclusive)
        throws BadBytecode
    {
        new Shifter(this, where, gapSize, exclusive).visit();
    }

    static class Shifter extends Walker {
        private int where, gap;
        private boolean exclusive;

        public Shifter(StackMap smt, int where, int gap, boolean exclusive) {
            super(smt);
            this.where = where;
            this.gap = gap;
            this.exclusive = exclusive;
        }

        @Override
        public int locals(int pos, int offset, int num) {
            if (exclusive ? where <= offset : where < offset) {
              X_Byte.write16bit(offset + gap, info, pos - 4);
            }

            return super.locals(pos, offset, num);
        }
    }

    /**
     * Undocumented method.  Do not use; internal-use only.
     *
     * 

This method is for javassist.convert.TransformNew. * It is called to update the stack map when * the NEW opcode (and the following DUP) is removed. * * @param where the position of the removed NEW opcode. * @throws CannotCompileException */ public void removeNew(int where) throws CannotCompileException { byte[] data = new NewRemover(this, where).doit(); this.set(data); } static class NewRemover extends SimpleCopy { int posOfNew; NewRemover(StackMap map, int where) { super(map); posOfNew = where; } @Override public int stack(int pos, int offset, int num) { return stackTypeInfoArray(pos, offset, num); } private int stackTypeInfoArray(int pos, int offset, int num) { int p = pos; int count = 0; for (int k = 0; k < num; k++) { byte tag = info[p]; if (tag == OBJECT) { p += 3; } else if (tag == UNINIT) { int offsetOfNew = X_Byte.readU16bit(info, p + 1); if (offsetOfNew == posOfNew) { count++; } p += 3; } else { p++; } } writer.write16bit(num - count); for (int k = 0; k < num; k++) { byte tag = info[pos]; if (tag == OBJECT) { int clazz = X_Byte.readU16bit(info, pos + 1); objectVariable(pos, clazz); pos += 3; } else if (tag == UNINIT) { int offsetOfNew = X_Byte.readU16bit(info, pos + 1); if (offsetOfNew != posOfNew) { uninitialized(pos, offsetOfNew); } pos += 3; } else { typeInfo(pos, tag); pos++; } } return pos; } } /** * Prints this stack map. */ public void print(java.io.PrintWriter out) { new Printer(this, out).print(); } static class Printer extends Walker { private java.io.PrintWriter writer; public Printer(StackMap map, java.io.PrintWriter out) { super(map); writer = out; } public void print() { int num = X_Byte.readU16bit(info, 0); writer.println(num + " entries"); visit(); } @Override public int locals(int pos, int offset, int num) { writer.println(" * offset " + offset); return super.locals(pos, offset, num); } } /** * Internal use only. */ public static class Writer { // see javassist.bytecode.stackmap.MapMaker private ByteArrayOutputStream output; /** * Constructs a writer. */ public Writer() { output = new ByteArrayOutputStream(); } /** * Converts the written data into a byte array. */ public byte[] toByteArray() { return output.toByteArray(); } /** * Converts to a StackMap attribute. */ public StackMap toStackMap(ConstPool cp) { return new StackMap(cp, output.toByteArray()); } /** * Writes a union verification_type_info value. * * @param data cpool_index or offset. */ public void writeVerifyTypeInfo(int tag, int data) { output.write(tag); if (tag == StackMap.OBJECT || tag == StackMap.UNINIT) { write16bit(data); } } /** * Writes a 16bit value. */ public void write16bit(int value) { output.write((value >>> 8) & 0xff); output.write(value & 0xff); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy