You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ge...@apache.org on 2005/10/05 04:20:10 UTC
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/...
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");
+ }
+}
+