/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source 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, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.bytecode; import com.caucho.vfs.TempBuffer; import com.caucho.vfs.TempStream; import com.caucho.vfs.WriteStream; import java.io.IOException; import java.util.ArrayList; /** * Represents a generic attribute */ public class CodeAttribute extends Attribute { private JavaClass _jClass; private int _maxStack; private int _maxLocals; private byte []_code; private ArrayList<ExceptionItem> _exceptions = new ArrayList<ExceptionItem>(); private ArrayList<Attribute> _attributes = new ArrayList<Attribute>(); public CodeAttribute() { super("Code"); } CodeAttribute(String name) { super(name); } public void setJavaClass(JavaClass jClass) { _jClass = jClass; } public JavaClass getJavaClass() { return _jClass; } /** * Returns the max locals. */ public int getMaxLocals() { return _maxLocals; } /** * Sets the max locals. */ public void setMaxLocals(int max) { _maxLocals = max; } /** * Returns the max stack. */ public int getMaxStack() { return _maxStack; } /** * Sets the max stack. */ public void setMaxStack(int max) { _maxStack = max; } /** * Sets the code value. */ public void setCode(byte []code) { _code = code; } /** * Gets the code value. */ public byte []getCode() { return _code; } /** * Adds an attribute. */ public void addAttribute(Attribute attr) { _attributes.add(attr); } /** * Returns the exceptions. */ public ArrayList<Attribute> getAttributes() { return _attributes; } /** * Returns the exceptions. */ public void setAttributes(ArrayList<Attribute> attributes) { if (_attributes != attributes) { _attributes.clear(); _attributes.addAll(attributes); } } /** * Removes an attribute. */ public Attribute removeAttribute(String name) { for (int i = _attributes.size() - 1; i >= 0; i--) { Attribute attr = _attributes.get(i); if (attr.getName().equals(name)) { _attributes.remove(i); return attr; } } return null; } /** * Returns the exceptions. */ public ArrayList<ExceptionItem> getExceptions() { return _exceptions; } /** * Returns the exceptions. */ public void addException(ClassConstant type, int start, int end, int handler) { _exceptions.add(new ExceptionItem(type.getIndex(), start, end, handler)); } /** * Writes the field to the output. */ public void read(ByteCodeParser in) throws IOException { int length = in.readInt(); _maxStack = in.readShort(); _maxLocals = in.readShort(); int codeLength = in.readInt(); _code = new byte[codeLength]; in.read(_code, 0, codeLength); int exnCount = in.readShort(); for (int i = 0; i < exnCount; i++) { ExceptionItem exn = new ExceptionItem(); exn.setStart(in.readShort() & 0xffff); exn.setEnd(in.readShort() & 0xffff); exn.setHandler(in.readShort() & 0xffff); exn.setType(in.readShort() & 0xffff); _exceptions.add(exn); } int attrCount = in.readShort(); for (int i = 0; i < attrCount; i++) { Attribute attr = in.parseAttribute(); _attributes.add(attr); } } /** * Writes the field to the output. */ public void write(ByteCodeWriter out) throws IOException { out.writeUTF8Const(getName()); TempStream ts = new TempStream(); ts.openWrite(); WriteStream ws = new WriteStream(ts); ByteCodeWriter o2 = new ByteCodeWriter(ws, out.getJavaClass()); o2.writeShort(_maxStack); o2.writeShort(_maxLocals); o2.writeInt(_code.length); o2.write(_code, 0, _code.length); o2.writeShort(_exceptions.size()); for (int i = 0; i < _exceptions.size(); i++) { ExceptionItem exn = _exceptions.get(i); o2.writeShort(exn.getStart()); o2.writeShort(exn.getEnd()); o2.writeShort(exn.getHandler()); o2.writeShort(exn.getType()); } o2.writeShort(_attributes.size()); for (int i = 0; i < _attributes.size(); i++) { Attribute attr = _attributes.get(i); attr.write(o2); } ws.close(); out.writeInt(ts.getLength()); TempBuffer ptr = ts.getHead(); for (; ptr != null; ptr = ptr.getNext()) out.write(ptr.getBuffer(), 0, ptr.getLength()); ts.destroy(); } /** * Clones the attribute */ public Attribute export(JavaClass source, JavaClass target) { ConstantPool cp = target.getConstantPool(); cp.addUTF8(getName()); CodeAttribute attr = new CodeAttribute(getName()); attr._maxStack = _maxStack; attr._maxLocals = _maxLocals; byte []code = new byte[_code.length]; System.arraycopy(_code, 0, code, 0, _code.length); attr._code = code; for (int i = 0; i < _exceptions.size(); i++) { ExceptionItem exn = _exceptions.get(i); int type = exn.getType(); if (type != 0) type = cp.addClass(source.getConstantPool().getClass(type).getName()).getIndex(); ExceptionItem newExn = new ExceptionItem(type, exn.getStart(), exn.getEnd(), exn.getHandler()); attr._exceptions.add(newExn); } for (int i = 0; i < _attributes.size(); i++) { Attribute codeAttr = _attributes.get(i); attr.addAttribute(codeAttr.export(source, target)); } try { attr.exportCode(source, target); } catch (Exception e) { throw new RuntimeException(e); } return attr; } /** * Exports code. */ public void exportCode(JavaClass source, JavaClass target) throws Exception { ExportAnalyzer analyzer = new ExportAnalyzer(source, target); CodeEnhancer visitor = new CodeEnhancer(source, this); visitor.analyze(analyzer, false); visitor.update(); } public String toString() { return "CodeAttribute[" + getName() + "]"; } public static class ExceptionItem { private int _type; private int _start; private int _end; private int _handler; public ExceptionItem() { } public ExceptionItem(int type, int start, int end, int handler) { _type = type; _start = start; _end = end; _handler = handler; } /** * Sets the exception type. */ public void setType(int type) { _type = type; } /** * Returns the exception type. */ public int getType() { return _type; } /** * Sets the start PC */ public void setStart(int pc) { _start = pc; } /** * Gets the start PC */ public int getStart() { return _start; } /** * Sets the end PC */ public void setEnd(int pc) { _end = pc; } /** * Gets the end PC */ public int getEnd() { return _end; } /** * Sets the handler PC */ public void setHandler(int pc) { _handler = pc; } /** * Gets the handler PC */ public int getHandler() { return _handler; } } public static class ExportAnalyzer extends Analyzer { private JavaClass _source; private JavaClass _target; public ExportAnalyzer(JavaClass source, JavaClass target) { _source = source; _target = target; } public void analyze(CodeVisitor visitor) throws Exception { int op = visitor.getOpcode(); int index; ConstantPool sourcePool = _source.getConstantPool(); ConstantPool targetPool = _target.getConstantPool(); ConstantPoolEntry entry; switch (op) { case CodeVisitor.ANEWARRAY: case CodeVisitor.CHECKCAST: case CodeVisitor.GETFIELD: case CodeVisitor.GETSTATIC: case CodeVisitor.INSTANCEOF: case CodeVisitor.INVOKEINTERFACE: case CodeVisitor.INVOKESPECIAL: case CodeVisitor.INVOKESTATIC: case CodeVisitor.INVOKEVIRTUAL: case CodeVisitor.LDC_W: case CodeVisitor.LDC2_W: case CodeVisitor.MULTIANEWARRAY: case CodeVisitor.NEW: case CodeVisitor.PUTFIELD: case CodeVisitor.PUTSTATIC: index = visitor.getShortArg(1); entry = sourcePool.getEntry(index); int targetIndex = entry.export(targetPool); visitor.setShortArg(1, targetIndex); break; case CodeVisitor.LDC: index = visitor.getByteArg(1); entry = sourcePool.getEntry(index); index = entry.export(targetPool); if (index <= 0xff) visitor.setByteArg(1, index); else { CodeEnhancer enhancer = (CodeEnhancer) visitor; enhancer.setByteArg(0, CodeVisitor.LDC_W); enhancer.addByte(enhancer.getOffset() + 2, 0); enhancer.setShortArg(1, index); } break; default: break; } } } }