harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ge...@apache.org
Subject svn commit: r294974 [6/25] - in /incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm: ./ jchevm/ jchevm/doc/ jchevm/etc/ jchevm/include/ jchevm/java/ jchevm/java/org/ jchevm/java/org/dellroad/ jchevm/java/org/dellroad/jc/ jchevm/java/org/dellroad/...
Date Wed, 05 Oct 2005 02:20:10 GMT
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CExpr.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CExpr.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CExpr.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CExpr.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,454 @@
+
+//
+// Copyright 2005 The Apache Software Foundation or its licensors,
+// as applicable.
+// 
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+// $Id: CExpr.java,v 1.4 2005/01/25 23:12:09 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import soot.*;
+import soot.jimple.*;
+import java.util.*;
+
+/**
+ * Class for assembling C language expressions and outputting them
+ * as C code.
+ *
+ * <p>
+ * The purpose of this class is to allow us to output arbitrarily
+ * complex expressions in C that contain sufficient, but not
+ * stupidly unnecessary, parentheses. Note that we do output
+ * unnecessary parentheses in those cases where it's deemed
+ * to make things clearer.
+ * </p>
+ */
+public class CExpr {
+
+	/* Variables and constants */
+	public static final int ATOMIC = 0;
+
+	/* Unary expressions */
+	public static final int DEREFERENCE = 1;
+	public static final int ADDRESS_OF = 2;
+	public static final int LOGICAL_NOT = 3;
+	public static final int COMPLEMENT = 4;
+	public static final int NEGATE = 5;
+
+	/* Binary expressions */
+	public static final int ADD = 6;
+	public static final int SUBTRACT = 7;
+	public static final int LOGICAL_AND = 8;
+	public static final int LOGICAL_OR = 9;
+	public static final int AND = 10;
+	public static final int OR = 11;
+	public static final int XOR = 12;
+	public static final int DIVIDE = 13;
+	public static final int MULTIPLY = 14;
+	public static final int MODULO = 15;
+	public static final int SHIFT_LEFT = 16;
+	public static final int SHIFT_RIGHT = 17;
+	public static final int ARROW = 18;
+	public static final int ARRAYINDEX = 19;
+	public static final int LT = 20;
+	public static final int LE = 21;
+	public static final int GT = 22;
+	public static final int GE = 23;
+	public static final int EQUAL = 24;
+	public static final int NOT_EQUAL = 25;
+	public static final int CAST = 26;
+
+	/* >= 2 operand expressions */
+	public static final int FUNCTION = 27;
+	public static final int THREEWAY = 28;
+
+	public static final int NUM_TYPES = 29;
+
+	private final int type;
+	private final CExpr ops[];
+	private String symbol;
+	private String s;
+
+	private static int[] prec;
+	private static int[] order;
+
+	static {
+
+		// Partially order operators as to how we want or need to
+		// require parentheses around operators. Note that we
+		// require them in cases not strictly required for C,
+		// e.g., by grouping together LOGICAL_AND and LOGICAL_OR.
+
+		ArrayList a = new ArrayList();
+		a.add(new int[] { ATOMIC });
+		a.add(new int[] { CAST, ARROW, ARRAYINDEX, FUNCTION });
+		a.add(new int[] { DEREFERENCE,
+		    NEGATE, ADDRESS_OF, LOGICAL_NOT, COMPLEMENT });
+		a.add(new int[] { MULTIPLY, DIVIDE, MODULO,
+		    ADD, SUBTRACT, SHIFT_LEFT, SHIFT_RIGHT });
+		a.add(new int[] { LT, LE, GT, GE, EQUAL, NOT_EQUAL });
+		a.add(new int[] { AND, OR, XOR });
+		a.add(new int[] { LOGICAL_AND, LOGICAL_OR });
+		a.add(new int[] { THREEWAY });
+		int[][] revp = (int [][])a.toArray(new int[a.size()][]);
+
+		// Compute precedence mapping based on partial order
+		prec = new int[NUM_TYPES];
+		order = new int[NUM_TYPES];
+		for (int i = 0; i < revp.length; i++) {
+			for (int j = 0; j < revp[i].length; j++) {
+				int op = revp[i][j];
+				order[op] = revp[i][0];
+				prec[op] = i;
+			}
+		}
+	}
+
+	/**
+	 * Create an "atomic" C expression containing the given string.
+	 */
+	public CExpr(String s) {
+		this.type = ATOMIC;
+		this.ops = null;
+		this.s = s;
+	}
+
+	/**
+	 * Create a function invocation or unary C expression.
+	 */
+	public CExpr(int type, CExpr op1) {
+		this(type, new CExpr[] { op1 });
+	}
+
+	/**
+	 * Create a function invocation or binary C expression.
+	 */
+	public CExpr(int type, CExpr op1, CExpr op2) {
+		this(type, new CExpr[] { op1, op2 });
+	}
+
+	/**
+	 * Create a function invocation or ternary C expression.
+	 */
+	public CExpr(int type, CExpr op1, CExpr op2, CExpr op3) {
+		this(type, new CExpr[] { op1, op2, op3 });
+	}
+
+	/**
+	 * Create a function invocation or unary C expression.
+	 */
+	public CExpr(int type, Object op1) {
+		this(type, new Object[] { op1 });
+	}
+
+	/**
+	 * Create a function invocation or binary C expression.
+	 */
+	public CExpr(int type, Object op1, Object op2) {
+		this(type, new Object[] { op1, op2 });
+	}
+
+	/**
+	 * Create a function invocation or ternary C expression.
+	 */
+	public CExpr(int type, Object op1, Object op2, Object op3) {
+		this(type, new Object[] { op1, op2, op3 });
+	}
+
+	/**
+	 * Create a function invocation.
+	 */
+	public CExpr(int type, Object op1, Object op2, Object op3, Object op4) {
+		this(type, new Object[] { op1, op2, op3, op4 });
+	}
+
+	public CExpr(int type, Collection ops) {
+		this(type, ops.toArray());
+	}
+
+	public CExpr(int type, Object[] ops) {
+
+		// Check arguments
+		if (type < 0 || type >= NUM_TYPES)
+			throw new IllegalArgumentException("bogus type");
+		if (isUnary(type)) {
+			if (ops.length != 1)
+				throw new IllegalArgumentException("unary");
+		} else if (isBinary(type)) {
+			if (ops.length != 2)
+				throw new IllegalArgumentException("binary");
+		} else if (isTernary(type)) {
+			if (ops.length != 3)
+				throw new IllegalArgumentException("ternary");
+		} else {
+			if (ops.length < 1)
+				throw new IllegalArgumentException("function");
+		}
+		this.type = type;
+
+		// Convert any non-CExpr arguments to ATOMIC's
+		if (ops instanceof CExpr[])
+			this.ops = (CExpr[])ops;
+		else {
+			this.ops = new CExpr[ops.length];
+			for (int i = 0; i < ops.length; i++) {
+				if (ops[i] instanceof CExpr) {
+					this.ops[i] = (CExpr)ops[i];
+					continue;
+				}
+				if (ops[i] instanceof ValueBox) {
+					this.ops[i] = C.value((ValueBox)ops[i]);
+					continue;
+				}
+				if (ops[i] instanceof Type) {
+					this.ops[i] = new CExpr(ADDRESS_OF,
+					    C.jc_type((Type)ops[i]));
+					continue;
+				}
+				if (ops[i] instanceof SootClass) {
+					this.ops[i] = new CExpr(
+					    C.name((SootClass)ops[i]));
+					continue;
+				}
+				if (ops[i] instanceof SootField) {
+					this.ops[i] = new CExpr(
+					    C.name((SootField)ops[i]));
+					continue;
+				}
+				if (ops[i] instanceof SootMethod) {
+					this.ops[i] = new CExpr(
+					    C.name((SootMethod)ops[i]));
+					continue;
+				}
+				if (ops[i] instanceof Value) {
+					throw new RuntimeException("Value"
+					    + " should be ValueBox: " + ops[i]);
+				}
+				this.ops[i] = new CExpr(ops[i].toString());
+			}
+		}
+
+		// Get symbol
+		switch (type) {
+		case DEREFERENCE:	symbol = "*";	break;
+		case ADDRESS_OF:	symbol = "&";	break;
+		case LOGICAL_NOT:	symbol = "!";	break;
+		case COMPLEMENT:	symbol = "~";	break;
+		case NEGATE:		symbol = "-";	break;
+		case ADD:		symbol = "+";	break;
+		case SUBTRACT:		symbol = "-";	break;
+		case LOGICAL_AND:	symbol = "&&";	break;
+		case LOGICAL_OR:	symbol = "||";	break;
+		case AND:		symbol = "&";	break;
+		case OR:		symbol = "|";	break;
+		case XOR:		symbol = "^";	break;
+		case DIVIDE:		symbol = "/";	break;
+		case MULTIPLY:		symbol = "*";	break;
+		case MODULO:		symbol = "%";	break;
+		case SHIFT_LEFT:	symbol = "<<";	break;
+		case SHIFT_RIGHT:	symbol = ">>";	break;
+		case ARROW:		symbol = "->";	break;
+		case ARRAYINDEX:	symbol = "[]";	break;	// never used
+		case LT:		symbol = "<";	break;
+		case LE:		symbol = "<=";	break;
+		case GT:		symbol = ">";	break;
+		case GE:		symbol = ">=";	break;
+		case EQUAL:		symbol = "==";	break;
+		case NOT_EQUAL:		symbol = "!=";	break;
+		case THREEWAY:		symbol = "?:";	break;	// never used
+		case CAST:		symbol = "()";	break;	// never used
+		default:				break;
+		}
+	}
+
+	public static boolean isUnary(int type) {
+		return (type >= DEREFERENCE && type <= NEGATE);
+	}
+
+	public static boolean isBinary(int type) {
+		return (type >= ADD && type <= CAST);
+	}
+
+	public static boolean isTernary(int type) {
+		return (type == THREEWAY);
+	}
+
+	private void gen() {
+		StringBuffer b = new StringBuffer();
+
+		// Handle special cases
+		switch (type) {
+		case FUNCTION:
+			addOp(b, 0);
+			b.append('(');
+			for (int i = 1; i < ops.length; i++) {
+				if (i > 1)
+					b.append(", ");
+				b.append(ops[i]);
+			}
+			b.append(')');
+			break;
+		case ARRAYINDEX:
+			addOp(b, 0);
+			b.append('[');
+			b.append(ops[1]);
+			b.append(']');
+			break;
+		case THREEWAY:
+			addOp(b, 0);
+			b.append(" ? ");
+			addOp(b, 1);
+			b.append(" : ");
+			addOp(b, 2);
+			break;
+		case CAST:
+			b.append('(');
+			addOp(b, 0);
+			b.append(')');
+			addOp(b, 1);
+			break;
+		default:
+			if (isUnary(type)) {
+				b.append(symbol);
+				addOp(b, 0);
+			} else {
+				addOp(b, 0);
+				if (type != ARROW)
+					b.append(' ');
+				b.append(symbol);
+				if (type != ARROW)
+					b.append(' ');
+				addOp(b, 1);
+			}
+			break;
+		}
+
+		// Done
+		s = b.toString();
+	}
+
+	private void addOp(StringBuffer b, int op) {
+
+		// Determine whether to parenthesize
+		boolean parens = false;
+		switch (ops[op].type) {
+		case ATOMIC:
+			parens = false;
+			break;
+		case AND:
+		case OR:
+		case XOR:
+			parens = true;
+			break;
+		default:
+			if (prec[ops[op].type] >= prec[type])
+				parens = true;
+			if (prec[ops[op].type] == prec[type]) {
+				if (isUnary(type))
+					parens = false;
+				if ((type == FUNCTION || type == CAST
+				      || type == ARRAYINDEX || type == ARROW)
+				    && op == 0)
+					parens = false;
+			}
+			if ((type == AND || type == OR || type == XOR)
+			    && !isUnary(ops[op].type))
+				parens = true;
+			if (type == CAST && op == 0)
+				parens = false;
+			break;
+		}
+		if (type == THREEWAY && op > 0 && ops[op].type != ATOMIC)
+			parens = true;
+		if (parens)
+			b.append('(');
+		b.append(ops[op]);
+		if (parens)
+			b.append(')');
+	}
+
+	/**
+	 * Return valid C code that expresses this C expression.
+	 */
+	public String toString() {
+		if (s == null)
+			gen();
+		return s;
+	}
+
+	private static int depth;
+
+	/**
+	 * Generate a random C expression. Used for testing.
+	 */
+	public static CExpr random(Random r) {
+		int type;
+		CExpr e;
+
+		depth++;
+		if (depth >= 5)
+			type = ATOMIC;
+		else
+			type = r.nextInt(NUM_TYPES);
+		switch (type) {
+		case FUNCTION:
+			CExpr[] params = new CExpr[r.nextInt(4) + 1];
+			for (int i = 0; i < params.length; i++)
+				params[i] = random(r);
+			e = new CExpr(type, params);
+			break;
+		case ATOMIC:
+			e = new CExpr("x");
+			break;
+		default:
+			if (isUnary(type))
+				e = new CExpr(type, new CExpr[] { random(r) });
+			else if (isBinary(type)) {
+				e = new CExpr(type,
+				    new CExpr[] { random(r), random(r) });
+			} else if (isTernary(type)) {
+				e = new CExpr(type, new CExpr[] { random(r),
+				    random(r), random(r) });
+			} else {
+				Util.panic("impossible flow");
+				e = null;
+			}
+			break;
+		}
+		depth--;
+		return e;
+	}
+
+	public void dumpOps(int depth) {
+		for (int i = 0; i < ops.length; i++) {
+			for (int j = 0; j < depth; j++)
+				System.out.print("  ");
+			System.out.println(i + ": " + ops[i]);
+			if (ops[i].type != ATOMIC)
+				ops[i].dumpOps(depth + 1);
+		}
+	}
+
+	/** 
+	 * Test method.
+	 */
+	public static void main(String[] args) {
+		CExpr e = random(new Random());
+		e.dumpOps(0);
+		System.out.println(e);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CFile.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CFile.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CFile.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CFile.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,959 @@
+
+//
+// Copyright 2005 The Apache Software Foundation or its licensors,
+// as applicable.
+// 
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+// $Id: CFile.java,v 1.19 2005/03/13 00:18:50 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import soot.*;
+import soot.tagkit.*;
+import soot.jimple.*;
+import java.util.*;
+import java.io.*;
+
+/**
+ * Represents a C source file being constructed from a Java class file.
+ */
+public class CFile extends SourceFile {
+	public static final String includeStringName = "_jc_include";
+	HashSet[] iMethodBuckets;
+	int numNonemptyIMethodBuckets;
+	int numSingletonIMethodBuckets;
+	HashSet fullDepends;
+	HashSet baseDepends;
+	HashMap methodMap;			// SootMethod -> CMethod
+	MethodOptimizer optimizer;
+	boolean includeLineNumbers;
+	JimpleBody body;
+
+	public CFile(SootClass c, Writer out,
+	    MethodOptimizer optimizer, boolean includeLineNumbers) {
+		super(c, out);
+		this.optimizer = optimizer;
+		this.includeLineNumbers = includeLineNumbers;
+		prepare();
+	}
+
+	/**
+	 * Output the C source file.
+	 */
+	public void output() {
+		outputInitialStuff();
+		if (!c.getFields().isEmpty()) {
+			outputBanner("Fields");
+			outputFields();
+		}
+		ArrayList list = new ArrayList();
+		list.addAll(Arrays.asList(staticFields));
+		list.addAll(Arrays.asList(virtualFields));
+		SootField[] fields = (SootField[])list.toArray(
+		    new SootField[list.size()]);
+		Arrays.sort(fields, Util.fieldComparator);
+		outputFieldList(fields, "Fields", "fields");
+		if (staticMethods.length > 0) {
+			outputBanner("Static methods");
+			outputMethods(staticMethods);
+		}
+		if (constructors.length > 0) {
+			outputBanner("Constructors");
+			outputMethods(constructors);
+		}
+		if (virtualMethods.length > 0) {
+			outputBanner("Instance methods");
+			outputMethods(virtualMethods);
+		}
+		outputBanner("Method list");
+		list.clear();
+		list.addAll(Arrays.asList(staticMethods));
+		list.addAll(Arrays.asList(constructors));
+		list.addAll(Arrays.asList(virtualMethods));
+		SootMethod[] methods = (SootMethod[])list.toArray(
+		    new SootMethod[list.size()]);
+		Arrays.sort(methods, Util.methodComparator);
+		outputMethodList(methods, "Methods", "methods");
+		if (staticFields.length > 0) {
+			outputBanner("Class fields structure");
+			outputStaticFieldStructure();
+		}
+		if (c.getInterfaceCount() > 0) {
+			outputBanner("Interface list");
+			outputInterfaceList();
+		}
+		if (!c.isInterface() && numNonemptyIMethodBuckets > 0) {
+			outputBanner("Interface hash table");
+			outputInterfaceHashTable();
+			if (numSingletonIMethodBuckets > 0)
+				outputInterfaceQuickTable();
+		}
+		outputBanner("Instanceof hash table");
+		outputInstanceOfHashTable();
+		outputBanner("Dependency list");
+		outputDepedencyList();
+		outputBanner("Class info");
+		outputInnerClases();
+		outputClassInfo();
+		outputFinalStuff();
+		out.close();
+	}
+
+	private void prepare() {
+
+		// Do interface hash table
+		prepareInterfaceMethodHashTable();
+
+		// Create dependency set
+		fullDepends = new HashSet();
+
+		// Analyze and optimze all methods
+		methodMap = new HashMap(c.getMethods().size(), 2.0f);
+		for (Iterator i = c.getMethods().iterator(); i.hasNext(); ) {
+			SootMethod m = (SootMethod)i.next();
+			CMethod cm = new CMethod(this, m,
+			    optimizer, includeLineNumbers, fullDepends);
+			methodMap.put(m, cm);
+		}
+
+		// Prepare dependencies
+		prepareDependencies();
+	}
+
+	/**
+	 * Generate interface method hash table.
+	 */
+	private void prepareInterfaceMethodHashTable() {
+
+		// Skip if class is not instantiable
+		if (c.isInterface() || c.isAbstract())
+			return;
+
+		// Generate set of all implemented interfaces
+		Set allInterfaces = Util.getAllInterfaces(c);
+
+		// Create interface method hash table
+		iMethodBuckets = new HashSet[IMETHOD_HASHSIZE];
+
+		// Generate set of signatures of methods specified by any
+		// (possibly inherited) interface implemented by this class
+		HashSet isigs = new HashSet();
+		for (Iterator i = allInterfaces.iterator(); i.hasNext(); ) {
+			SootClass sc = (SootClass)i.next();
+			for (Iterator j = sc.getMethods().iterator();
+			    j.hasNext(); ) {
+				SootMethod m = (SootMethod)j.next();
+				if (m.isStatic())
+					continue;
+				isigs.add(m.getSubSignature());
+			}
+		}
+
+		// Add corresponding methods to the hash table buckets
+		for (Iterator i = isigs.iterator(); i.hasNext(); ) {
+			SootMethod m = Util.findMethod(c, (String)i.next());
+			Util.require(!m.isAbstract());
+			int bucket = Util.imethodHash(m);
+			if (iMethodBuckets[bucket] == null) {
+				iMethodBuckets[bucket] = new HashSet();
+				numNonemptyIMethodBuckets++;
+				numSingletonIMethodBuckets++;
+			} else if (iMethodBuckets[bucket].size() == 1
+			    && !iMethodBuckets[bucket].contains(m))
+				numSingletonIMethodBuckets--;
+			iMethodBuckets[bucket].add(m);
+		}
+	}
+
+	/**
+	 * Add dependencies on all classes that could, if changed,
+	 * require this class's JC source file to be regenerated
+	 * and/or recompiled. This includes headers where any structures
+	 * we use are defined.
+	 */
+	protected void prepareDependencies() {
+
+		// Add this class and java.lang.Class, both of which
+		// are implicit method parameter types
+		fullDepends.add(c);
+		fullDepends.add(
+		    Scene.v().loadClassAndSupport("java.lang.Class"));
+
+		// Add java.lang.String, because we can have String constants
+		fullDepends.add(
+		    Scene.v().loadClassAndSupport("java.lang.String"));
+
+		// Add all superclasses and superinterfaces
+		Util.addSupertypes(c, fullDepends);
+
+		// Add dependencies for all fields
+		for (Iterator i = c.getFields().iterator(); i.hasNext(); ) {
+			addDependency(fullDepends,
+			    ((SootField)i.next()).getType());
+		}
+
+		// Add dependencies for all methods
+		for (Iterator i = c.getMethods().iterator(); i.hasNext(); )
+			addDependencies(fullDepends, (SootMethod)i.next());
+
+		// Add dependencies for all inner classes and outer class
+		for (int i = 0; i < innerClasses.length; i++)
+			fullDepends.add(innerClasses[i].inner);
+		if (outerClass != null)
+			fullDepends.add(outerClass);
+
+		// Remove all superclasses to get base dependency set
+		baseDepends = (HashSet)fullDepends.clone();
+		for (Iterator i = fullDepends.iterator(); i.hasNext(); ) {
+			for (SootClass sc = (SootClass)i.next();
+			    sc.hasSuperclass(); ) {
+				sc = sc.getSuperclass();
+				baseDepends.remove(sc);
+			}
+		}
+	}
+
+	/**
+	 * Add to <code>set</code> the {@link SootClass} associated with
+	 * {@link Type} <code>t</code>, if any.
+	 */
+	protected void addDependency(Set set, Type t) {
+		if (t instanceof ArrayType)
+			t = ((ArrayType)t).baseType;
+		if (t instanceof RefType)
+			set.add(((RefType)t).getSootClass());
+	}
+
+	/**
+	 * Add all SootClasses to <code>set</code> that are referenced by
+	 * the method signature, throws clause, locals, traps, or body
+	 * instructions.
+	 */
+	protected void addDependencies(final Set set, SootMethod m) {
+
+		// Add return type
+		addDependency(set, m.getReturnType());
+
+		// Add parameter types
+		for (int i = 0; i < m.getParameterCount(); i++)
+			addDependency(set, m.getParameterType(i));
+
+		// Add thrown exception types
+		for (Iterator i = m.getExceptions().iterator(); i.hasNext(); )
+			set.add((SootClass)i.next());
+
+		// Stop here if there's no body
+		if (m.isAbstract() || m.isNative())
+			return;
+
+		// Synchronized methods will get a new java.lang.Throwable trap
+		if (m.isSynchronized())
+			set.add(Scene.v().getSootClass("java.lang.Throwable"));
+
+		// Add locals' types
+		Body body = m.retrieveActiveBody();
+		for (Iterator i = body.getLocals().iterator(); i.hasNext(); )
+			addDependency(set, ((Local)i.next()).getType());
+
+		// Add traps
+		for (Iterator i = body.getTraps().iterator(); i.hasNext(); )
+			set.add(((Trap)i.next()).getException());
+
+		// Add classes any of whose static fields or methods we use
+		// or to whom we refer directly (e.g., via instanceof).
+		for (Iterator i = body.getUseAndDefBoxes().iterator();
+		    i.hasNext(); ) {
+			ValueBox vb = (ValueBox)i.next();
+			vb.getValue().apply(new AbstractJimpleValueSwitch() {
+			    public void caseSpecialInvokeExpr(
+			      SpecialInvokeExpr v) {
+				caseInvokeExpr(v);
+			    }
+			    public void caseStaticInvokeExpr(
+			      StaticInvokeExpr v) {
+				caseInvokeExpr(v);
+			    }
+			    public void caseVirtualInvokeExpr(
+			      VirtualInvokeExpr v) {
+				caseInvokeExpr(v);
+			    }
+			    private void caseInvokeExpr(InvokeExpr v) {
+				set.add(
+				  v.getMethod().getDeclaringClass());
+			    }
+			    public void caseStaticFieldRef(StaticFieldRef v) {
+				set.add(
+				  v.getField().getDeclaringClass());
+			    }
+			    public void caseCastExpr(CastExpr v) {
+				addDependency(set, v.getCastType());
+			    }
+			    public void caseInstanceOfExpr(InstanceOfExpr v) {
+				addDependency(set, v.getCheckType());
+			    }
+			    public void caseNewArrayExpr(NewArrayExpr v) {
+				addDependency(set, v.getType());
+			    }
+			    public void caseNewMultiArrayExpr(
+					NewMultiArrayExpr v) {
+				addDependency(set, v.getType());
+			    }
+			    public void caseNewExpr(NewExpr v) { // needed?
+				addDependency(set, v.getBaseType());
+			    }
+			    public void caseCaughtExceptionRef(
+					CaughtExceptionRef v) {
+				addDependency(set, v.getType());
+			    }
+			});
+		}
+	}
+
+	public void outputInitialStuff() {
+
+		// Output initial comments and #include lines
+		// We #include headers for all classes we depend upon,
+		// but not including any superclasses, because those
+		// header files are included by base class header files.
+		// Our dependency list is the full list (probably overkill)
+		super.outputInitialStuff(
+		    (SootClass[])baseDepends.toArray(
+		      new SootClass[baseDepends.size()]),
+		    (SootClass[])fullDepends.toArray(
+		       new SootClass[fullDepends.size()]),
+		    true);
+
+/***
+		// Do any direct included string
+		Type stringType = RefType.v("java.lang.String");
+		if (c.declaresField(includeStringName, stringType)) {
+			SootField f = c.getField(includeStringName, stringType);
+			if (f.isStatic()
+			    && Util.isFinal(f) 
+			    && f.hasTag("ConstantValue")) {
+				byte[] value = f.getTag(
+				    "ConstantValue").getValue();
+				for (int i = 0; i < value.length; i++) {
+					char ch = (char)(value[i] & 0xff);
+					if (ch == '\n')
+						out.println();
+					else
+						out.print(ch);
+				}
+			}
+		}
+***/
+	}
+
+	public void outputFields() {
+		for (Iterator i = c.getFields().iterator(); i.hasNext(); )
+			outputField((SootField)i.next());
+	}
+
+	public void outputField(SootField f) {
+		out.println("// " + C.string(f.getDeclaration(), false));
+		ConstantValueTag initialValue = getInitialValue(f);
+		boolean isString = (f.getType() instanceof RefType)
+		    && ((RefType)f.getType()).getSootClass().equals(
+		      Scene.v().getSootClass("java.lang.String"));
+		if (initialValue != null && !isString)
+			outputInitialValue(f, initialValue);
+		out.println("static _jc_field "
+		    + prefix + "$field_info$" + C.name(f) + " = {");
+		out.indent();
+		out.println(".name=\t\t" + C.string(f.getName()) + ",");
+		out.println(".signature=\t"
+		    + C.string(Util.fieldDescriptor(f.getType())) + ",");
+		out.println(".class=\t\t&" + prefix + "$type,");
+		out.println(".type=\t\t&" + C.jc_type(f.getType()) + ",");
+		out.println(".access_flags=\t" + C.accessDefs(f) + ",");
+		out.print(".offset=\t");
+		if (f.isStatic()) {
+			out.println("_JC_OFFSETOF("
+			    + prefix + "$fields_struct, " + C.name(f) + "),");
+		} else if (Util.isReference(f)) {	/* { */
+			out.println("_JC_OFFSETOF("
+			    + prefix + "$object, refs[-1]."
+			    + cname + "." + C.name(f) + "),");
+		} else {				/* { */
+			out.println("_JC_OFFSETOF("
+			    + prefix + "$object, nonrefs."
+			    + cname + "." + C.name(f) + "),");
+		}
+		if (initialValue != null) {
+			out.print(".initial_value=\t");
+			if (isString) {
+				out.print(C.string(
+				    ((StringConstantValueTag)initialValue)
+				      .getStringValue()));
+			} else {
+				out.print("&" + prefix
+				    + "$initial_value$" + C.name(f));
+			}
+			out.println(",");
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public ConstantValueTag getInitialValue(SootField f) {
+
+		// Only static fields can have initial values
+		if (!f.isStatic())
+			return null;
+
+		// Look for ConstantValue tag
+		for (Iterator i = f.getTags().iterator(); i.hasNext(); ) {
+			Tag tag = (Tag)i.next();
+			if (tag instanceof ConstantValueTag)
+				return (ConstantValueTag)tag;
+		}
+		return null;
+	}
+
+	public void outputInitialValue(final SootField f,
+	    final ConstantValueTag cvTag) {
+		TypeSwitch ts = new TypeSwitch() {
+		    public void caseBooleanType(BooleanType t) {
+			IntegerConstantValueTag tag
+			    = (IntegerConstantValueTag)cvTag;
+			out.println("static const jboolean " + prefix
+			    + "$initial_value$" + C.name(f) + " = "
+			    + tag.getIntValue() + ";");
+		    }
+		    public void caseByteType(ByteType t) {
+			IntegerConstantValueTag tag
+			    = (IntegerConstantValueTag)cvTag;
+			out.println("static const jbyte " + prefix
+			    + "$initial_value$" + C.name(f) + " = "
+			    + tag.getIntValue() + ";");
+		    }
+		    public void caseCharType(CharType t) {
+			IntegerConstantValueTag tag
+			    = (IntegerConstantValueTag)cvTag;
+			out.println("static const jchar " + prefix
+			    + "$initial_value$" + C.name(f) + " = "
+			    + tag.getIntValue() + ";");
+		    }
+		    public void caseShortType(ShortType t) {
+			IntegerConstantValueTag tag
+			    = (IntegerConstantValueTag)cvTag;
+			out.println("static const jshort " + prefix
+			    + "$initial_value$" + C.name(f) + " = "
+			    + tag.getIntValue() + ";");
+		    }
+		    public void caseIntType(IntType t) {
+			IntegerConstantValueTag tag
+			    = (IntegerConstantValueTag)cvTag;
+			out.println("static const jint " + prefix
+			    + "$initial_value$" + C.name(f) + " = "
+			    + tag.getIntValue() + ";");
+		    }
+		    public void caseLongType(LongType t) {
+			LongConstantValueTag tag = (LongConstantValueTag)cvTag;
+			out.println("static const jlong " + prefix
+			    + "$initial_value$" + C.name(f) + " = _JC_JLONG("
+			    + tag.getLongValue() + ");");
+		    }
+		    public void caseFloatType(FloatType t) {
+			FloatConstantValueTag tag
+			    = (FloatConstantValueTag)cvTag;
+			out.print("static const unsigned char " + prefix
+			    + "$initial_value$" + C.name(f) + "[] = {");
+			byte[] bytes = tag.getValue();
+			for (int i = 0; i < 4; i++) {
+			    if (i > 0)
+				out.print(",");
+			    out.print(" 0x"
+				+ Integer.toHexString(bytes[i] & 0xff));
+			}
+			out.println(" };");
+		    }
+		    public void caseDoubleType(DoubleType t) {
+			DoubleConstantValueTag tag
+			    = (DoubleConstantValueTag)cvTag;
+			out.print("static const unsigned char " + prefix
+			    + "$initial_value$" + C.name(f) + "[] = {");
+			byte[] bytes = tag.getValue();
+			for (int i = 0; i < 8; i++) {
+			    if (i > 0)
+				out.print(",");
+			    out.print(" 0x"
+				+ Integer.toHexString(bytes[i] & 0xff));
+			}
+			out.println(" };");
+		    }
+		    public void caseRefType(RefType t) {	// String
+			StringConstantValueTag tag
+			    = (StringConstantValueTag)cvTag;
+			out.println("static const char *" + prefix
+			    + "$initial_value$" + C.name(f) + " = "
+			    + C.string(tag.getStringValue()) + ";");
+		    }
+		    public void defaultCase(Type t) {
+			Util.panic("bogus type " + t);
+		    }
+		};
+		f.getType().apply(ts);
+	}
+
+	public void outputStaticFieldStructure() {
+		out.println(prefix + "$fields_struct "
+		    + prefix + "$class_fields = { };");
+		out.println();
+	}
+
+	public void outputMethods(SootMethod[] list) {
+		for (int i = 0; i < list.length; i++)
+			outputMethod(list[i]);
+	}
+
+	public void outputMethod(SootMethod m) {
+		out.println("//");
+		out.println("// " + C.string(m.getDeclaration(), false));
+		out.println("//");
+		out.println();
+		CMethod cm = (CMethod)methodMap.get(m);
+		cm.outputMethodInfo();
+		cm.outputMethodFunction();
+	}
+
+	public void outputFieldList(SootField[] fields,
+			String comment, String label) {
+		if (fields.length == 0)
+			return;
+		outputCommentLine(comment);
+		out.println("static _jc_field *const "
+		    + prefix + "$" + label + "[] = {");
+		out.indent();
+		for (int i = 0; i < fields.length; i++) {
+			out.print("&" + prefix + "$field_info$"
+			    + C.name(fields[i]));
+			if (i < fields.length - 1)
+				out.print(',');
+			out.println();
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputMethodList(SootMethod[] methods,
+			String comment, String label) {
+		if (methods.length == 0)
+			return;
+		outputCommentLine(comment);
+		out.println("static _jc_method *const "
+		    + prefix + "$" + label + "[] = {");
+		out.indent();
+		for (int i = 0; i < methods.length; i++) {
+			out.print("&" + prefix + "$method_info$"
+			    + C.name(methods[i]));
+			if (i < methods.length - 1)
+				out.print(',');
+			out.println();
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputInterfaceList() {
+
+		// List directly implemented interfaces
+		outputCommentLine("Directly implemented interfaces");
+		out.println("static _jc_type *const "
+		    + prefix + "$interfaces[] = {");
+		out.indent();
+		Collection ifaces = c.getInterfaces();
+		SootClass[] list = (SootClass[])ifaces.toArray(
+		    new SootClass[ifaces.size()]);
+		for (int i = 0; i < list.length; i++) {
+			out.print("&_jc_" + C.name(list[i]) + "$type");
+			if (i < list.length - 1)
+				out.print(',');
+			out.println();
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputInterfaceHashTable() {
+
+		// Sanity check
+		out.println("#if _JC_IMETHOD_HASHSIZE != " + IMETHOD_HASHSIZE);
+		out.println("#error \"_JC_IMETHOD_HASHSIZE has the wrong"
+		    + " value (should be " + IMETHOD_HASHSIZE + ")\"");
+		out.println("#endif");
+		out.println();
+
+		outputCommentLine("Interface lookup hash table buckets");
+		for (int i = 0; i < IMETHOD_HASHSIZE; i++) {
+			if (iMethodBuckets[i] == null)
+				continue;
+			out.println("static _jc_method *"
+			    + prefix + "$imethod_hash_bucket_" + i + "[] = {");
+			out.indent();
+			SootMethod[] list = (SootMethod[])iMethodBuckets[i]
+			    .toArray(new SootMethod[iMethodBuckets[i].size()]);
+			Arrays.sort(list, Util.methodComparator);
+			for (int j = 0; j < list.length; j++) {
+				SootClass sc = list[j].getDeclaringClass();
+				out.println("&_jc_" + C.name(sc)
+				    + "$method_info$" + C.name(list[j]) + ",");
+			}
+			out.println("_JC_NULL");
+			out.undent();
+			out.println("};");
+		}
+		out.println();
+
+		// Output the interface hash table itself
+		outputCommentLine("Interface lookup hash table");
+		out.println("static _jc_method **"
+		    + prefix + "$imethod_hash_table[_JC_IMETHOD_HASHSIZE] = {");
+		out.indent();
+		int count = 0;
+		for (int i = 0; i < IMETHOD_HASHSIZE; i++) {
+			if (iMethodBuckets[i] == null)
+				continue;
+			out.print("[" + i + "]=\t"
+			    + prefix + "$imethod_hash_bucket_" + i);
+			if (++count < numNonemptyIMethodBuckets)
+				out.print(',');
+			out.println();
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputInterfaceQuickTable() {
+
+		outputCommentLine("Interface \"quick\" lookup hash table");
+		out.println("static const void *" + prefix
+		    + "$imethod_quick_table[_JC_IMETHOD_HASHSIZE] = {");
+		out.indent();
+		int count = 0;
+		for (int i = 0; i < IMETHOD_HASHSIZE; i++) {
+			if (iMethodBuckets[i] == null
+			    || iMethodBuckets[i].size() != 1)
+				continue;
+			SootMethod m = (SootMethod)
+			    iMethodBuckets[i].iterator().next();
+			SootClass sc = m.getDeclaringClass();
+			out.print("[" + i + "]=\t&_jc_"
+			    + C.name(sc) + "$method$" + C.name(m));
+			if (++count < numSingletonIMethodBuckets)
+				out.print(',');
+			out.println();
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputVtable() {
+
+		// Sanity check
+		if (c.isInterface())
+			throw new RuntimeException("assertion failure");
+
+		// Compute virtual method table (signature -> class mapping)
+		HashMap virt = new HashMap();
+		for (int i = superclasses.size() - 1; i >= 0; i--) {
+			SootClass sc = (SootClass)superclasses.get(i);
+			for (Iterator j = sc.getMethods().iterator();
+			    j.hasNext(); ) {
+				SootMethod m = (SootMethod)j.next();
+				if (Util.isVirtual(m))
+					virt.put(m.getSubSignature(), sc);
+			}
+		}
+
+		// Output virtual method dispatch table
+		for (int i = superclasses.size() - 1; i >= 0; i--) {
+			SootClass sc = (SootClass)superclasses.get(i);
+			out.println("." + C.name(sc) + "= {");
+			SootMethod[] list = (SootMethod[])sc.getMethods()
+			    .toArray(new SootMethod[sc.getMethods().size()]);
+			Arrays.sort(list, Util.methodComparator);
+			for (int j = 0; j < list.length; j++) {
+				SootMethod m = list[j];
+				if (!Util.isVirtual(m))
+					continue;
+				out.print("    ." + C.name(m) + "=");
+				SootClass mc = (SootClass)virt.get(
+				    m.getSubSignature());
+				if (!sc.equals(mc)) {
+					spaceFillTo(16
+					    + C.name(m).length() + 2, 64);
+					out.print("// overridden");
+				}
+				out.println();
+				out.indent();
+				out.println("&_jc_" + C.name(mc)
+				    + "$method$" + C.name(m) + ",");
+				out.undent();
+			}
+			out.println("},");
+		}
+	}
+
+	public void outputInstanceOfHashTable() {
+
+		// Sanity check
+		out.println("#if _JC_INSTANCEOF_HASHSIZE != "
+		    + INSTANCEOF_HASHSIZE);
+		out.println("#error \"_JC_INSTANCEOF_HASHSIZE has the wrong"
+		    + " value (should be " + INSTANCEOF_HASHSIZE + ")\"");
+		out.println("#endif");
+		out.println();
+
+		// Create set of classes of which we are an instance
+		Set set = Util.getAllSupertypes(c);
+
+		// Generate hash table
+		HashSet[] buckets = new HashSet[INSTANCEOF_HASHSIZE];
+		for (Iterator i = set.iterator(); i.hasNext(); ) {
+			SootClass sc = (SootClass)i.next();
+			int bucket = Util.instanceofHash(sc);
+			if (buckets[bucket] == null)
+				buckets[bucket] = new HashSet();
+			buckets[bucket].add(sc);
+		}
+
+		// Output hash table buckets
+		outputCommentLine("Instanceof hash table buckets");
+		int numNonemptyBuckets = 0;
+		for (int i = 0; i < INSTANCEOF_HASHSIZE; i++) {
+			if (buckets[i] == null)
+				continue;
+			numNonemptyBuckets++;
+			out.println("static _jc_type *const "
+			    + prefix + "$instanceof_hash_bucket_"
+			    + i + "[] = {");
+			out.indent();
+			SootClass[] list = (SootClass[])buckets[i]
+			    .toArray(new SootClass[buckets[i].size()]);
+			Arrays.sort(list, Util.classComparator);
+			for (int j = 0; j < list.length; j++) {
+				out.println("&_jc_"
+				    + C.name(list[j]) + "$type" + ",");
+			}
+			out.println("_JC_NULL");
+			out.undent();
+			out.println("};");
+		}
+		out.println();
+
+		// Output the hash table itself
+		outputCommentLine("Instanceof hash table");
+		out.println("static _jc_type *const *const " + prefix
+		    + "$instanceof_hash_table[_JC_INSTANCEOF_HASHSIZE] = {");
+		out.indent();
+		int count = 0;
+		for (int i = 0; i < INSTANCEOF_HASHSIZE; i++) {
+			if (buckets[i] == null)
+				continue;
+			out.print("[" + i + "]=\t"
+			    + prefix + "$instanceof_hash_bucket_" + i);
+			if (++count < numNonemptyBuckets)
+				out.print(',');
+			out.println();
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputInnerClases() {
+		if (innerClasses.length == 0)
+			return;
+		outputCommentLine("Inner class list");
+		out.println("static _jc_inner_class "
+		    + prefix + "$inner_classes[] = {");
+		out.indent();
+		for (int i = 0; i < innerClasses.length; i++) {
+			InnerClass inner = innerClasses[i];
+			out.println("{ &_jc_" + C.name(inner.inner) + "$type, "
+			    +  C.accessDefs(inner.flags) + " },");
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputDepedencyList() {
+		outputCommentLine("Class dependency info");
+		out.println("static _jc_class_depend "
+		    + prefix + "$class_depends[] = {");
+		out.indent();
+		SootClass[] list = (SootClass[])fullDepends.toArray(
+		    new SootClass[fullDepends.size()]);
+		Arrays.sort(list, Util.classComparator);
+		for (int i = 0; i < list.length; i++) {
+			SootClass sc = list[i];
+			if (sc.equals(c))	// don't depend on self
+				continue;
+			out.println("{ "
+			    + C.string(sc.getName().replace('.', '/'))
+			    + ",\t_JC_JLONG(0x"
+			    + Long.toHexString(Util.classHash(sc)) + ") },");
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputClassInfo() {
+		outputCommentLine("Class info");
+
+		// Output a vtype structure
+		out.println(prefix + "$vtype " + prefix + "$type = {");
+
+		// Output type sub-structure
+		out.println("    .type= {");
+		out.indent();
+
+		// Output initial info
+		out.println(".name=\t\t\t"
+		    + C.string(c.getName().replace('.', '/')) + ",");
+		out.println(".superclass=\t\t"
+		    + (c.hasSuperclass() ?
+		      ("&_jc_" + C.name(c.getSuperclass()) + "$type") :
+		      "_JC_NULL")
+		    + ",");
+		out.println(".access_flags=\t\t" + C.accessDefs(c) + ",");
+		out.println(".flags=\t\t\t_JC_TYPE_REFERENCE,");
+
+		// Output interface info
+		if (c.getInterfaceCount() > 0) {
+			out.println(".num_interfaces=sizeof("
+			    + prefix + "$interfaces) / sizeof(*"
+			    + prefix + "$interfaces),");
+			out.println(".interfaces=\t\t"
+			    + prefix + "$interfaces,");
+		}
+		out.print(".imethod_hash_table=\t");
+		if (numNonemptyIMethodBuckets > 0) {
+			out.println(prefix + "$imethod_hash_table,");
+		} else
+			out.println("_jc_empty_imethod_table,");
+		out.print(".imethod_quick_table=\t");
+		if (numSingletonIMethodBuckets > 0)
+			out.println(prefix + "$imethod_quick_table,");
+		else
+			out.println("_jc_empty_quick_table,");
+
+		// Count total number of declared virtual methods
+		int totalVirtualMethods = 0;
+		for (Iterator i = superclasses.iterator(); i.hasNext(); ) {
+			SootClass sc = (SootClass)i.next();
+			for (Iterator j = sc.getMethods().iterator();
+			    j.hasNext(); ) {
+				SootMethod m = (SootMethod)j.next();
+				if (Util.isVirtual(m))
+				    	totalVirtualMethods++;
+			}
+		}
+
+		// Begin non-array info
+		out.println(".u= {");
+		out.println("    .nonarray= {");
+		out.indent();
+		out.println(".block_size_index=\t_JC_LIBJC_VERSION,");
+		out.println(".num_vmethods=\t\t" + totalVirtualMethods + ",");
+		out.println(".hash=\t\t\t" + "_JC_JLONG(0x"
+		    + Long.toHexString(Util.classHash(c)) + "),");
+		out.println(".source_file=\t\t" + C.string(sourceFile) + ",");
+
+		// Output instance size and offset
+		if (!c.isInterface()) {
+			out.println(".instance_size=\t\tsizeof("
+			    + prefix + "$refs) + sizeof("
+			    + prefix + "$object),");
+		}
+
+		out.println(".num_virtual_refs=\t" + numVirtualRefFields + ",");
+
+		// Output fields and methods
+		outputMemberList(staticFields.length + virtualFields.length,
+		    "fields");
+		outputMemberList(staticMethods.length + constructors.length
+		    + virtualMethods.length, "methods");
+
+		// Output instanceof hash table
+		out.println(".instanceof_hash_table=\t"
+		    + prefix + "$instanceof_hash_table,");
+
+		// Output class fields
+		if (staticFields.length > 0) {
+			out.println(".class_fields=\t\t"
+			    + "&" + prefix + "$class_fields,");
+		}
+
+		// Output inner class info
+		if (innerClasses.length > 0) {
+			out.println(".num_inner_classes=\t"
+			    + innerClasses.length + ",");
+			out.println(".inner_classes=\t\t"
+			    + prefix + "$inner_classes,");
+		}
+		if (outerClass != null) {
+			out.println(".outer_class=\t\t"
+			    + "&_jc_" + C.name(outerClass) + "$type,");
+		}
+
+		// Output class dependency info
+		out.println(".num_class_depends=\t\tsizeof("
+		  + prefix + "$class_depends) / sizeof(*"
+		  + prefix + "$class_depends),");
+		out.println(".class_depends=\t\t" + prefix + "$class_depends,");
+
+		// End non-array info
+		out.undent();
+		out.println("    }");
+		out.println("}");
+
+		// End _jc_type sub-structure
+		out.undent();
+		out.println("    }" + (!c.isInterface() ? "," : ""));
+
+		// Output vtable for non-interface classes
+		if (!c.isInterface()) {
+			out.println("    .vtable= {");
+			out.indent();
+			outputVtable();
+			out.undent();
+			out.println("    }");
+		}
+
+		// End vtype
+		out.println("};");
+		out.println();
+	}
+
+	private void outputMemberList(int length, String label) {
+		if (length == 0)
+			return;
+		out.println(".num_" + label + "=\t\tsizeof(" + prefix + "$"
+		    + label + ") / sizeof(*" + prefix + "$" + label + "),");
+		out.println("." + label + "=\t\t" + prefix + "$" + label + ",");
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CMethod.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CMethod.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CMethod.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CMethod.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,829 @@
+
+//
+// Copyright 2005 The Apache Software Foundation or its licensors,
+// as applicable.
+// 
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+// $Id: CMethod.java,v 1.21 2005/05/14 21:58:24 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import java.io.*;
+import java.util.*;
+import org.dellroad.jc.cgen.analysis.ActiveUseTagger;
+import org.dellroad.jc.cgen.analysis.FollowsAnalysis;
+import org.dellroad.jc.cgen.escape.StackAllocTag;
+import soot.*;
+import soot.baf.*;
+import soot.jimple.*;
+import soot.jimple.internal.*;
+import soot.jimple.toolkits.annotation.tags.*;
+import soot.tagkit.*;
+import soot.toolkits.graph.CompleteUnitGraph;
+
+/**
+ * Implements JC's C code generation algorithm for implementing Java methods.
+ */
+public class CMethod {
+
+	private static final ThreadLocal CURRENT_METHOD = new ThreadLocal();
+
+	private static final boolean DEBUG = false;
+
+	final SootMethod m;
+	final CFile cfile;
+	final CodeWriter out;
+	StmtBody body;
+	final MethodOptimizer optimizer;
+	final boolean includeLineNumbers;
+	int lineNumberTableLength;
+	CompleteUnitGraph graph;
+	PatchingChain bodyChain;
+	Map infoMap;			// Stmt -> StmtInfo
+	List traps;			// Trap's
+
+	public CMethod(CFile cfile, SootMethod m, MethodOptimizer optimizer,
+	    boolean includeLineNumbers, Set deps) {
+		this.cfile = cfile;
+		this.out = cfile.out;
+		this.m = m;
+		this.optimizer = optimizer;
+		this.includeLineNumbers = includeLineNumbers;
+		processBody(deps);
+	}
+
+	// Analysis information about a Stmt
+	static class StmtInfo {
+		char javaLineNumber = 0;		// java source line #
+		boolean branchTarget = false;		// target of branch/trap
+		boolean trapBoundary = false;		// trap begin or end
+		boolean backwardTrapTarget = false;	// back-branching trap
+		int lineNumberIndex = -1;		// line # table index
+		short labelIndex = -1;			// goto label index
+		short region = 0;			// trap region
+		boolean needsRegionUpdate = false;	// update new region
+	}
+
+	// Provides access to the current method being output
+	public static CMethod current() {
+		return (CMethod)CURRENT_METHOD.get();
+	}
+
+	// Get the StmtInfo corresponding to 'unit'. Create one if needed.
+	StmtInfo getInfo(Unit unit) {
+		StmtInfo info;
+		if ((info = (StmtInfo)infoMap.get(unit)) == null) {
+			info = new StmtInfo();
+			infoMap.put(unit, info);
+		}
+		return info;
+	}
+
+	// Primp, tweak, and optimize the method body
+	private void processBody(Set deps) {
+
+		// Skip if we're not going to generate a normal body
+		if (!m.isConcrete())
+			return;
+
+		// Wrap synchronized methods with monitorenter/exit statements
+		if (m.isSynchronized())
+			wrapSynchronized(m.retrieveActiveBody());
+
+		// Debug
+		if (DEBUG)
+			dumpBody(m, "BEFORE OPTIMIZATION");
+
+		// Perform useful optimizations on method body
+		graph = optimizer.optimize(m, deps);
+
+		// Debug
+		if (DEBUG)
+			dumpBody(m, "AFTER OPTIMIZATION");
+
+		// Get body and Unit chain
+		body = (JimpleBody)graph.getBody();
+		bodyChain = body.getUnits();
+
+		// Copy tags from statements to value boxes
+		StmtTagCopierSwitch tagCopier = new StmtTagCopierSwitch();
+		for (Iterator i = bodyChain.iterator(); i.hasNext(); ) {
+			Stmt stmt = (Stmt)i.next();
+			stmt.apply(tagCopier);
+		}
+
+		// Elide leading '$' from locals' names
+		for (Iterator i = body.getLocals().iterator(); i.hasNext(); ) {
+			Local local = (Local)i.next();
+			String name = local.getName();
+			if (name.charAt(0) == '$')
+				local.setName(name.substring(1));
+		}
+	}
+
+	// Analyze the body to derive various bits of information we need.
+	// This method is not allowed to change the method body
+	private void analyzeBody() {
+
+		// Skip if we're not going to generate a normal body
+		if (!m.isConcrete())
+			return;
+
+		// Initialize Stmt info map
+		infoMap = new HashMap();
+
+		// Mark trap targets that represent possible backward branches
+		traps = new ArrayList(body.getTraps());
+		for (int i = 0; i < traps.size(); i++) {
+			Trap trap = (Trap)traps.get(i);
+			Unit handler = trap.getHandlerUnit();
+			if (bodyChain.follows(trap.getEndUnit(), handler))
+				getInfo(handler).backwardTrapTarget = true;
+		}
+
+		// Mark statements that change the Java source line number
+		if (includeLineNumbers) {
+			int lastLineNumber = -1;
+			for (Iterator i = bodyChain.iterator(); i.hasNext(); ) {
+				Unit unit = (Unit)i.next();
+				LineNumberTag tag = (LineNumberTag)unit.getTag(
+				    "LineNumberTag");
+				if (tag == null)
+					continue;
+				int lineNumber = tag.getLineNumber();
+				if (lineNumber == lastLineNumber)
+					continue;
+				getInfo(unit).javaLineNumber = (char)lineNumber;
+				lastLineNumber = lineNumber;
+			}
+		}
+
+		// Mark branch targets as branch targets needing labels
+		for (Iterator i = bodyChain.iterator(); i.hasNext(); ) {
+			Unit unit = (Unit)i.next();
+			for (Iterator j = unit.getUnitBoxes().iterator();
+			    j.hasNext(); ) {
+				UnitBox ub = (UnitBox)j.next();
+				getInfo(ub.getUnit()).branchTarget = true;
+			}
+		}
+
+		// Mark trap handlers as branch targets and region updates
+		for (Iterator i = traps.iterator(); i.hasNext(); ) {
+			Trap trap = (Trap)i.next();
+			StmtInfo info = getInfo(trap.getHandlerUnit());
+			info.branchTarget = true;
+			info.needsRegionUpdate = true;
+		}
+
+		// Mark trap range boundaries
+		for (Iterator i = traps.iterator(); i.hasNext(); ) {
+			Trap trap = (Trap)i.next();
+			getInfo(trap.getBeginUnit()).trapBoundary = true;
+			getInfo(trap.getEndUnit()).trapBoundary = true;
+		}
+
+		// Assign trap regions to units
+		short region = 0;
+		for (Iterator i = bodyChain.iterator(); i.hasNext(); ) {
+			StmtInfo info = getInfo((Unit)i.next());
+			if (info.trapBoundary)
+				region++;
+			info.region = region;
+		}
+
+		// Annotate all Units into which control can flow
+		// such that a new trap region is entered.
+		boolean first = true;
+		for (Iterator i = bodyChain.iterator(); i.hasNext(); ) {
+			Unit unit = (Unit)i.next();
+
+			// Get this Unit's region
+			StmtInfo info = getInfo(unit);
+			region = info.region;
+
+			// Special case first unit
+			if (first) {
+				if (region != 0)
+					getInfo(unit).needsRegionUpdate = true;
+				first = false;
+			}
+
+			// Annotate any subsequent statements in other regions
+			if (unit.fallsThrough()) {
+				info = getInfo((Unit)bodyChain.getSuccOf(unit));
+				if (info.region != region)
+					info.needsRegionUpdate = true;
+			}
+			for (Iterator j = unit.getUnitBoxes().iterator();
+			    j.hasNext(); ) {
+				info = getInfo(((UnitBox)j.next()).getUnit());
+				if (info.region != region)
+					info.needsRegionUpdate = true;
+			}
+		}
+
+		// Scan StmtInfo's and mark for line numbers and branch labels
+		StmtInfo previous = new StmtInfo();
+		lineNumberTableLength = 0;
+		short nextLabelIndex = 0;
+		for (Iterator i = bodyChain.iterator(); i.hasNext(); ) {
+			Unit unit = (Unit)i.next();
+			StmtInfo info = getInfo(unit);
+
+			// Inherit Java line number from previous unit
+			if (info.javaLineNumber == 0)
+				info.javaLineNumber = previous.javaLineNumber;
+
+			// Line number table entry if Java line number changes
+			if (info.javaLineNumber != previous.javaLineNumber)
+			    	info.lineNumberIndex = lineNumberTableLength++;
+
+			// We need a label if any branch or trap targets us
+			if (info.branchTarget)
+				info.labelIndex = nextLabelIndex++;
+
+			// Update for next go round
+			previous = info;
+		}
+
+		// Tag static method and field refs for active use
+		new ActiveUseTagger(graph);
+	}
+
+	/**
+	 * Make a synchronized method look as if it was contained inside
+	 * a big synchronized block. This relieves the VM itself from having
+	 * to explicitly do the synchronization operations. Note that this
+	 * is only done for non-native methods. The VM is still responsible
+	 * for handling synchronization for native methods.
+	 */
+	public static void wrapSynchronized(Body body) {
+
+		// Check for applicability
+		SootMethod method = body.getMethod();
+		if (body.getUnits().size() == 0 || !method.isSynchronized())
+			return;
+		SootClass c = method.getDeclaringClass();
+
+		// Remember original first statment
+		PatchingChain units = body.getUnits();
+		Unit firstStmt = (Unit)units.getFirst();
+
+		// Lock monitor at the start of the method
+		Local thisRef = null;
+		StringConstant classConstant = null;
+		if (!method.isStatic()) {
+			thisRef = Jimple.v().newLocal("thisRef", RefType.v(c));
+			body.getLocals().addLast(thisRef);
+			units.addFirst(Jimple.v().newEnterMonitorStmt(
+			    (Value)thisRef));
+			units.addFirst(Jimple.v().newIdentityStmt(thisRef,
+			    Jimple.v().newThisRef(RefType.v(c))));
+		} else {
+			classConstant = ClassConstant.v(
+			    method.getDeclaringClass().getName());
+			units.addFirst(Jimple.v().newEnterMonitorStmt(
+			    classConstant));
+		}
+
+		// Unlock monitor before each return statement. We don't
+		// need to unlock before throw statements because the trap
+		// handler we add below will automatically handle those cases.
+		HashSet returns = new HashSet();
+		for (Iterator i = units.iterator(); i.hasNext(); ) {
+			Stmt stmt = (Stmt)i.next();
+			if (stmt instanceof ReturnStmt
+			    || stmt instanceof ReturnVoidStmt)
+				returns.add(stmt);
+		}
+		for (Iterator i = returns.iterator(); i.hasNext(); ) {
+			units.insertBefore(Jimple.v().newExitMonitorStmt(
+			    method.isStatic() ?
+			      (Value)classConstant : (Value)thisRef),
+			    i.next());
+		}
+
+		// Add a trap and handler to unlock monitor after any exception
+		SootClass jlt = Scene.v().getSootClass("java.lang.Throwable");
+		Local e = Jimple.v().newLocal("exception", RefType.v(jlt));
+		body.getLocals().addLast(e);
+		units.addLast(Jimple.v().newIdentityStmt(e,
+		    Jimple.v().newCaughtExceptionRef()));
+		Unit trapHandler = (Unit)body.getUnits().getLast();
+		units.addLast(Jimple.v().newExitMonitorStmt(
+		    method.isStatic() ? (Value)classConstant : (Value)thisRef));
+		units.addLast(Jimple.v().newThrowStmt(e));
+		body.getTraps().addLast(
+		    Jimple.v().newTrap(jlt, firstStmt,
+		    trapHandler, trapHandler));
+	}
+
+	public void outputMethodInfo() {
+
+		// Analyze method
+		if (infoMap == null)
+			analyzeBody();
+
+		// Determine what to do
+		boolean generateBody = !cfile.c.isInterface()
+		    || Util.isClassInit(m);
+		boolean doLineNumTable = generateBody
+		    && !m.isAbstract()
+		    && includeLineNumbers
+		    && lineNumberTableLength > 0;
+		boolean doTrapTable = m.isConcrete() && !traps.isEmpty();
+
+		// Declare line number and trap table
+		if (doLineNumTable) {
+			out.println("static _jc_linenum "
+			    + cfile.prefix + "$linenum_table$"
+			    + C.name(m) + "[];");
+			out.println();
+		}
+
+		// Output exception trap table
+		if (doTrapTable) {
+			out.println("static _jc_trap_info " + cfile.prefix
+			    + "$trap_table$" + C.name(m) + "[] = {");
+			out.indent();
+			SootClass throwable = Scene.v()
+			    .getSootClass("java.lang.Throwable");
+			for (int i = 0; i < traps.size(); i++) {
+				Trap trap = (Trap)traps.get(i);
+				SootClass type = trap.getException();
+				out.println("_JC_TRAP("
+				    + (type.equals(throwable) ? "_JC_NULL" :
+					"&_jc_" + C.name(type) + "$type")
+				    + ", " + getInfo(trap.getBeginUnit()).region
+				    + ", " + getInfo(trap.getEndUnit()).region
+				    + "),");
+			}
+			out.undent();
+			out.println("};");
+			out.println();
+		}
+
+		// Output parameter 'ptypes'
+		out.println("static const unsigned char " + cfile.prefix
+		    + "$param_ptypes$" + C.name(m) + "[] = { ");
+		for (int i = 0; i < m.getParameterCount(); i++) {
+			out.print(Util._JC_TYPE(m.getParameterType(i)));
+			out.print(", ");
+		}
+		out.println(Util._JC_TYPE(m.getReturnType()) + " };");
+		out.println();
+
+		// Output exception list
+		List elist = m.getExceptions();
+		if (elist.size() > 0) {
+			out.println("static _jc_type *const " + cfile.prefix
+			    + "$exceptions$" + C.name(m) + "[] = {");
+			out.indent();
+			for (Iterator i = elist.iterator(); i.hasNext(); ) {
+				SootClass ec = (SootClass)i.next();
+				out.print("&_jc_" + C.name(ec) + "$type");
+				if (i.hasNext())
+					out.print(",");
+				out.println();
+			}
+			out.undent();
+			out.println("};");
+			out.println();
+		}
+
+		// Output parameter types
+		if (m.getParameterCount() > 0) {
+			out.println("static _jc_type *const " + cfile.prefix
+			    + "$param_types$" + C.name(m) + "[] = {");
+			out.indent();
+			for (int i = 0; i < m.getParameterCount(); i++) {
+				out.print("&"
+				    + C.jc_type(m.getParameterType(i)));
+				if (i < m.getParameterCount() - 1)
+					out.print(",");
+				out.println();
+			}
+			out.undent();
+			out.println("};");
+			out.println();
+		}
+
+		// Output initial method info stuff
+		out.println("_jc_method " + cfile.prefix
+		    + "$method_info$" + C.name(m) + " = {");
+		out.indent();
+		out.println(".name=\t\t\t" + C.string(m.getName()) + ",");
+		out.println(".signature=\t\t"
+		    + C.string(Util.signature(m)) + ",");
+		out.println(".class=\t\t\t&" + cfile.prefix + "$type,");
+		if (m.getParameterCount() > 0) {
+			out.println(".param_types=\t\t&"
+			    + cfile.prefix + "$param_types$" + C.name(m) + ",");
+		}
+		out.println(".return_type=\t\t&"
+		    + C.jc_type(m.getReturnType()) + ",");
+		out.println(".param_ptypes=\t\t&"
+		    + cfile.prefix + "$param_ptypes$" + C.name(m) + ",");
+
+		out.println(".signature_hash=\t_JC_JLONG(0x"
+		    + Long.toHexString(Util.sigHash(m)) + "),");
+		out.println(".access_flags=\t\t" + C.accessDefs(m) + ",");
+
+		// Output more method info stuff
+		if (generateBody) {
+			out.println(".function=\t\t&"
+			    + cfile.prefix + "$method$" + C.name(m) + ",");
+		}
+		if (!cfile.c.isInterface() && Util.isVirtual(m)) {
+			out.println(".vtable_index=\t\t_JC_OFFSETOF(struct "
+			    + cfile.prefix + "$vtable, "
+			    + C.name(cfile.c) + "." + C.name(m) + ")"
+			    + " / sizeof(void *),");
+		}
+		out.println(".num_parameters=\t"
+		    + m.getParameterCount() + ",");
+		if (m.getExceptions().size() > 0) {
+			out.println(".num_exceptions=\t"
+			    + m.getExceptions().size() + ",");
+			out.println(".exceptions=\t\t&" + cfile.prefix
+			    + "$exceptions$" + C.name(m) + ",");
+		}
+		if (doTrapTable || doLineNumTable) {
+			out.println(".u= { .exec= {");
+			if (doTrapTable) {
+				out.println("  .trap_table_len=\t"
+				    + traps.size() + ",");
+				out.println("  .trap_table=\t\t"
+				    + cfile.prefix + "$trap_table$" + C.name(m)
+				    + ",");
+			}
+			if (doLineNumTable) {
+				out.println("  .u= {");
+				out.println("    .linenum= {");
+				out.println("      .len=\t"
+				    + lineNumberTableLength + ",");
+				out.println("      .table=\t"
+				    + cfile.prefix + "$linenum_table$"
+				    + C.name(m));
+				out.println("    },");
+				out.println("  },");
+			}
+			out.println("} },");
+		}
+
+		// Done with method info
+		out.undent();
+		out.println("};");
+		out.println();
+
+		// Output line number table
+		if (doLineNumTable) {
+			out.println("_JC_LINENUM_TABLE("
+			    + C.name(cfile.c) + ", " + C.name(m) + ");");
+			out.println();
+		}
+	}
+
+	public void outputMethodFunction() {
+
+		// No body for interface virtual methods
+		if (cfile.c.isInterface() && !Util.isClassInit(m))
+			return;
+
+		// Analyze method
+		if (infoMap == null)
+			analyzeBody();
+
+		// Set current method
+		CURRENT_METHOD.set(this);
+
+		// Output initial stuff for body
+		out.print(C.type(m));
+		if (Util.isReference(m))
+			out.print(" *");
+		out.println(" _JC_JCNI_ATTR");
+		out.println(cfile.prefix + "$method$"
+		    + C.name(m) + C.paramsDecl(m, true));
+
+		// Output normal, abstract, or native method body
+		out.println('{');
+		out.indent();
+		if (m.isNative())
+			outputNativeMethodBody();
+		else if (m.isAbstract())
+			outputAbstractMethodBody();
+		else
+			outputNormalMethodBody();
+		out.undent();
+		out.println('}');
+		out.println();
+
+		// Unset current method
+		CURRENT_METHOD.set(null);
+	}
+
+	/**
+	 * Reset state. This frees a bunch of memory.
+	 */
+	public void reset() {
+		m.releaseActiveBody();
+		body = null;
+		lineNumberTableLength = 0;
+		graph = null;
+		bodyChain = null;
+		infoMap = null;
+		traps = null;
+	}
+
+	private void outputNormalMethodBody() {
+
+		// Get sorted locals array
+		Local[] locary = (Local[])body.getLocals().toArray(
+		    new Local[body.getLocals().size()]);
+		Arrays.sort(locary, Util.localComparator);
+
+		// Determine which locals need to be volatile
+		Set volatileLocals = determineVolatileLocals();
+
+		// Output stack allocated object memory
+		for (Iterator i = bodyChain.iterator(); i.hasNext(); ) {
+			Stmt stmt = (Stmt)i.next();
+			if (!(stmt instanceof AssignStmt))
+				continue;
+			AssignStmt assign = (AssignStmt)stmt;
+			StackAllocTag tag = (StackAllocTag)assign
+			    .getRightOpBox().getTag("StackAllocTag");
+			if (tag == null)
+				continue;
+			assign.getRightOp().apply(stackMemorySwitch);
+			out.println(" mem" + tag.getId() + ";");
+		}
+
+		// Do locals
+		for (int i = 0; i < locary.length; i++) {
+			Local local = locary[i];
+			out.print(C.type(local, true) + " ");
+			if (Util.isReference(local.getType()))
+				out.print("*");
+			if (volatileLocals.contains(local))
+				out.print("volatile ");
+			out.println(local.getName() + ";");
+		}
+
+		// Do exception catcher, if any
+		if (!traps.isEmpty())
+			out.println("_jc_catch_frame\tcatch;");
+
+		// Blank line
+		if (locary.length > 0 || !traps.isEmpty())
+			out.println();
+
+		// Determine if we need a stack overflow check
+		for (Iterator i = bodyChain.iterator(); i.hasNext(); ) {
+			Stmt stmt = (Stmt)i.next();
+			if (!stmt.containsInvokeExpr())
+				continue;
+			if (NullCheckStmt.isNullCheck(stmt))
+				continue;
+			if (stmt.getInvokeExpr().getMethod().isNative())
+				continue;
+			out.println("// Check for stack overflow");
+			out.println("_JC_STACK_OVERFLOW_CHECK(env);");
+			out.println();
+			break;
+		}
+
+		// Output trap targets, if any
+		if (!traps.isEmpty()) {
+			out.println("// Define exception targets");
+			out.print("_JC_DEFINE_TRAPS(env, catch, &"
+			    + cfile.prefix + "$method_info$" + C.name(m));
+			for (int i = 0; i < traps.size(); i++) {
+				Trap trap = (Trap)traps.get(i);
+				out.print(", &&label"
+				    + getInfo(trap.getHandlerUnit())
+				      .labelIndex);
+			}
+			out.println(");");
+			out.println();
+		}
+
+		// Validate body just for good measure
+		if (DEBUG)
+			body.validate();
+
+		// Iterate through body units and convert to C
+		StmtInfo previous = new StmtInfo();
+		CStmtSwitch ss = new CStmtSwitch(this);
+		for (Iterator i = bodyChain.iterator(); i.hasNext(); ) {
+			Stmt stmt = (Stmt)i.next();
+
+			// Get info about this statement
+			StmtInfo info = (StmtInfo)infoMap.get(stmt);
+
+			// Output label if this statement has one
+			if (info.labelIndex != -1) {
+				int indent = out.getIndent();
+				out.setIndent(0);
+				out.println();
+				out.println("label" + info.labelIndex + ":");
+				out.setIndent(indent);
+			}
+
+			// Output region update if needed
+			if (info.needsRegionUpdate) {
+				out.println("_JC_TRAP_REGION(catch, "
+				    + info.region + ");");
+			}
+
+			// Output line number table entry if required
+			if (info.lineNumberIndex != -1) {
+				out.println("_JC_LINE_NUMBER("
+				    + (int)info.javaLineNumber + ");\t\t\t\t// "
+				    + info.lineNumberIndex);
+			}
+
+			// Output check for backward branch trap handlers
+			if (info.backwardTrapTarget)
+				out.println("_JC_PERIODIC_CHECK(env);");
+
+			// Output statement
+			stmt.apply(ss);
+
+			// Update for next go round
+			if (info != null)
+				previous = info;
+		}
+	}
+
+	private final AbstractJimpleValueSwitch stackMemorySwitch
+	    = new AbstractJimpleValueSwitch() {
+		public void caseNewExpr(NewExpr v) {
+			RefType t = (RefType)v.getBaseType();
+			SootClass sc = t.getSootClass();
+			out.println("struct {");
+			out.indent();
+			out.println("struct _jc_"
+			    + C.name(sc) + "$refs\trefs;");
+			out.println("struct _jc_"
+			    + C.name(sc) + "$object\tobj;");
+			out.undent();
+			out.print("}");
+		}
+		public void caseNewArrayExpr(NewArrayExpr v) {
+			doArray(v.getSize(), (ArrayType)v.getType());
+		}
+		public void caseNewMultiArrayExpr(NewMultiArrayExpr v) {
+			doArray(v.getSize(0), (ArrayType)v.getType());
+		}
+		public void doArray(Value length, ArrayType atype) {
+			int len = ((IntConstant)length).value;
+			Type etype = atype.getElementType();
+			out.println("struct {");
+			out.indent();
+			if (Util.isReference(etype)) {
+				out.println("_jc_word\t\telems[" + len + "];");
+				out.println("_jc_object_array\tarray;");
+			} else {
+				String tw = Util.typeWord(etype);
+				out.println("_jc_" + tw + "_array\tarray;");
+				out.println(C.type(etype)
+				    + "\telems[" + len + "];");
+			}
+			out.undent();
+			out.print("}");
+		}
+		public void defaultCase(Object obj) {
+			throw new RuntimeException("non-new value");
+		}
+	};
+
+	private Set determineVolatileLocals() {
+
+		// No traps?
+		if (traps.isEmpty())
+			return Collections.EMPTY_SET;
+
+		// Get units at the head of each trap
+		Set trapHeads = new HashSet();
+		for (Iterator i = traps.iterator(); i.hasNext(); )
+			trapHeads.add(((Trap)i.next()).getHandlerUnit());
+
+		// Compute follows function
+		FollowsAnalysis follows = new FollowsAnalysis(graph);
+
+		// Find locals that could be used after catching an exception
+		Set volatileLocals = new HashSet();
+		for (Iterator i = bodyChain.iterator(); i.hasNext(); ) {
+			Stmt stmt = (Stmt)i.next();
+			boolean afterException = false;
+			if (trapHeads.contains(stmt))
+				afterException = true;
+			else {
+				for (Iterator j = trapHeads.iterator();
+				    j.hasNext(); ) {
+					Stmt head = (Stmt)j.next();
+					if (follows.canFollow(head, stmt)) {
+						afterException = true;
+						break;
+					}
+				}
+			}
+			if (!afterException)
+				continue;
+			List uses = stmt.getUseBoxes();
+			for (Iterator j = uses.iterator(); j.hasNext(); ) {
+				ValueBox useBox = (ValueBox)j.next();
+				Value use = useBox.getValue();
+				if (use instanceof Local)
+					volatileLocals.add(use);
+			}
+		}
+
+		// Done
+		return volatileLocals;
+	}
+
+	private void outputNativeMethodBody() {
+		out.println("_jc_value retval;");
+		out.println();
+		//out.println("_JC_STACK_OVERFLOW_CHECK(env);");
+		out.print("_JC_INVOKE_NATIVE_METHOD(env, &" + cfile.prefix
+		    + "$method_info$" + C.name(m) + ", &retval");
+		if (!m.isStatic())
+			out.print(", this");
+		for (int i = 0; i < m.getParameterCount(); i++)
+			out.print(", param" + i);
+		out.println(");");
+		if (!(m.getReturnType() instanceof VoidType)) {
+			out.println("return retval."
+			    + Util.typeLetter(m.getReturnType()) + ";");
+		}
+	}
+
+	private void outputAbstractMethodBody() {
+		out.println("_JC_ABSTRACT_METHOD(env, &"
+		    + cfile.prefix + "$method_info$" + C.name(m) + ");");
+	}
+
+	// Debugging stuff..
+
+	static void dumpBody(SootMethod m, String label) {
+		System.out.println("------ " + label + ": "
+		    + m.getSubSignature() + " -------");
+		JimpleBody body = (JimpleBody)m.retrieveActiveBody();
+		Map stmtMap = computeStmtMap(body.getUnits());
+		for (Iterator i = body.getUnits().iterator(); i.hasNext(); ) {
+			Stmt stmt = (Stmt)i.next();
+			Integer num = (Integer)stmtMap.get(stmt);
+			Integer tnum;
+			try {
+				tnum = (Integer)stmtMap.get(
+				    ((UnitBox)stmt.getUnitBoxes().get(0))
+				    .getUnit());
+			} catch (IndexOutOfBoundsException e) {
+				tnum = null;
+			}
+			System.out.println(num + "\t" + stmt
+			    + (tnum != null ? " [" + tnum + "]" : ""));
+		}
+		if (!body.getTraps().isEmpty()) {
+			System.out.println("------ TRAPS -------");
+			for (Iterator i = body.getTraps().iterator();
+			    i.hasNext(); )
+				dumpTrap((Trap)i.next(), stmtMap);
+		}
+		System.out.println("------ END -------");
+	}
+
+	private static void dumpTrap(Trap trap, Map map) {
+		System.out.println("\tTrap: ["
+		    + map.get(trap.getBeginUnit()) + "] - ["
+		    + map.get(trap.getEndUnit()) + "] -> ["
+		    + map.get(trap.getHandlerUnit()) + "] "
+		    + trap.getException());
+	}
+
+	private static Map computeStmtMap(Collection units) {
+		HashMap map = new HashMap();
+		int count = 0;
+		for (Iterator i = units.iterator(); i.hasNext(); ) {
+			Stmt stmt = (Stmt)i.next();
+			map.put(stmt, new Integer(++count));
+		}
+		return map;
+	}
+}

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CStmtSwitch.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CStmtSwitch.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CStmtSwitch.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CStmtSwitch.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,310 @@
+
+//
+// Copyright 2005 The Apache Software Foundation or its licensors,
+// as applicable.
+// 
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+// $Id: CStmtSwitch.java,v 1.16 2005/03/20 17:16:08 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import java.io.*;
+import java.util.*;
+import org.dellroad.jc.cgen.analysis.ActiveUseTag;
+import soot.*;
+import soot.baf.*;
+import soot.jimple.*;
+import soot.jimple.toolkits.annotation.tags.*;
+
+/**
+ * Converts Jimple statements into C statements.
+ */
+public class CStmtSwitch extends AbstractStmtSwitch {
+	CMethod cm;
+	CodeWriter out;
+
+	public CStmtSwitch(CMethod cm) {
+		this.cm = cm;
+		this.out = cm.out;
+	}
+
+	public void caseBreakpointStmt(BreakpointStmt stmt) {
+		out.println("// Breakpoint: " + stmt);
+	}
+
+	public void caseInvokeStmt(InvokeStmt stmt) {
+/********
+		// Special case C.include() for included code
+		if (v instanceof StaticInvokeExpr) {
+			StaticInvokeExpr i = (StaticInvokeExpr)v;
+			SootMethod method = i.getMethod();
+			SootClass cls = method.getDeclaringClass();
+			Value arg;
+			if (cls.getName().equals("C")
+			    && method.getName().equals("include")
+			    && i.getArgCount() == 1
+			    && (arg = i.getArg(0)) instanceof StringConstant) {
+				out.println(((StringConstant)arg).value);
+				return;
+			}
+		}
+*********/
+		// Get invoke expression
+		ValueBox exprBox = stmt.getInvokeExprBox();
+
+		// Special case NullCheckStmt
+		if (NullCheckStmt.isNullCheck(stmt)) {
+			NullCheckTag tag = (NullCheckTag)
+			    exprBox.getTag("NullCheckTag");
+			if (tag != null && !tag.needCheck())
+				return;
+			out.println(new CExpr(CExpr.FUNCTION,
+			    "_JC_EXPLICIT_NULL_CHECK", "env",
+			    ((SpecialInvokeExpr)exprBox.getValue())
+			      .getBaseBox()) + ";");
+			return;
+		}
+
+		// Special case ActiveUseCheckStmt
+		if (ActiveUseCheckStmt.isActiveUseCheck(stmt)) {
+			ActiveUseTag tag = (ActiveUseTag)
+			    exprBox.getTag("ActiveUseTag");
+			if (tag != null && !tag.isCheckNeeded())
+				return;
+			out.println("_JC_ACTIVE_USE(env, " + C.name(
+			    ActiveUseCheckStmt.getSootClass(stmt)) + ");");
+			return;
+		}
+
+		// Just a normal invocation
+		out.println(C.value(exprBox) + ";");
+	}
+
+	public void caseAssignStmt(AssignStmt stmt) {
+
+		// Output array store check if needed
+		Value lhs = stmt.getLeftOp();
+		Type lht = lhs.getType();
+		if (lhs instanceof ArrayRef
+		    && Util.isReference(lht)
+		    && (Util.hasSubtypes(lht)
+		      || !stmt.getRightOp().getType().equals(lht))) {
+			out.println(new CExpr(CExpr.FUNCTION,
+			   "_JC_ARRAYSTORE_CHECK", "env",
+			   C.value(((ArrayRef)lhs).getBaseBox()),
+			   C.value(stmt.getRightOpBox())) + ";");
+		}
+
+		// Output assignment
+		out.println(C.value(stmt.getLeftOpBox())
+		    + " = " + C.value(stmt.getRightOpBox()) + ";");
+	}
+
+	public void caseIdentityStmt(IdentityStmt stmt) {
+		out.println(C.value(stmt.getLeftOpBox())
+		    + " = " + C.value(stmt.getRightOpBox()) + ";");
+	}
+
+	public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
+		out.println(new CExpr(CExpr.FUNCTION,
+		    "_JC_MONITOR_ENTER", "env", stmt.getOpBox()) + ";");
+	}
+
+	public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
+		out.println(new CExpr(CExpr.FUNCTION,
+		    "_JC_MONITOR_EXIT", "env", stmt.getOpBox()) + ";");
+	}
+
+	public void caseGotoStmt(GotoStmt stmt) {
+		branch(stmt, stmt.getTarget());
+	}
+
+	public void caseIfStmt(IfStmt stmt) {
+		Stmt target = stmt.getTarget();
+		out.print("if (" + C.value(stmt.getConditionBox()) + ")");
+		if (stmt.equals(target) || cm.bodyChain.follows(stmt, target)) {
+			out.println(" {");
+			out.indent();
+			backwardBranch(target);
+			out.undent();
+			out.println("}");
+		} else {
+			out.println();
+			out.indent();
+			forwardBranch(target);
+			out.undent();
+		}
+	}
+
+	private void branch(Unit from, Unit target) {
+		if (from.equals(target) || cm.bodyChain.follows(from, target))
+			backwardBranch(target);
+		else
+			forwardBranch(target);
+	}
+
+	private void backwardBranch(Unit target) {
+		out.println("_JC_PERIODIC_CHECK(env);");
+		out.println("goto label" + cm.getInfo(target).labelIndex + ";");
+	}
+
+	private void forwardBranch(Unit target) {
+		out.println("goto label" + cm.getInfo(target).labelIndex + ";");
+	}
+
+	// Represents one case in a tableswitch or lookupswitch
+	private static class Case implements Comparable {
+		final int value;
+		final Unit target;
+		Case(int value, Unit target) {
+			this.value = value;
+			this.target = target;
+		}
+		public int compareTo(Object o) {
+			Case that = (Case)o;
+			return (this.value < that.value ? -1 :
+			    this.value > that.value ? +1 : 0);
+		}
+	}
+
+	public void caseLookupSwitchStmt(LookupSwitchStmt stmt) {
+		int numCases = stmt.getTargetCount();
+		Case[] cases = new Case[numCases];
+		for (int i = 0; i < numCases; i++) {
+			cases[i] = new Case(stmt.getLookupValue(i),
+			    stmt.getTarget(i));
+		}
+		handleSwitch(stmt, stmt.getKeyBox(),
+		    cases, stmt.getDefaultTarget());
+	}
+
+	private void handleSwitch(Stmt stmt, ValueBox key,
+	    Case[] cases, Unit defaultTarget) {
+
+		// Output switch statement
+		out.println("switch (" + C.value(key) + ") {");
+
+		// Sort cases (should already be sorted)
+		Arrays.sort(cases);
+
+		// Compress out cases that just branch to the default target
+		int count = 0;
+		for (int i = 0; i < cases.length; i++) {
+			if (cases[i].target.equals(defaultTarget))
+				continue;
+			cases[count++] = cases[i];
+		}
+
+		// Output normal cases, compacting contiguous case ranges
+		int previousValue = 0;
+		int previousStartValue = 0;
+		Unit previousTarget = null;
+		boolean caseOpen = false;
+
+		for (int i = 0; i < count; i++) {
+			int value = cases[i].value;
+			Unit target = cases[i].target;
+			boolean closePrevious;
+
+			// Determine whether we should close previous range
+			if (caseOpen
+			    && (value != previousValue + 1
+			      || !target.equals(previousTarget))) {
+				if (previousValue != previousStartValue)
+					out.print(" ... " + previousValue);
+				out.println(":");
+				out.indent();
+				branch(stmt, previousTarget);
+				out.undent();
+				caseOpen = false;
+			}
+
+			// Can we continue an already open case?
+			if (caseOpen && i < count - 1) {
+				previousValue = value;
+				continue;
+			}
+
+			// Start a new case if necessary
+			if (!caseOpen) {
+				out.print("case " + value);
+				previousStartValue = value;
+				previousTarget = target;
+			}
+
+			// Is this the last value? If so we must stop
+			if (i == count - 1) {
+				if (caseOpen)
+					out.print(" ... " + value);
+				out.println(":");
+				out.indent();
+				branch(stmt, target);
+				out.undent();
+				break;
+			}
+
+			// Continue with open case
+			previousValue = value;
+			caseOpen = true;
+		}
+
+		// Output the default case
+		out.println("default:");
+		out.indent();
+		branch(stmt, defaultTarget);
+		out.undent();
+		out.println('}');
+	}
+
+	public void caseNopStmt(NopStmt stmt) {
+	}
+
+	public void caseRetStmt(RetStmt stmt) {
+		defaultCase(stmt);
+	}
+
+	public void caseReturnStmt(ReturnStmt stmt) {
+		if (!cm.traps.isEmpty())
+			out.println("_JC_CANCEL_TRAPS(env, catch);");
+		out.println("return " + C.value(stmt.getOpBox()) + ";");
+	}
+
+	public void caseReturnVoidStmt(ReturnVoidStmt stmt) {
+		if (!cm.traps.isEmpty())
+			out.println("_JC_CANCEL_TRAPS(env, catch);");
+		out.println("return;");
+	}
+
+	public void caseTableSwitchStmt(TableSwitchStmt stmt) {
+		int numCases = stmt.getHighIndex() - stmt.getLowIndex() + 1;
+		Case[] cases = new Case[numCases];
+		for (int i = 0; i < numCases; i++) {
+			cases[i] = new Case(stmt.getLowIndex() + i,
+			    stmt.getTarget(i));
+		}
+		handleSwitch(stmt, stmt.getKeyBox(),
+		    cases, stmt.getDefaultTarget());
+	}
+
+	public void caseThrowStmt(ThrowStmt stmt) {
+		out.println(new CExpr(CExpr.FUNCTION,
+		    "_JC_THROW", "env", C.value(stmt.getOpBox())) + ";");
+	}
+
+	public void defaultCase(Object o) {
+		throw new RuntimeException("unhandled case");
+	}
+}
+



Mime
View raw message