172 lines
5.0 KiB
Java
172 lines
5.0 KiB
Java
/*******************************************************************************
|
|
* Copyright (c) 2002,2006 IBM Corporation.
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* Contributors:
|
|
* IBM Corporation - initial API and implementation
|
|
*******************************************************************************/
|
|
package com.ibm.wala.shrikeCT;
|
|
|
|
/**
|
|
* This class helps emit Code elements.
|
|
*
|
|
* After constructing a CodeWriter, at least the max stack, max locals and bytecode bytes must be set before it can be used.
|
|
*/
|
|
public final class CodeWriter extends ClassWriter.Element {
|
|
final private int attrID;
|
|
|
|
private int maxLocals = -1;
|
|
|
|
private int maxStack = -1;
|
|
|
|
private byte[] code;
|
|
|
|
private int[] exnHandlers;
|
|
|
|
private ClassWriter.Element[] attributes;
|
|
|
|
/**
|
|
* Build an empty serializable Code attribute.
|
|
*
|
|
* @throws IllegalArgumentException if w is null
|
|
*/
|
|
public CodeWriter(ClassWriter w) {
|
|
if (w == null) {
|
|
throw new IllegalArgumentException("w is null");
|
|
}
|
|
attrID = w.addCPUtf8("Code");
|
|
}
|
|
|
|
private void verify() {
|
|
if (maxStack < 0) {
|
|
throw new IllegalArgumentException("maxStack not set");
|
|
}
|
|
if (maxLocals < 0) {
|
|
throw new IllegalArgumentException("maxLocals not set");
|
|
}
|
|
if (code == null) {
|
|
throw new IllegalArgumentException("No bytecodes set");
|
|
}
|
|
}
|
|
|
|
public int getCodeLength() throws IllegalStateException {
|
|
if (code == null) {
|
|
throw new IllegalStateException("code not initialized");
|
|
}
|
|
return code.length;
|
|
}
|
|
|
|
@Override
|
|
public int getSize() throws IllegalArgumentException {
|
|
verify();
|
|
|
|
int size = 14 + code.length + 2 + (exnHandlers == null ? 0 : exnHandlers.length) * 2 + 2;
|
|
if (attributes != null) {
|
|
for (int i = 0; i < attributes.length; i++) {
|
|
size += attributes[i].getSize();
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
@Override
|
|
public int copyInto(byte[] buf, int offset) throws IllegalArgumentException {
|
|
verify();
|
|
|
|
int start = offset;
|
|
ClassWriter.setUShort(buf, offset, attrID);
|
|
ClassWriter.setUShort(buf, offset + 6, maxStack);
|
|
ClassWriter.setUShort(buf, offset + 8, maxLocals);
|
|
ClassWriter.setInt(buf, offset + 10, code.length);
|
|
offset += 14;
|
|
System.arraycopy(code, 0, buf, offset, code.length);
|
|
offset += code.length;
|
|
ClassWriter.setUShort(buf, offset, (exnHandlers == null ? 0 : exnHandlers.length) / 4);
|
|
offset += 2;
|
|
if (exnHandlers != null) {
|
|
for (int i = 0; i < exnHandlers.length; i++) {
|
|
ClassWriter.setUShort(buf, offset, exnHandlers[i]);
|
|
offset += 2;
|
|
}
|
|
}
|
|
|
|
ClassWriter.setUShort(buf, offset, (attributes == null ? 0 : attributes.length));
|
|
offset += 2;
|
|
if (attributes != null) {
|
|
for (int i = 0; i < attributes.length; i++) {
|
|
offset = attributes[i].copyInto(buf, offset);
|
|
}
|
|
}
|
|
ClassWriter.setInt(buf, start + 2, offset - start - 6);
|
|
return offset;
|
|
}
|
|
|
|
/**
|
|
* Set the bytecodes for this Code attribute.
|
|
*
|
|
* @throws IllegalArgumentException if code is null
|
|
*/
|
|
public void setCode(byte[] code) throws IllegalArgumentException {
|
|
if (code == null) {
|
|
throw new IllegalArgumentException("code is null");
|
|
}
|
|
if (code.length > 0xFFFF) {
|
|
throw new IllegalArgumentException("Code array is too long: " + code.length);
|
|
}
|
|
if (code.length == 0) {
|
|
throw new IllegalArgumentException("Code array is empty");
|
|
}
|
|
|
|
this.code = code;
|
|
}
|
|
|
|
/**
|
|
* Set the raw handler data for this Code attribute.
|
|
*
|
|
* @param exnHandlers a flattened sequence of (startPC, endPC, catchClassIndex, catchPC) tuples
|
|
* @throws IllegalArgumentException if exnHandlers is null
|
|
*/
|
|
public void setRawHandlers(int[] exnHandlers) {
|
|
if (exnHandlers == null) {
|
|
throw new IllegalArgumentException("exnHandlers is null");
|
|
}
|
|
if (exnHandlers.length % 4 != 0) {
|
|
throw new IllegalArgumentException("Exception handlers array has bad length: " + exnHandlers.length);
|
|
}
|
|
if (exnHandlers.length / 4 > 0xFFFF) {
|
|
throw new IllegalArgumentException("Too many exception handlers: " + exnHandlers.length / 4);
|
|
}
|
|
for (int i = 0; i < exnHandlers.length; i++) {
|
|
int v = exnHandlers[i];
|
|
if (v < 0 || v > 0xFFFF) {
|
|
throw new IllegalArgumentException("Invalid exception handler entry at " + i);
|
|
}
|
|
}
|
|
|
|
this.exnHandlers = exnHandlers;
|
|
}
|
|
|
|
/**
|
|
* Set the maximum number of local variable space used, in words, by this Code.
|
|
*/
|
|
public void setMaxLocals(int maxLocals) {
|
|
this.maxLocals = maxLocals;
|
|
}
|
|
|
|
/**
|
|
* Set the maximum stack size, in words, in this Code.
|
|
*/
|
|
public void setMaxStack(int maxStack) {
|
|
this.maxStack = maxStack;
|
|
}
|
|
|
|
/**
|
|
* Set the attributes of this Code.
|
|
*/
|
|
public void setAttributes(ClassWriter.Element[] attributes) {
|
|
this.attributes = attributes;
|
|
}
|
|
} |