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

com.feilong.lib.javassist.bytecode.StackMap Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.3.0
Show 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.
 */

package com.feilong.lib.javassist.bytecode;

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

import com.feilong.lib.javassist.CannotCompileException;

/**
 * Another stack_map attribute defined in CLDC 1.1 for J2ME.
 *
 * 

* This is an entry in the attributes table of a Code attribute. * It was introduced by J2ME CLDC 1.1 (JSR 139) for pre-verification. * *

* According to the CLDC specification, the sizes of some fields are not 16bit * but 32bit if the code size is more than 64K or the number of the local variables * is more than 64K. However, for the J2ME CLDC technology, they are always 16bit. * The implementation of the StackMap class assumes they are 16bit. * * @see MethodInfo#doPreverify * @see StackMapTable * @since 3.12 */ 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, DataInputStream in) throws IOException{ super(cp, name_id, in); } /** * Returns number_of_entries. */ public int numOfEntries(){ return ByteArray.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 = ByteArray.readU16bit(info, 0); int pos = 2; for (int i = 0; i < num; i++){ int offset = ByteArray.readU16bit(info, pos); int numLoc = ByteArray.readU16bit(info, pos + 2); pos = locals(pos + 4, offset, numLoc); int numStack = ByteArray.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 = ByteArray.readU16bit(info, pos + 1); objectVariable(pos, clazz); pos += 3; }else if (tag == UNINIT){ int offsetOfNew = ByteArray.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 = ByteArray.readU16bit(info, 0); ByteArray.write16bit(num, dest, 0); super.visit(); } @Override public int locals(int pos,int offset,int num){ ByteArray.write16bit(offset, dest, pos - 4); return super.locals(pos, offset, num); } @Override public int typeInfoArray(int pos,int offset,int num,boolean isLocals){ ByteArray.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); ByteArray.write16bit(newClazz, dest, pos + 1); } @Override public void uninitialized(int pos,int offset){ dest[pos] = UNINIT; ByteArray.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. * * @see com.feilong.lib.javassist.CtBehavior#addParameter(com.feilong.lib.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 = ByteArray.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); } } } 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){ ByteArray.write16bit(offset + gap, info, pos - 4); } return super.locals(pos, offset, num); } @Override public void uninitialized(int pos,int offset){ if (where <= offset){ ByteArray.write16bit(offset + gap, info, pos + 1); } } } /** * @see CodeIterator.Switcher#adjustOffsets(int, int) */ void shiftForSwitch(int where,int gapSize) throws BadBytecode{ new SwitchShifter(this, where, gapSize).visit(); } static class SwitchShifter extends Walker{ private int where, gap; public SwitchShifter(StackMap smt, int where, int gap){ super(smt); this.where = where; this.gap = gap; } @Override public int locals(int pos,int offset,int num){ if (where == pos + offset){ ByteArray.write16bit(offset - gap, info, pos - 4); }else if (where == pos){ ByteArray.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. */ 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 = ByteArray.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 = ByteArray.readU16bit(info, pos + 1); objectVariable(pos, clazz); pos += 3; }else if (tag == UNINIT){ int offsetOfNew = ByteArray.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 = ByteArray.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