aboutsummaryrefslogtreecommitdiff
path: root/src/main/javassist/bytecode/stackmap/TypedBlock.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/javassist/bytecode/stackmap/TypedBlock.java')
-rw-r--r--src/main/javassist/bytecode/stackmap/TypedBlock.java249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/main/javassist/bytecode/stackmap/TypedBlock.java b/src/main/javassist/bytecode/stackmap/TypedBlock.java
new file mode 100644
index 0000000..65dce97
--- /dev/null
+++ b/src/main/javassist/bytecode/stackmap/TypedBlock.java
@@ -0,0 +1,249 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2007 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.
+ *
+ * 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 javassist.bytecode.stackmap;
+
+import javassist.bytecode.*;
+
+public class TypedBlock extends BasicBlock {
+ public int stackTop, numLocals;
+ public TypeData[] stackTypes, localsTypes;
+
+ // set by a Liveness object.
+ // inputs[i] is true if the i-th variable is used within this block.
+ public boolean[] inputs;
+
+ // working area for Liveness class.
+ public boolean updating;
+ public int status;
+ public byte[] localsUsage;
+
+ /**
+ * Divides the method body into basic blocks.
+ * The type information of the first block is initialized.
+ *
+ * @param optmize if it is true and the method does not include
+ * branches, this method returns null.
+ */
+ public static TypedBlock[] makeBlocks(MethodInfo minfo, CodeAttribute ca,
+ boolean optimize)
+ throws BadBytecode
+ {
+ TypedBlock[] blocks = (TypedBlock[])new Maker().make(minfo);
+ if (optimize && blocks.length < 2)
+ if (blocks.length == 0 || blocks[0].incoming == 0)
+ return null;
+
+ ConstPool pool = minfo.getConstPool();
+ boolean isStatic = (minfo.getAccessFlags() & AccessFlag.STATIC) != 0;
+ blocks[0].initFirstBlock(ca.getMaxStack(), ca.getMaxLocals(),
+ pool.getClassName(), minfo.getDescriptor(),
+ isStatic, minfo.isConstructor());
+ new Liveness().compute(ca.iterator(), blocks, ca.getMaxLocals(),
+ blocks[0].localsTypes);
+ return blocks;
+ }
+
+ protected TypedBlock(int pos) {
+ super(pos);
+ localsTypes = null;
+ inputs = null;
+ updating = false;
+ }
+
+ protected void toString2(StringBuffer sbuf) {
+ super.toString2(sbuf);
+ sbuf.append(",\n stack={");
+ printTypes(sbuf, stackTop, stackTypes);
+ sbuf.append("}, locals={");
+ printTypes(sbuf, numLocals, localsTypes);
+ sbuf.append("}, inputs={");
+ if (inputs != null)
+ for (int i = 0; i < inputs.length; i++)
+ sbuf.append(inputs[i] ? "1, " : "0, ");
+
+ sbuf.append('}');
+ }
+
+ private void printTypes(StringBuffer sbuf, int size,
+ TypeData[] types) {
+ if (types == null)
+ return;
+
+ for (int i = 0; i < size; i++) {
+ if (i > 0)
+ sbuf.append(", ");
+
+ TypeData td = types[i];
+ sbuf.append(td == null ? "<>" : td.toString());
+ }
+ }
+
+ public boolean alreadySet() {
+ return localsTypes != null;
+ }
+
+ public void setStackMap(int st, TypeData[] stack, int nl, TypeData[] locals)
+ throws BadBytecode
+ {
+ stackTop = st;
+ stackTypes = stack;
+ numLocals = nl;
+ localsTypes = locals;
+ }
+
+ /*
+ * Computes the correct value of numLocals.
+ */
+ public void resetNumLocals() {
+ if (localsTypes != null) {
+ int nl = localsTypes.length;
+ while (nl > 0 && localsTypes[nl - 1] == TypeTag.TOP) {
+ if (nl > 1) {
+ TypeData td = localsTypes[nl - 2];
+ if (td == TypeTag.LONG || td == TypeTag.DOUBLE)
+ break;
+ }
+
+ --nl;
+ }
+
+ numLocals = nl;
+ }
+ }
+
+ public static class Maker extends BasicBlock.Maker {
+ protected BasicBlock makeBlock(int pos) {
+ return new TypedBlock(pos);
+ }
+
+ protected BasicBlock[] makeArray(int size) {
+ return new TypedBlock[size];
+ }
+ }
+
+ /**
+ * Initializes the first block by the given method descriptor.
+ *
+ * @param block the first basic block that this method initializes.
+ * @param className a dot-separated fully qualified class name.
+ * For example, <code>javassist.bytecode.stackmap.BasicBlock</code>.
+ * @param methodDesc method descriptor.
+ * @param isStatic true if the method is a static method.
+ * @param isConstructor true if the method is a constructor.
+ */
+ void initFirstBlock(int maxStack, int maxLocals, String className,
+ String methodDesc, boolean isStatic, boolean isConstructor)
+ throws BadBytecode
+ {
+ if (methodDesc.charAt(0) != '(')
+ throw new BadBytecode("no method descriptor: " + methodDesc);
+
+ stackTop = 0;
+ stackTypes = new TypeData[maxStack];
+ TypeData[] locals = new TypeData[maxLocals];
+ if (isConstructor)
+ locals[0] = new TypeData.UninitThis(className);
+ else if (!isStatic)
+ locals[0] = new TypeData.ClassName(className);
+
+ int n = isStatic ? -1 : 0;
+ int i = 1;
+ try {
+ while ((i = descToTag(methodDesc, i, ++n, locals)) > 0)
+ if (locals[n].is2WordType())
+ locals[++n] = TypeTag.TOP;
+ }
+ catch (StringIndexOutOfBoundsException e) {
+ throw new BadBytecode("bad method descriptor: "
+ + methodDesc);
+ }
+
+ numLocals = n;
+ localsTypes = locals;
+ }
+
+ private static int descToTag(String desc, int i,
+ int n, TypeData[] types)
+ throws BadBytecode
+ {
+ int i0 = i;
+ int arrayDim = 0;
+ char c = desc.charAt(i);
+ if (c == ')')
+ return 0;
+
+ while (c == '[') {
+ ++arrayDim;
+ c = desc.charAt(++i);
+ }
+
+ if (c == 'L') {
+ int i2 = desc.indexOf(';', ++i);
+ if (arrayDim > 0)
+ types[n] = new TypeData.ClassName(desc.substring(i0, ++i2));
+ else
+ types[n] = new TypeData.ClassName(desc.substring(i0 + 1, ++i2 - 1)
+ .replace('/', '.'));
+ return i2;
+ }
+ else if (arrayDim > 0) {
+ types[n] = new TypeData.ClassName(desc.substring(i0, ++i));
+ return i;
+ }
+ else {
+ TypeData t = toPrimitiveTag(c);
+ if (t == null)
+ throw new BadBytecode("bad method descriptor: " + desc);
+
+ types[n] = t;
+ return i + 1;
+ }
+ }
+
+ private static TypeData toPrimitiveTag(char c) {
+ switch (c) {
+ case 'Z' :
+ case 'C' :
+ case 'B' :
+ case 'S' :
+ case 'I' :
+ return TypeTag.INTEGER;
+ case 'J' :
+ return TypeTag.LONG;
+ case 'F' :
+ return TypeTag.FLOAT;
+ case 'D' :
+ return TypeTag.DOUBLE;
+ case 'V' :
+ default :
+ return null;
+ }
+ }
+
+ public static String getRetType(String desc) {
+ int i = desc.indexOf(')');
+ if (i < 0)
+ return "java.lang.Object";
+
+ char c = desc.charAt(i + 1);
+ if (c == '[')
+ return desc.substring(i + 1);
+ else if (c == 'L')
+ return desc.substring(i + 2, desc.length() - 1).replace('/', '.');
+ else
+ return "java.lang.Object";
+ }
+}