001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.bytecode;
031:
032: import com.caucho.log.Log;
033: import com.caucho.vfs.TempBuffer;
034: import com.caucho.vfs.TempStream;
035: import com.caucho.vfs.WriteStream;
036:
037: import java.io.IOException;
038: import java.util.ArrayList;
039: import java.util.logging.Logger;
040:
041: /**
042: * Represents a generic attribute
043: */
044: public class CodeAttribute extends Attribute {
045: static private final Logger log = Log.open(CodeAttribute.class);
046:
047: private JavaClass _jClass;
048: private int _maxStack;
049: private int _maxLocals;
050: private byte[] _code;
051: private ArrayList<ExceptionItem> _exceptions = new ArrayList<ExceptionItem>();
052:
053: private ArrayList<Attribute> _attributes = new ArrayList<Attribute>();
054:
055: public CodeAttribute() {
056: super ("Code");
057: }
058:
059: CodeAttribute(String name) {
060: super (name);
061: }
062:
063: public void setJavaClass(JavaClass jClass) {
064: _jClass = jClass;
065: }
066:
067: public JavaClass getJavaClass() {
068: return _jClass;
069: }
070:
071: /**
072: * Returns the max locals.
073: */
074: public int getMaxLocals() {
075: return _maxLocals;
076: }
077:
078: /**
079: * Sets the max locals.
080: */
081: public void setMaxLocals(int max) {
082: _maxLocals = max;
083: }
084:
085: /**
086: * Returns the max stack.
087: */
088: public int getMaxStack() {
089: return _maxStack;
090: }
091:
092: /**
093: * Sets the max stack.
094: */
095: public void setMaxStack(int max) {
096: _maxStack = max;
097: }
098:
099: /**
100: * Sets the code value.
101: */
102: public void setCode(byte[] code) {
103: _code = code;
104: }
105:
106: /**
107: * Gets the code value.
108: */
109: public byte[] getCode() {
110: return _code;
111: }
112:
113: /**
114: * Adds an attribute.
115: */
116: public void addAttribute(Attribute attr) {
117: _attributes.add(attr);
118: }
119:
120: /**
121: * Returns the exceptions.
122: */
123: public ArrayList<Attribute> getAttributes() {
124: return _attributes;
125: }
126:
127: /**
128: * Returns the exceptions.
129: */
130: public void setAttributes(ArrayList<Attribute> attributes) {
131: if (_attributes != attributes) {
132: _attributes.clear();
133: _attributes.addAll(attributes);
134: }
135: }
136:
137: /**
138: * Removes an attribute.
139: */
140: public Attribute removeAttribute(String name) {
141: for (int i = _attributes.size() - 1; i >= 0; i--) {
142: Attribute attr = _attributes.get(i);
143:
144: if (attr.getName().equals(name)) {
145: _attributes.remove(i);
146: return attr;
147: }
148: }
149:
150: return null;
151: }
152:
153: /**
154: * Returns the exceptions.
155: */
156: public ArrayList<ExceptionItem> getExceptions() {
157: return _exceptions;
158: }
159:
160: /**
161: * Returns the exceptions.
162: */
163: public void addException(ClassConstant type, int start, int end,
164: int handler) {
165: _exceptions.add(new ExceptionItem(type.getIndex(), start, end,
166: handler));
167: }
168:
169: /**
170: * Writes the field to the output.
171: */
172: public void read(ByteCodeParser in) throws IOException {
173: int length = in.readInt();
174:
175: _maxStack = in.readShort();
176: _maxLocals = in.readShort();
177:
178: int codeLength = in.readInt();
179:
180: _code = new byte[codeLength];
181: in.read(_code, 0, codeLength);
182:
183: int exnCount = in.readShort();
184:
185: for (int i = 0; i < exnCount; i++) {
186: ExceptionItem exn = new ExceptionItem();
187:
188: exn.setStart(in.readShort() & 0xffff);
189: exn.setEnd(in.readShort() & 0xffff);
190: exn.setHandler(in.readShort() & 0xffff);
191: exn.setType(in.readShort() & 0xffff);
192:
193: _exceptions.add(exn);
194: }
195:
196: int attrCount = in.readShort();
197:
198: for (int i = 0; i < attrCount; i++) {
199: Attribute attr = in.parseAttribute();
200:
201: _attributes.add(attr);
202: }
203: }
204:
205: /**
206: * Writes the field to the output.
207: */
208: public void write(ByteCodeWriter out) throws IOException {
209: out.writeUTF8Const(getName());
210:
211: TempStream ts = new TempStream();
212: ts.openWrite();
213: WriteStream ws = new WriteStream(ts);
214: ByteCodeWriter o2 = new ByteCodeWriter(ws, out.getJavaClass());
215:
216: o2.writeShort(_maxStack);
217: o2.writeShort(_maxLocals);
218: o2.writeInt(_code.length);
219: o2.write(_code, 0, _code.length);
220:
221: o2.writeShort(_exceptions.size());
222: for (int i = 0; i < _exceptions.size(); i++) {
223: ExceptionItem exn = _exceptions.get(i);
224:
225: o2.writeShort(exn.getStart());
226: o2.writeShort(exn.getEnd());
227: o2.writeShort(exn.getHandler());
228: o2.writeShort(exn.getType());
229: }
230:
231: o2.writeShort(_attributes.size());
232: for (int i = 0; i < _attributes.size(); i++) {
233: Attribute attr = _attributes.get(i);
234:
235: attr.write(o2);
236: }
237:
238: ws.close();
239:
240: out.writeInt(ts.getLength());
241: TempBuffer ptr = ts.getHead();
242:
243: for (; ptr != null; ptr = ptr.getNext())
244: out.write(ptr.getBuffer(), 0, ptr.getLength());
245:
246: ts.destroy();
247: }
248:
249: /**
250: * Clones the attribute
251: */
252: public Attribute export(JavaClass source, JavaClass target) {
253: ConstantPool cp = target.getConstantPool();
254:
255: cp.addUTF8(getName());
256:
257: CodeAttribute attr = new CodeAttribute(getName());
258:
259: attr._maxStack = _maxStack;
260: attr._maxLocals = _maxLocals;
261:
262: byte[] code = new byte[_code.length];
263: System.arraycopy(_code, 0, code, 0, _code.length);
264: attr._code = code;
265:
266: for (int i = 0; i < _exceptions.size(); i++) {
267: ExceptionItem exn = _exceptions.get(i);
268:
269: int type = exn.getType();
270:
271: if (type != 0)
272: type = cp.addClass(
273: source.getConstantPool().getClass(type)
274: .getName()).getIndex();
275:
276: ExceptionItem newExn = new ExceptionItem(type, exn
277: .getStart(), exn.getEnd(), exn.getHandler());
278:
279: attr._exceptions.add(newExn);
280: }
281:
282: for (int i = 0; i < _attributes.size(); i++) {
283: Attribute codeAttr = _attributes.get(i);
284:
285: attr.addAttribute(codeAttr.export(source, target));
286: }
287:
288: try {
289: attr.exportCode(source, target);
290: } catch (Exception e) {
291: throw new RuntimeException(e);
292: }
293:
294: return attr;
295: }
296:
297: /**
298: * Exports code.
299: */
300: public void exportCode(JavaClass source, JavaClass target)
301: throws Exception {
302: ExportAnalyzer analyzer = new ExportAnalyzer(source, target);
303:
304: CodeEnhancer visitor = new CodeEnhancer(source, this );
305:
306: visitor.analyze(analyzer, false);
307:
308: visitor.update();
309: }
310:
311: public String toString() {
312: return "CodeAttribute[" + getName() + "]";
313: }
314:
315: public static class ExceptionItem {
316: private int _type;
317:
318: private int _start;
319: private int _end;
320: private int _handler;
321:
322: public ExceptionItem() {
323: }
324:
325: public ExceptionItem(int type, int start, int end, int handler) {
326: _type = type;
327: _start = start;
328: _end = end;
329: _handler = handler;
330: }
331:
332: /**
333: * Sets the exception type.
334: */
335: public void setType(int type) {
336: _type = type;
337: }
338:
339: /**
340: * Returns the exception type.
341: */
342: public int getType() {
343: return _type;
344: }
345:
346: /**
347: * Sets the start PC
348: */
349: public void setStart(int pc) {
350: _start = pc;
351: }
352:
353: /**
354: * Gets the start PC
355: */
356: public int getStart() {
357: return _start;
358: }
359:
360: /**
361: * Sets the end PC
362: */
363: public void setEnd(int pc) {
364: _end = pc;
365: }
366:
367: /**
368: * Gets the end PC
369: */
370: public int getEnd() {
371: return _end;
372: }
373:
374: /**
375: * Sets the handler PC
376: */
377: public void setHandler(int pc) {
378: _handler = pc;
379: }
380:
381: /**
382: * Gets the handler PC
383: */
384: public int getHandler() {
385: return _handler;
386: }
387: }
388:
389: public static class ExportAnalyzer extends Analyzer {
390: private JavaClass _source;
391: private JavaClass _target;
392:
393: public ExportAnalyzer(JavaClass source, JavaClass target) {
394: _source = source;
395: _target = target;
396: }
397:
398: public void analyze(CodeVisitor visitor) throws Exception {
399: int op = visitor.getOpcode();
400: int index;
401: ConstantPool sourcePool = _source.getConstantPool();
402: ConstantPool targetPool = _target.getConstantPool();
403: ConstantPoolEntry entry;
404:
405: switch (op) {
406: case CodeVisitor.ANEWARRAY:
407: case CodeVisitor.CHECKCAST:
408: case CodeVisitor.GETFIELD:
409: case CodeVisitor.GETSTATIC:
410: case CodeVisitor.INSTANCEOF:
411: case CodeVisitor.INVOKEINTERFACE:
412: case CodeVisitor.INVOKESPECIAL:
413: case CodeVisitor.INVOKESTATIC:
414: case CodeVisitor.INVOKEVIRTUAL:
415: case CodeVisitor.LDC_W:
416: case CodeVisitor.LDC2_W:
417: case CodeVisitor.MULTIANEWARRAY:
418: case CodeVisitor.NEW:
419: case CodeVisitor.PUTFIELD:
420: case CodeVisitor.PUTSTATIC:
421: index = visitor.getShortArg(1);
422:
423: entry = sourcePool.getEntry(index);
424: int targetIndex = entry.export(targetPool);
425:
426: visitor.setShortArg(1, targetIndex);
427: break;
428:
429: case CodeVisitor.LDC:
430: index = visitor.getByteArg(1);
431: entry = sourcePool.getEntry(index);
432: index = entry.export(targetPool);
433: if (index <= 0xff)
434: visitor.setByteArg(1, index);
435: else {
436: CodeEnhancer enhancer = (CodeEnhancer) visitor;
437: enhancer.setByteArg(0, CodeVisitor.LDC_W);
438: enhancer.addByte(enhancer.getOffset() + 2, 0);
439: enhancer.setShortArg(1, index);
440: }
441: break;
442:
443: default:
444: break;
445: }
446: }
447: }
448: }
|