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 [7/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/CValueSwitch.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CValueSwitch.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CValueSwitch.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CValueSwitch.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,544 @@
+
+//
+// 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: CValueSwitch.java,v 1.17 2005/05/02 03:47:48 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import soot.*;
+import soot.jimple.*;
+import soot.jimple.toolkits.annotation.tags.*;
+import soot.jimple.toolkits.pointer.CastCheckTag;
+import soot.tagkit.*;
+import java.util.*;
+import org.dellroad.jc.cgen.analysis.ActiveUseTag;
+import org.dellroad.jc.cgen.escape.StackAllocTag;
+
+/**
+ * Converts Jimple expressions into C expressions.
+ */
+public class CValueSwitch extends AbstractJimpleValueSwitch {
+
+	/**
+	 * The method in which this expression exists.
+	 */
+	final CMethod method;
+
+	/**
+	 * Any tags that were associated with the ValueBox.
+	 */
+	private final ValueBox valueBox;
+
+	/**
+	 * The result of the conversion.
+	 */
+	CExpr result;
+
+	public CValueSwitch(CMethod method, ValueBox valueBox) {
+		this.method = method;
+		this.valueBox = valueBox;
+	}
+
+	private boolean hasTag(String name) {
+		return valueBox != null && valueBox.hasTag(name);
+	}
+
+	private Tag getTag(String name) {
+		if (valueBox == null)
+			return null;
+		return valueBox.getTag(name);
+	}
+
+	public void caseArrayRef(ArrayRef v) {
+		ArrayCheckTag tag = (ArrayCheckTag)getTag("ArrayCheckTag");
+		int chklo = (tag == null || tag.isCheckLower()) ? 1 : 0;
+		int chkhi = (tag == null || tag.isCheckUpper()) ? 1 : 0;
+		Object[] params;
+		int pnum = 0;
+		if (Util.isReference(v.getType())) {
+			params = new Object[6];
+			params[pnum++] = "_JC_REF_ELEMENT";
+			params[pnum++] = "env";
+		} else {
+			params = new Object[7];
+			params[pnum++] = "_JC_PRIM_ELEMENT";
+			params[pnum++] = "env";
+			params[pnum++] = Util.typeWord(v.getType());
+		}
+		params[pnum++] = v.getBaseBox();
+		params[pnum++] = v.getIndexBox();
+		params[pnum++] = "" + chklo;
+		params[pnum++] = "" + chkhi;
+		result = new CExpr(CExpr.FUNCTION, params);
+	}
+
+	public void caseDoubleConstant(DoubleConstant v) {
+		long bits = Double.doubleToRawLongBits(v.value);
+		if (bits == 0) {
+			result = new CExpr("(jdouble)0.0");
+			return;
+		}
+		Object[] ops = new Object[9];
+		ops[0] = "_JC_DCONST";
+		for (int i = 0; i < 8; i++) {
+			ops[1 + i] = "0x" + Integer.toHexString(
+			    (int)(bits >> (8 * (7 - i))) & 0xff);
+		}
+		result = new CExpr(CExpr.FUNCTION, ops);
+	}
+
+	public void caseFloatConstant(FloatConstant v) {
+		int bits = Float.floatToRawIntBits(v.value);
+		if (bits == 0) {
+			result = new CExpr("(jfloat)0.0");
+			return;
+		}
+		Object[] ops = new Object[5];
+		ops[0] = "_JC_FCONST";
+		for (int i = 0; i < 4; i++) {
+			ops[1 + i] = "0x" + Integer.toHexString(
+			    (bits >> (8 * (3 - i))) & 0xff);
+		}
+		result = new CExpr(CExpr.FUNCTION, ops);
+	}
+
+	public void caseIntConstant(IntConstant v) {
+		result = new CExpr(Integer.toString(v.value));
+	}
+
+	public void caseLongConstant(LongConstant v) {
+		result = new CExpr(CExpr.FUNCTION,
+		    "_JC_JLONG", Long.toString(v.value));
+	}
+
+	public void caseNullConstant(NullConstant v) {
+		result = new CExpr("_JC_NULL");
+	}
+
+	public void caseStringConstant(StringConstant v) {
+		if (ClassConstant.isClassConstant(v)) {
+			result = new CExpr("&_jc_"
+			    + C.encode(ClassConstant.getClassName(v))
+			    + "$class_object");
+		} else {
+			result = new CExpr(CExpr.FUNCTION,
+			    "_JC_STRING", "env", C.string(v.value));
+		}
+	}
+
+	// Common code for simple binary ops
+	private void caseBinOpExpr(BinopExpr e, int type) {
+		result = new CExpr(type, e.getOp1Box(), e.getOp2Box());
+	}
+
+	public void caseAddExpr(AddExpr v) {
+		caseBinOpExpr(v, CExpr.ADD);
+	}
+
+	public void caseAndExpr(AndExpr v) {
+		caseBinOpExpr(v, CExpr.AND);
+	}
+
+	public void caseCmpExpr(CmpExpr v) {
+		result = new CExpr(CExpr.FUNCTION,
+		    "_JC_LCMP", v.getOp1Box(), v.getOp2Box());
+	}
+
+	public void caseCmpgExpr(CmpgExpr v) {
+		if (v.getOp1().getType() instanceof FloatType
+		    && v.getOp2().getType() instanceof FloatType) {
+			result = new CExpr(CExpr.FUNCTION,
+			    "_JC_FCMPG", v.getOp1Box(), v.getOp2Box());
+		} else {
+			result = new CExpr(CExpr.FUNCTION,
+			    "_JC_DCMPG", v.getOp1Box(), v.getOp2Box());
+		}
+	}
+
+	public void caseCmplExpr(CmplExpr v) {
+		if (v.getOp1().getType() instanceof FloatType
+		    && v.getOp2().getType() instanceof FloatType) {
+			result = new CExpr(CExpr.FUNCTION,
+			    "_JC_FCMPL", v.getOp1Box(), v.getOp2Box());
+		} else {
+			result = new CExpr(CExpr.FUNCTION,
+			    "_JC_DCMPL", v.getOp1Box(), v.getOp2Box());
+		}
+	}
+
+	public void caseDivExpr(DivExpr v) {
+		caseBinOpExpr(v, CExpr.DIVIDE);
+	}
+
+	public void caseEqExpr(EqExpr v) {
+		caseBinOpExpr(v, CExpr.EQUAL);
+	}
+
+	public void caseGeExpr(GeExpr v) {
+		caseBinOpExpr(v, CExpr.GE);
+	}
+
+	public void caseGtExpr(GtExpr v) {
+		caseBinOpExpr(v, CExpr.GT);
+	}
+
+	public void caseLeExpr(LeExpr v) {
+		caseBinOpExpr(v, CExpr.LE);
+	}
+
+	public void caseLtExpr(LtExpr v) {
+		caseBinOpExpr(v, CExpr.LT);
+	}
+
+	public void caseMulExpr(MulExpr v) {
+		caseBinOpExpr(v, CExpr.MULTIPLY);
+	}
+
+	public void caseNeExpr(NeExpr v) {
+		caseBinOpExpr(v, CExpr.NOT_EQUAL);
+	}
+
+	public void caseOrExpr(OrExpr v) {
+		caseBinOpExpr(v, CExpr.OR);
+	}
+
+	public void caseRemExpr(RemExpr v) {
+		if (v.getType() instanceof DoubleType
+		    || v.getType() instanceof FloatType) {
+			result = new CExpr(CExpr.FUNCTION,
+			    "_jc_cs_fmod", v.getOp1Box(), v.getOp2Box());
+			return;
+		}
+		caseBinOpExpr(v, CExpr.MODULO);
+	}
+
+	public void caseShlExpr(ShlExpr v) {
+		boolean isLong = (v.getOp1().getType() instanceof LongType);
+		result = new CExpr(CExpr.SHIFT_LEFT, v.getOp1Box(),
+		   new CExpr(CExpr.AND, v.getOp2Box(),
+		     isLong ? "0x3f" : "0x1f"));
+	}
+
+	public void caseShrExpr(ShrExpr v) {
+		boolean isLong = (v.getOp1().getType() instanceof LongType);
+		result = new CExpr(CExpr.FUNCTION,
+		    isLong ? "_JC_LSHR" : "_JC_ISHR",
+		    v.getOp1Box(), v.getOp2Box());
+	}
+
+	public void caseSubExpr(SubExpr v) {
+		caseBinOpExpr(v, CExpr.SUBTRACT);
+	}
+
+	public void caseUshrExpr(UshrExpr v) {
+		boolean isLong = (v.getOp1().getType() instanceof LongType);
+		result = new CExpr(CExpr.FUNCTION,
+		    isLong ? "_JC_LUSHR" : "_JC_IUSHR",
+		    v.getOp1Box(), v.getOp2Box());
+	}
+
+	public void caseXorExpr(XorExpr v) {
+		caseBinOpExpr(v, CExpr.XOR);
+	}
+
+	public void caseInterfaceInvokeExpr(InterfaceInvokeExpr v) {
+		final Object[] params = new Object[6 + v.getArgCount()];
+		int pnum = 0;
+		params[pnum++] = "_JC_INVOKE_INTERFACE";
+		params[pnum++] = "env";
+		params[pnum++] = v.getBaseBox();
+		params[pnum++] = new CExpr(CExpr.FUNCTION, "_JC_JLONG", "0x"
+		    + Long.toHexString(Util.sigHash(v.getMethod())));
+		params[pnum++] = C.valueType(v.getType());
+		params[pnum++] = C.paramsDecl(v.getMethod(), false);
+		for (int i = 0; i < v.getArgCount(); i++)
+			params[pnum++] = v.getArgBox(i);
+		result = new CExpr(CExpr.FUNCTION, params);
+	}
+
+	public void caseSpecialInvokeExpr(SpecialInvokeExpr v) {
+		SootMethod meth = v.getMethod();
+		SootClass specialClass = meth.getDeclaringClass();
+		ValueBox instance = v.getBaseBox();
+
+		// Is this a nonvirtual invocation?
+		boolean nonvirtual = Util.isNonvirtual(v, method.m);
+
+		// Use the appropriate C macro and parameters
+		Object[] params = new Object[5
+		    + (nonvirtual ? 1 : 0) + v.getArgCount()];
+		int pnum = 0;
+		params[pnum++] = nonvirtual ?
+		    "_JC_INVOKE_NONVIRTUAL" : "_JC_INVOKE_VIRTUAL";
+		params[pnum++] = "env";
+		params[pnum++] = specialClass;
+		params[pnum++] = meth;
+		if (nonvirtual) {
+			NullCheckTag tag = (NullCheckTag)getTag("NullCheckTag");
+			int nullchk = (tag == null || tag.needCheck()) ? 1 : 0;
+			params[pnum++] = "" + nullchk;
+		}
+		params[pnum++] = instance;
+		for (int i = 0; i < v.getArgCount(); i++)
+			params[pnum++] = v.getArgBox(i);
+
+		// Get result
+		result = new CExpr(CExpr.FUNCTION, params);
+	}
+
+	public void caseStaticInvokeExpr(StaticInvokeExpr v) {
+		SootMethod meth = v.getMethod();
+		SootClass currentClass = method.m.getDeclaringClass();
+		SootClass methodClass = meth.getDeclaringClass();
+		Object[] params = new Object[5 + v.getArgCount()];
+		ActiveUseTag tag = (ActiveUseTag)getTag("ActiveUseTag");
+		boolean omitCheck = tag != null && !tag.isCheckNeeded();
+		int pnum = 0;
+		params[pnum++] = "_JC_INVOKE_STATIC";
+		params[pnum++] = "env";
+		params[pnum++] = meth.getDeclaringClass();
+		params[pnum++] = meth;
+		params[pnum++] = omitCheck ? "1" : "0";
+		for (int i = 0; i < v.getArgCount(); i++)
+			params[pnum++] = v.getArgBox(i);
+		result = new CExpr(CExpr.FUNCTION, params);
+	}
+
+	public void caseVirtualInvokeExpr(VirtualInvokeExpr v) {
+		SootMethod meth = v.getMethod();
+		ValueBox instance = v.getBaseBox();
+
+		// Handle case where an interface method is specified
+		boolean invokei = meth.getDeclaringClass().isInterface();
+
+		// Construct expression
+		Object[] params;
+		int pnum = 0;
+		if (invokei) {
+			params = new Object[6 + v.getArgCount()];
+			params[pnum++] = "_JC_INVOKE_INTERFACE";
+			params[pnum++] = "env";
+			params[pnum++] = instance;
+			params[pnum++] = new CExpr(CExpr.FUNCTION, "_JC_JLONG",
+			    "0x" + Long.toHexString(Util.sigHash(meth)));
+			params[pnum++] = C.valueType(v.getType());
+			params[pnum++] = C.paramsDecl(v.getMethod(), false);
+		} else {
+			params = new Object[5 + v.getArgCount()];
+			params[pnum++] = "_JC_INVOKE_VIRTUAL";
+			params[pnum++] = "env";
+			params[pnum++] = meth.getDeclaringClass();
+			params[pnum++] = meth;
+			params[pnum++] = instance;
+		}
+		for (int i = 0; i < v.getArgCount(); i++)
+			params[pnum++] = v.getArgBox(i);
+		result = new CExpr(CExpr.FUNCTION, params);
+	}
+
+	public void caseCastExpr(CastExpr v) {
+		final Type ctype = v.getCastType();
+		final ValueBox operand = v.getOpBox();
+		final Type optype = v.getOp().getType();
+
+		// Can this cast be eliminated?
+		CastCheckTag tag = (CastCheckTag)getTag("CastCheckTag");
+		if (tag != null && tag.canEliminateCheck()) {
+			CValueSwitch sub = new CValueSwitch(method, operand);
+			operand.getValue().apply(sub);
+			result = (CExpr)sub.result;
+			return;
+		}
+
+		// Handle primitive casts using equivalent C casts
+		if (Util.isPrimitive(ctype)) {
+
+			// Handle floating -> integral casts
+			if (!(ctype instanceof FloatType
+			      || ctype instanceof DoubleType)
+			    && (optype instanceof FloatType
+			      || optype instanceof DoubleType)) {
+				result = new CExpr(CExpr.FUNCTION,
+				    new Object[] { "_JC_CAST_FLT2INT", "env", 
+				    C.type(optype), C.type(ctype), operand });
+				return;
+			}
+
+			// Handle "simple" casts using equivalent C casts
+			result = new CExpr(CExpr.CAST, C.type(ctype), operand);
+			return;
+		}
+
+		// Handle final types using an optimized cast
+		if (!Util.hasSubtypes(ctype)) {
+			result = new CExpr(CExpr.FUNCTION,
+			    "_JC_CAST_FINAL", "env", ctype, operand);
+			return;
+		}
+
+		// Normal cast
+		result = new CExpr(CExpr.FUNCTION,
+		    "_JC_CAST", "env", ctype, operand);
+	}
+
+	public void caseInstanceOfExpr(InstanceOfExpr v) {
+		final ValueBox operand = v.getOpBox();
+		final Type type = v.getCheckType();
+
+		// Handle any final type using a direct equality test
+		if (!Util.hasSubtypes(type)) {
+			result = new CExpr(CExpr.FUNCTION,
+			    "_JC_INSTANCEOF_FINAL", "env", operand, type);
+		} else {
+			result = new CExpr(CExpr.FUNCTION,
+			    "_JC_INSTANCEOF", "env", operand, type);
+		}
+	}
+
+	public void caseNewArrayExpr(NewArrayExpr v) {
+		ArrayType arrayType = (ArrayType)v.getType();
+		Type baseType = arrayType.baseType;
+		StackAllocTag tag = (StackAllocTag)getTag("StackAllocTag");
+		Object[] params = new Object[5 + (tag != null ? 1 : 0)];
+		int pnum = 0;
+		if (Util.isPrimitive(baseType)) {
+			params[pnum++] = tag != null ?
+			    "_JC_STACK_NEW_PRIM_ARRAY" : "_JC_NEW_PRIM_ARRAY";
+			params[pnum++] = "env";
+			if (tag != null)
+				params[pnum++] = "&mem" + tag.getId();
+			params[pnum++] = Util.typeWord(baseType);
+		} else {
+			RefType refType = (RefType)baseType;
+			params[pnum++] = tag != null ?
+			    "_JC_STACK_NEW_REF_ARRAY" : "_JC_NEW_REF_ARRAY";
+			params[pnum++] = "env";
+			if (tag != null)
+				params[pnum++] = "&mem" + tag.getId();
+			params[pnum++] = C.name(refType.getSootClass());
+		}
+		params[pnum++] = String.valueOf(arrayType.numDimensions);
+		params[pnum++] = v.getSizeBox();
+		result = new CExpr(CExpr.FUNCTION, params);
+	}
+
+	public void caseNewMultiArrayExpr(NewMultiArrayExpr v) {
+		ArrayType arrayType = (ArrayType)v.getType();
+		Type baseType = arrayType.baseType;
+		StackAllocTag tag = (StackAllocTag)getTag("StackAllocTag");
+		StringBuffer sizes = new StringBuffer();
+		boolean zero = false;
+		int i;
+		for (i = 0; i < v.getSizeCount(); i++) {
+			if (i > 0)
+				sizes.append(", ");
+			sizes.append(C.value(v.getSizeBox(i)));
+		}
+		Object[] params = new Object[6 + (tag != null ? 1 : 0)];
+		int pnum = 0;
+		if (Util.isReference(baseType)) {
+			params[pnum++] = tag != null ?
+			   "_JC_STACK_NEW_REF_MULTIARRAY" :
+			   "_JC_NEW_REF_MULTIARRAY"; 
+			params[pnum++] = "env";
+			if (tag != null)
+				params[pnum++] = "&mem" + tag.getId();
+			params[pnum++] = ((RefType)baseType).getSootClass();
+		} else {
+			params[pnum++] = tag != null ?
+			    "_JC_STACK_NEW_PRIM_MULTIARRAY" :
+			    "_JC_NEW_PRIM_MULTIARRAY";
+			params[pnum++] = "env";
+			if (tag != null)
+				params[pnum++] = "&mem" + tag.getId();
+			params[pnum++] = Util.typeWord(baseType);
+		}
+		params[pnum++] = new Integer(arrayType.numDimensions);
+		params[pnum++] = new Integer(v.getSizeCount());
+		params[pnum++] = sizes;
+		result = new CExpr(CExpr.FUNCTION, params);
+	}
+
+	public void caseNewExpr(NewExpr v) {
+		StackAllocTag tag = (StackAllocTag)getTag("StackAllocTag");
+		result = tag != null ?
+		    new CExpr(CExpr.FUNCTION, "_JC_STACK_NEW", "env",
+		      "&mem" + tag.getId(), v.getBaseType().getSootClass()) :
+		    new CExpr(CExpr.FUNCTION, "_JC_NEW",
+		      "env", v.getBaseType().getSootClass());
+	}
+
+	public void caseLengthExpr(LengthExpr v) {
+		result = new CExpr(CExpr.FUNCTION,
+		    "_JC_ARRAY_LENGTH", "env", v.getOpBox());
+	}
+
+	public void caseNegExpr(NegExpr v) {
+		result = new CExpr(CExpr.NEGATE, v.getOpBox());
+	}
+
+	public void caseInstanceFieldRef(InstanceFieldRef v) {
+		SootField field = v.getField();
+		Object[] params = new Object[5];
+		params[0] = Util.isReference(field) ?
+		    "_JC_REF_FIELD" : "_JC_PRIM_FIELD";
+		params[1] = "env";
+		params[2] = v.getBaseBox();
+		params[3] = field.getDeclaringClass();
+		params[4] = field;
+		result = new CExpr(CExpr.FUNCTION, params);
+	}
+
+	public void caseLocal(Local local) {
+		result = new CExpr(local.getName());
+	}
+
+	public void caseParameterRef(ParameterRef v) {
+		result = new CExpr("param" + v.getIndex());
+	}
+
+	public void caseCaughtExceptionRef(CaughtExceptionRef v) {
+		result = new CExpr(CExpr.FUNCTION,
+		    "_JC_CAUGHT_EXCEPTION", "env");
+	}
+
+	public void caseThisRef(ThisRef v) {
+		result = new CExpr("this");
+	}
+
+	public void caseStaticFieldRef(StaticFieldRef v) {
+		SootField field = v.getField();
+		SootClass currentClass = method.m.getDeclaringClass();
+		SootClass fieldClass = field.getDeclaringClass();
+		ActiveUseTag tag = (ActiveUseTag)getTag("ActiveUseTag");
+		boolean omitCheck = tag != null && !tag.isCheckNeeded();
+		Object[] params = new Object[5];
+		int pnum = 0;
+		params[pnum++] = "_JC_STATIC_FIELD";
+		params[pnum++] = "env";
+		params[pnum++] = fieldClass;
+		params[pnum++] = field;
+		params[pnum++] = omitCheck ? "1" : "0";
+		result = new CExpr(CExpr.FUNCTION, params);
+	}
+
+	public void defaultCase(Object v) {
+		Util.panic("unknown Value " + v);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/ClassConstant.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/ClassConstant.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/ClassConstant.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/ClassConstant.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,59 @@
+
+//
+// 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: ClassConstant.java,v 1.1 2004/07/13 03:36:20 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import java.util.Random;
+import soot.jimple.StringConstant;
+
+/**
+ * Hack for representing class constants, which Soot doesn't yet support.
+ * We fake them as string constants with a special random prefix.
+ * This class provides methods for converting back and forth.
+ */
+public class ClassConstant {
+
+	// Random prefix to avoid collisions
+	private static final String PREFIX
+	    = Long.toHexString(new Random().nextLong()
+	      + new Object().hashCode());
+
+	private ClassConstant() {
+	}
+
+	public static StringConstant v(String className) {
+		if (className.length() == 0 || className.charAt(0) == '[') {
+			throw new RuntimeException("bogus class name `"
+			    + className + "'");
+		}
+		return StringConstant.v(PREFIX + "/" + className);
+	}
+
+	public static boolean isClassConstant(StringConstant c) {
+		int i;
+		return (i = c.value.indexOf('/')) == PREFIX.length()
+		    && c.value.substring(0, i).equals(PREFIX);
+	}
+
+	public static String getClassName(StringConstant c) {
+		return c.value.substring(PREFIX.length() + 1);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CodeGenerator.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CodeGenerator.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CodeGenerator.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CodeGenerator.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,63 @@
+
+//
+// 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: CodeGenerator.java,v 1.2 2004/07/13 03:36:20 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import java.io.OutputStream;
+import org.dellroad.jc.ClassfileFinder;
+
+/**
+ * Interface for objects that can generate C source code and header files
+ * that conform to the JC C source file standard.
+ */
+public interface CodeGenerator {
+
+	/**
+	 * Generate the C header file for the given class.
+	 *
+	 * @param className name of the class who's header file we're generating
+	 * @param finder a way to acquire Java class files
+	 * @param output where to write the generated header file to
+	 */
+	public void generateH(String className, ClassfileFinder finder,
+	    OutputStream output) throws Exception;
+
+	/**
+	 * Generate the C source file for the given class.
+	 *
+	 * @param className name of the class who's C file we're generating
+	 * @param finder a way to acquire Java class files
+	 * @param output where to write the generated C file to
+	 */
+	public void generateC(String className, ClassfileFinder finder,
+	    OutputStream output) throws Exception;
+
+	/**
+	 * Reset state.
+	 *
+	 * <p>
+	 * Currently only one CodeGenerator instance will be
+	 * in use at a time. Before and after each use, this
+	 * method is invoked. A good oportunity to free objects
+	 * that are no longer needed, (re)initialize state, etc.
+	 */
+	public void reset();
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CodeWriter.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CodeWriter.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CodeWriter.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/CodeWriter.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,175 @@
+
+//
+// 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: CodeWriter.java,v 1.1.1.1 2004/02/20 05:15:25 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Arrays;
+
+/**
+ * Extension of {@link PrintWriter PrintWriter} that contains methods
+ * useful for generating and formatting C source files. Basically you
+ * can set an indentation level (see {@link #indent indent()}) that
+ * persists for subsequent lines until you unset it
+ * (see {@link #undent undent()}).
+ */
+public class CodeWriter extends PrintWriter {
+	private static final char[] EOL_chars
+	    = System.getProperty("line.separator").toCharArray();
+
+	protected final Writer w;
+	protected final int indent;
+	protected int indentLevel;
+	protected boolean needIndent;
+
+	/**
+	 * Constructor. Uses the default indentation of 8 spaces.
+	 *
+	 * @param w underlying output
+	 */
+	public CodeWriter(Writer w) {
+		this(w, 8);
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param w underlying output
+	 * @param indent number of spaces for each indentation level
+	 */
+	public CodeWriter(Writer w, int indent) {
+		super(w);
+		if (w == null || indent <= 0)
+			throw new IllegalArgumentException();
+		this.w = w;
+		this.indent = indent;
+		this.indentLevel = 0;
+	}
+
+	/**
+	 * Set indentation level to an absolute number of indents.
+	 *
+	 * @param level  Non-negative indentation level
+	 */
+	public void setIndent(int level) {
+		if (level < 0)
+			throw new IllegalArgumentException();
+		indentLevel = level;
+	}
+
+	/**
+	 * Get the current indentation level.
+	 */
+	public int getIndent() {
+		return (indentLevel);
+	}
+
+	/** 
+	 * Increase the current indentation level by one.
+	 */
+	public void indent() {
+		indentLevel++;
+	}
+
+	/** 
+	 * Decrease the current indentation level by one.
+	 */
+	public void undent() {
+		if (indentLevel > 0)
+			indentLevel--;
+	}
+
+	public void println() {
+		super.println();
+		needIndent = true;
+	}
+
+	/** 
+	 * Output enough tabs and spaces to achieve current indentation.
+	 */
+	protected void doIndent() {
+		int spaces = indentLevel * indent;
+		while (spaces >= 8) {
+			super.write('\t');
+			spaces -= 8;
+		}
+		super.write("       ", 0, spaces);
+		needIndent = false;
+	}
+
+	public void write(int ch) {
+		if (needIndent) {
+			char[] buf = new char[] { (char)ch };
+			doIndentIfNeeded(buf, 0, 1);
+		}
+		super.write(ch);
+	}
+
+	public void write(char[] buf) {
+		if (buf.length == 0)
+			return;
+		doIndentIfNeeded(buf, 0, buf.length);
+		super.write(buf);
+	}
+
+	public void write(char[] buf, int off, int len) {
+		if (len == 0)
+			return;
+		doIndentIfNeeded(buf, off, len);
+		super.write(buf, off, len);
+	}
+
+	public void write(String s) {
+		if (s.length() == 0)
+			return;
+		doIndentIfNeeded(s, 0, s.length());
+		super.write(s);
+	}
+
+	public void write(String s, int off, int len) {
+		if (len == 0)
+			return;
+		doIndentIfNeeded(s, off, len);
+		super.write(s, off, len);
+	}
+
+	private void doIndentIfNeeded(String s, int off, int len) {
+		if (!needIndent)
+			return;
+		if (len != EOL_chars.length)
+			doIndent();
+		doIndentIfNeeded(s.toCharArray(), off, len);
+	}
+
+	private void doIndentIfNeeded(char[] buf, int off, int len) {
+		if (!needIndent)
+			return;
+		if (len != EOL_chars.length)
+			doIndent();
+		for (int i = 0; i < len; i++) {
+			if (buf[off + i] != EOL_chars[i]) {
+				doIndent();
+				return;
+			}
+		}
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Constants.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Constants.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Constants.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Constants.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,43 @@
+
+//
+// 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: Constants.java,v 1.1.1.1 2004/02/20 05:15:25 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+/**
+ * Constants that define the sizes of certain automatically
+ * generated hash tables used by generated C code.
+ */
+public interface Constants {
+	/**
+	 * Size of interface method lookup hash tables
+	 * and ``quick'' interface method lookup tables.
+	 * Must be a power of two and equal to the definition
+	 * in <code>jc_defs.h</code>.
+	 */
+	public static final int IMETHOD_HASHSIZE = 128;
+
+	/**
+	 * Size of instanceof hash tables.
+	 * Must be a power of two and equal to the definition
+	 * in <code>jc_defs.h</code>.
+	 */
+	public static final int INSTANCEOF_HASHSIZE = 128;
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/DefaultMethodOptimizer.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/DefaultMethodOptimizer.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/DefaultMethodOptimizer.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/DefaultMethodOptimizer.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,551 @@
+
+//
+// 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: DefaultMethodOptimizer.java,v 1.24 2005/03/18 14:16:13 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import java.util.*;
+import org.dellroad.jc.cgen.escape.EscapeAnalysis;
+import org.dellroad.jc.cgen.analysis.TypeAnalysis;
+import soot.*;
+import soot.grimp.*;
+import soot.jimple.*;
+import soot.tagkit.*;
+import soot.toolkits.scalar.*;
+import soot.jimple.toolkits.invoke.*;
+import soot.toolkits.graph.CompleteUnitGraph;
+
+/**
+ * Method optimizer that does a few things beyond the normal Soot stuff:
+ *
+ * <ul>
+ * <li>Convert virtual method invocations to nonvirtual invocations
+ *	when the target method is final.</li>
+ * <li>Inline methods suitable for inlining (i.e., short enough,
+ *	nonvirtual invocation, etc.).</li>
+ * </ul>
+ *
+ * These are local optimizations only (not using a global call graph).
+ */
+public class DefaultMethodOptimizer implements MethodOptimizer {
+
+	// Default inlining parameters copied from Soot
+	public static final double MAX_EXPANSION
+	    = Double.parseDouble(System.getProperty(
+	      "jc.gen.inline.max.expansion", "2.5"));
+
+	// Maximum size we allow calling method to grow to
+	public static final int MAX_CALLER_SIZE
+	    = Integer.parseInt(System.getProperty(
+	      "jc.gen.inline.max.caller", "5000"));
+
+	// Maximum size of called method we'll inline
+	public static final int MAX_CALLEE_SIZE
+	    = Integer.parseInt(System.getProperty(
+	      "jc.gen.inline.max.callee", "12"));
+
+	// If below these sizes, don't worry about overflowing MAX_EXPANSION
+	public static final int MIN_CALLER_SIZE
+	    = Integer.parseInt(System.getProperty(
+	      "jc.gen.inline.min.caller", "20"));
+	public static final int MIN_CALLEE_SIZE
+	    = Integer.parseInt(System.getProperty(
+	      "jc.gen.inline.min.callee", "3"));
+
+	// Maximum size of stack-allocated objects
+	public static final int MAX_STACK_ALLOC
+	    = Integer.parseInt(System.getProperty(
+	      "jc.gen.max.stack.alloc", "1024"));
+
+	// Whether to print inlined methods
+	public static final boolean INLINE_VERBOSE
+	    = Boolean.getBoolean("jc.gen.inline.verbose");
+
+	// Represents one potential inline site
+	private static class Inline {
+
+		final SootMethod caller;
+		final SootMethod callee;
+		final InvokeExpr expr;
+		final Stmt stmt;
+		final int calleeSize;
+
+		public Inline(SootMethod caller, Stmt stmt) {
+			this.stmt = stmt;
+			this.callee = stmt.getInvokeExpr().getMethod();
+			this.caller = caller;
+			this.expr = stmt.getInvokeExpr();
+
+			// Compute callee size, not counting IdentityStmt's
+			int size = 0;
+			for (Iterator i = ((JimpleBody)callee
+			      .retrieveActiveBody()).getUnits().iterator();
+			    i.hasNext(); ) {
+				Stmt calleeStmt = (Stmt)i.next();
+				if (!(calleeStmt instanceof IdentityStmt))
+					size++;
+			}
+			this.calleeSize = size;
+		}
+
+		// Check size parameters
+		public boolean tooBig(int originalSize) {
+
+			// Get current size of caller method
+			int callerSize = ((JimpleBody)caller
+			    .retrieveActiveBody()).getUnits().size();
+
+			// Impose absolute maximum caller can grow to
+			if (callerSize + calleeSize > MAX_CALLER_SIZE)
+				return true;
+
+			// Below certain thresholds, we don't care
+			if (calleeSize <= MIN_CALLEE_SIZE)
+				return false;
+
+			// Don't inline large methods
+			if (calleeSize > MAX_CALLEE_SIZE)
+				return true;
+
+			// Below certain thresholds, we don't care
+			if (callerSize <= MIN_CALLER_SIZE)
+				return false;
+
+			// Limit the blowup of the calling method
+			if (callerSize + calleeSize
+			    > originalSize * MAX_EXPANSION)
+				return true;
+
+			// It's OK
+			return false;
+		}
+
+		public SootClass getStaticInvokeClass() {
+			if (!(expr instanceof StaticInvokeExpr))
+				return null;
+			return expr.getMethod().getDeclaringClass();
+		}
+	}
+
+	public CompleteUnitGraph optimize(SootMethod method, Set deps) {
+
+		// Get body and units
+		JimpleBody body = (JimpleBody)method.retrieveActiveBody();
+		PatchingChain units = body.getUnits();
+
+		//
+		// Look for this pattern:
+		//
+		// 	if (foo == null)
+		//		throw new NullPointerException();
+		//
+		// and replace with NullCheckStmt(foo);
+		//
+		optimizeExplicitNullChecks(body);
+
+		// Record original length of this method
+		int originalSize = units.size();
+
+		// Current flow graph
+		CompleteUnitGraph graph;
+
+		// Keep inlining until we can't anymore
+		while (true) {
+
+			// Apply the standard Soot jimple optimizations
+			PackManager.v().getPack("jop").apply(body);
+
+			// Work around Soot bug
+			Stmt first = (Stmt)units.getFirst();
+			Stmt nop = Jimple.v().newNopStmt();
+			units.insertBefore(nop, first);
+			nop.redirectJumpsToThisTo(first);
+
+			// (Re)compute flow graph
+			graph = new CompleteUnitGraph(body);
+
+			// (Re)compute type analysis
+			TypeAnalysis typeAnalysis = new TypeAnalysis(
+			    new SimpleLocalDefs(graph));
+
+			// Debug
+			//CMethod.dumpBody(method, "BEFORE NEXT INLINING");
+
+			// Convert virtual -> nonvirtual
+			nonvirtualize(body, typeAnalysis);
+
+			// Find the best inlinable invocation site
+			Inline inline = null;
+			for (Iterator i = units.iterator(); i.hasNext(); ) {
+
+				// Must be INVOKESTATIC or INVOKESPECIAL
+				Stmt stmt = (Stmt)i.next();
+				if (!stmt.containsInvokeExpr())
+					continue;
+
+				// Check invocation for basic suitability
+				if (!safeToInline(method, stmt))
+					continue;
+				Inline candidate = new Inline(method, stmt);
+				if (candidate.tooBig(originalSize))
+					continue;
+
+				// Save the shortest inline
+				if (inline == null
+				    || candidate.calleeSize < inline.calleeSize)
+					inline = candidate;
+			}
+
+			// Anything to do?
+			if (inline == null)
+				break;
+
+			// Grab line number tag, if any
+			LineNumberTag lineNumberTag = (LineNumberTag)
+			    inline.stmt.getTag("LineNumberTag");
+
+			// Add a null pointer check if invocation is non-static
+			if (!inline.callee.getName().equals("<init>")
+			    && inline.expr instanceof InstanceInvokeExpr) {
+				InstanceInvokeExpr iexpr
+				    = (InstanceInvokeExpr)inline.expr;
+				NullCheckStmt.insertNullCheck(units,
+				    inline.stmt, iexpr.getBase());
+			}
+
+			// Verbosity
+			if (INLINE_VERBOSE) {
+				System.out.println("Inlining "
+				    + inline.caller.getDeclaringClass()
+				      .getName()
+				    + "." + Util.fullSignature(inline.caller)
+				    + " <-- "
+				    + inline.callee.getDeclaringClass()
+				      .getName()
+				    + "." + Util.fullSignature(inline.callee));
+			}
+
+			// Remember statement just before the inline site
+			Stmt pred = (Stmt)units.getPredOf(inline.stmt);
+
+			// Inline it
+			SiteInliner.inlineSite(inline.callee,
+			    inline.stmt, inline.caller, Collections.EMPTY_MAP);
+
+			// Get first statement of inlined method
+			Stmt inlineStart = (Stmt)(pred != null ?
+			    units.getSuccOf(pred) : units.getFirst());
+
+			// Copy line number tag, if any
+			if (lineNumberTag != null)
+				inlineStart.addTag(lineNumberTag);
+
+			// Add an active use check if method is static
+			SootClass cl = inline.getStaticInvokeClass();
+			if (cl != null) {
+				ActiveUseCheckStmt.insertActiveUseCheck(units,
+				    inlineStart, cl);
+			}
+
+			// Record a dependency on the inlined class
+			deps.add(inline.callee.getDeclaringClass());
+		}
+
+		// Debug
+		//CMethod.dumpBody(method, "BEFORE TAG ANNOTATION");
+
+		// Do tag annotations
+		PackManager.v().getPack("jap").apply(body);
+
+		// Do escape analysis
+		EscapeAnalysis.analyze(graph, MAX_STACK_ALLOC);
+
+	    	// Return optimized body
+		return graph;
+	}
+
+	// Basic check for inline saftey without regards to size blowup
+	private boolean safeToInline(SootMethod callingMethod, Stmt stmt) {
+
+		// Get info
+		InvokeExpr invoke = stmt.getInvokeExpr();
+		SootMethod calledMethod = invoke.getMethod();
+		SootClass callingClass = callingMethod.getDeclaringClass();
+		SootClass calledClass = calledMethod.getDeclaringClass();
+
+		// Avoid inlining our various hacks
+		if (NullCheckStmt.isNullCheck(stmt)
+		    || ActiveUseCheckStmt.isActiveUseCheck(stmt))
+			return false;
+
+		// Avoid inlining recursive invocations
+		if (callingMethod.equals(calledMethod))
+			return false;
+
+		// Avoid inlining when base is "null" to workaround problem
+		// where gcc -O2 optimizes away code like this:
+		//	((Object)null).hashCode();
+		// Besides, what's the point, we know it will segfault
+		if (invoke instanceof InstanceInvokeExpr
+		    && ((InstanceInvokeExpr)invoke).getBase()
+		      instanceof NullConstant)
+			return false;
+
+		//
+		// Avoid inlining synchronized methods, due to the following
+		// issues:
+		//
+		// - When Soot inlines static ones, it adds code to invoke
+		//   Class.forName() which uses a static field, and we don't
+		//   handle that (a previously generated header file would
+		//   not declare the new field). 
+		//
+		// - We add explicit synchronization wrapping statements to
+		//   the Jimple for synchronized methods, and we don't want
+		//   to track whether this modification has been done yet.
+		//
+		// - When both methods are in the same class, both static
+		//   or non-static, and both synchronized, we want to remove
+		//   the "inner" synchronization as an optimization.
+		//
+		// - In any case, it's not clear that inlining is even much
+		//   of a win in light of all the synchronization overhead.
+		//
+		if (calledMethod.isSynchronized())
+			return false;
+
+		// The method invocation must be to a known, fixed method
+		if (!(invoke instanceof StaticInvokeExpr
+		    || (invoke instanceof SpecialInvokeExpr
+		      && Util.isNonvirtual((SpecialInvokeExpr)invoke,
+		       callingMethod))))
+			return false;
+
+		// The target method must not be native, etc.
+		if (!calledMethod.isConcrete())
+			return false;
+
+		//
+		// Any INVOKESPECIAL's in the called method must be nonvirtual
+		// in both classes, or else the two classes must be the same.
+		// Also, don't inline anything calling VMStackWalker methods.
+		//
+		for (Iterator i = ((JimpleBody)calledMethod
+		    .retrieveActiveBody()).getUnits().iterator();
+		    i.hasNext(); ) {
+
+			// Check invoke Stmt's
+			Stmt calleeStmt = (Stmt)i.next();
+			if (!calleeStmt.containsInvokeExpr())
+				continue;
+			InvokeExpr expr = calleeStmt.getInvokeExpr();
+
+			// Avoid VMStackWalker
+			if (expr.getMethod().getDeclaringClass().getName()
+			    .equals("gnu.classpath.VMStackWalker"))
+				return false;
+
+			// Check INVOKESPECIALs
+			if (!(expr instanceof SpecialInvokeExpr))
+				continue;
+			SpecialInvokeExpr innerInvoke = (SpecialInvokeExpr)expr;
+			if ((!Util.isNonvirtual(innerInvoke, callingMethod)
+			      || !Util.isNonvirtual(innerInvoke, callingMethod))
+			    && !callingClass.equals(calledClass))
+				return false;
+		}
+		return true;
+	}
+
+	// Look for virtual and interface invocations that we can
+	// convert into nonvirtual invocations.
+	private void nonvirtualize(JimpleBody body, TypeAnalysis typeAnalysis) {
+		for (Iterator i = body.getUnits().iterator(); i.hasNext(); ) {
+
+			// Look for method invocations
+			Stmt stmt = (Stmt)i.next();
+			if (!stmt.containsInvokeExpr())
+				continue;
+			InvokeExpr expr = stmt.getInvokeExpr();
+
+			// Try to nonvirtualize
+			SootMethod actualMethod = null;
+			if (expr instanceof VirtualInvokeExpr) {
+				actualMethod = nonvirtualizeVirtual(stmt,
+				    (VirtualInvokeExpr)expr, typeAnalysis);
+			} else if (expr instanceof InterfaceInvokeExpr) {
+				actualMethod = nonvirtualizeInterface(stmt,
+				    (InterfaceInvokeExpr)expr, typeAnalysis);
+			}
+
+			// Sanity check
+			if (actualMethod != null
+			    && actualMethod.getDeclaringClass().isInterface())
+				throw new RuntimeException("oops");
+
+			// Replace invocation with INVOKESPECIAL
+			if (actualMethod != null) {
+				InstanceInvokeExpr invoke
+				    = (InstanceInvokeExpr)expr;
+				Local base = (Local)invoke.getBase();
+				stmt.getInvokeExprBox().setValue(
+				    Jimple.v().newSpecialInvokeExpr(
+				      base, actualMethod, invoke.getArgs()));
+			}
+		}
+	}
+
+	// Try to nonvirtualize an INVOKEVIRTUAL
+	private SootMethod nonvirtualizeVirtual(Stmt stmt,
+	    VirtualInvokeExpr invoke, TypeAnalysis typeAnalysis) {
+
+		// Check for final methods
+		SootMethod method = invoke.getMethod();
+		if (Util.isFinal(method)
+		    || Util.isFinal(method.getDeclaringClass()))
+			return method;
+
+		// Check if exact type is known
+		SootClass c = null;
+		RefLikeType type =  typeAnalysis.getExactType(
+		    (Local)invoke.getBase(), stmt);
+		if (type instanceof RefType)
+			c = ((RefType)type).getSootClass();
+//		else if (type instanceof ArrayType)
+//			c = Scene.v().getSootClass("java.lang.Object");
+		if (c != null) {
+			return c.getMethod(method.getName(),
+			    method.getParameterTypes(),
+			    method.getReturnType());
+		}
+		return null;
+	}
+
+	// Try to nonvirtualize an INVOKEINTERFACE
+	private SootMethod nonvirtualizeInterface(Stmt stmt,
+	    InterfaceInvokeExpr invoke, TypeAnalysis typeAnalysis) {
+
+		// Check if exact type is known
+		SootClass c = null;
+		RefLikeType type = typeAnalysis.getExactType(
+		    (Local)invoke.getBase(), stmt);
+		if (type instanceof RefType)
+			c = ((RefType)type).getSootClass();
+//		else if (type instanceof ArrayType)
+//			c = Scene.v().getSootClass("java.lang.Object");
+		if (c != null) {
+			SootMethod method = invoke.getMethod();
+			return c.getMethod(method.getName(),
+			    method.getParameterTypes(),
+			    method.getReturnType());
+		}
+		return null;
+	}
+
+	//
+	// We look for this pattern:
+	//
+	//	if ($expr != null)
+	//		goto label1;
+	//	$local = new NullPointerException();
+	//	invokespecial NullPointerException.<init>
+	//	throw $local
+	//  label1:
+	//
+	// and replace with a more efficient explicit null pointer check
+	//
+	private void optimizeExplicitNullChecks(JimpleBody body) {
+		PatchingChain units = body.getUnits();
+		for (Iterator i = units.snapshotIterator(); i.hasNext(); ) {
+
+			// Look for the pattern
+			Value value;
+			IfStmt ifStmt;
+			AssignStmt newStmt;
+			InvokeStmt invokeStmt;
+			ThrowStmt throwStmt;
+			try {
+				// Decode if (v != null) statement
+				ifStmt = (IfStmt)i.next();
+				Stmt ifTarget = ifStmt.getTarget();
+				NeExpr ifNeExpr = (NeExpr)ifStmt.getCondition();
+				Value op1 = ifNeExpr.getOp1();
+				Value op2 = ifNeExpr.getOp2();
+				if (op1 instanceof NullConstant)
+					value = op2;
+				else if (op2 instanceof NullConstant)
+					value = op1;
+				else
+					continue;
+
+				// Decode x = new NullPointerException
+				newStmt = (AssignStmt)i.next();
+				Local exception = (Local)newStmt.getLeftOp();
+				NewExpr newExpr = (NewExpr)newStmt.getRightOp();
+				SootClass npeClass
+				    = newExpr.getBaseType().getSootClass();
+				if (!npeClass.getName().equals(
+				    "java.lang.NullPointerException"))
+				    	continue;
+
+				// Decode x.<init> invocation
+				invokeStmt = (InvokeStmt)i.next();
+				SpecialInvokeExpr invokeExpr
+				    = (SpecialInvokeExpr)invokeStmt
+				      .getInvokeExpr();
+				if (invokeExpr.getBase() != exception)
+					continue;
+				SootMethod init = invokeExpr.getMethod();
+				if (init.getDeclaringClass() != npeClass)
+					continue;
+				if (!init.getName().equals("<init>")
+				    || invokeExpr.getArgCount() != 0)
+				    	continue;
+
+				// Decode throw x statement
+				throwStmt = (ThrowStmt)i.next();
+				if (throwStmt.getOp() != exception)
+					continue;
+
+				// The next statement must be the != target
+				if (i.next() != ifTarget)
+					continue;
+			} catch (ClassCastException e) {
+				continue;
+			}
+
+			// There must be no branches into the statements
+			if (!newStmt.getBoxesPointingToThis().isEmpty())
+				continue;
+			if (!invokeStmt.getBoxesPointingToThis().isEmpty())
+				continue;
+			if (!throwStmt.getBoxesPointingToThis().isEmpty())
+				continue;
+
+			// Replace statements with explicit null check
+			NullCheckStmt.insertNullCheck(units, ifStmt, value);
+			units.remove(ifStmt);
+			units.remove(newStmt);
+			units.remove(invokeStmt);
+			units.remove(throwStmt);
+		}
+	}
+}
+
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/HFile.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/HFile.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/HFile.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/HFile.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,389 @@
+
+//
+// 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: HFile.java,v 1.3 2005/05/08 21:12:07 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import soot.*;
+import java.util.*;
+import java.io.*;
+
+/**
+ * Represents a C header file being constructed from a Java class file.
+ */
+public class HFile extends SourceFile {
+	protected String includeProtector;
+
+	public HFile(SootClass c, Writer out) {
+		super(c, out);
+		includeProtector = "_JC_" + cname + "_H_";
+	}
+
+	/**
+	 * Output the C header file.
+	 */
+	public void output() {
+		outputInitialStuff();
+		outputForwardDecls();
+		outputTypedefs();
+		outputStaticFieldStructure();
+		outputMethodDeclarations();
+		outputVirtualMethodStructure();
+		outputVtable();
+		outputVtype();
+		outputObject();
+		outputClassInfoDecl();
+		outputFinalStuff();
+		out.close();
+	}
+
+	public void outputInitialStuff() {
+
+		// Include direct superclass's header file only.
+		// Depend on this class and all superclasses.
+		super.outputInitialStuff(superclasses.size() > 1 ?
+		   new SootClass[] { (SootClass)superclasses.get(1) } :
+		   new SootClass[] { /* must be java.lang.Object */ },
+		   (SootClass[])superclasses.toArray(
+		     new SootClass[superclasses.size()]), false);
+		out.println("#ifndef " + includeProtector);
+		out.println("#define " + includeProtector);
+		out.println();
+	}
+
+	public void outputFinalStuff() {
+		out.println("#endif\t/* " + includeProtector + " */");
+		super.outputFinalStuff();
+	}
+
+	public void outputForwardDecls() {
+
+		// Skip for interfaces
+		if (c.isInterface())
+			return;
+
+		outputCommentLine("Forward structure declarations");
+		HashSet decls = new HashSet();
+
+		// Declare types for all reference fields
+		// XXX not really necessary
+		for (Iterator i = c.getFields().iterator(); i.hasNext(); ) {
+			SootField f = (SootField)i.next();
+			if (f.getType() instanceof RefType) {
+				RefType t = (RefType)f.getType();
+				decls.add(t.getSootClass().getName());
+			}
+		}
+
+		// Declare types for all method parameters and return values
+		for (Iterator i = c.getMethods().iterator(); i.hasNext(); ) {
+			SootMethod m = (SootMethod)i.next();
+			for (int j = 0; j < m.getParameterCount(); j++) {
+				Type t = m.getParameterType(j);
+				if (t instanceof RefType) {
+					decls.add(((RefType)t)
+					    .getSootClass().getName());
+				}
+			}
+			if (m.getReturnType() instanceof RefType) {
+				decls.add(((RefType)m.getReturnType())
+				    .getSootClass().getName());
+			}
+		}
+
+		// Declare type for java.lang.Class, which is
+		// an implicit parameter to all static methods
+		decls.add("java.lang.Class");
+
+		// Output forward decl's
+		String[] list = (String[])decls.toArray(
+		    new String[decls.size()]);
+		Arrays.sort(list);
+		for (int i = 0; i < list.length; i++) {
+			out.println("struct _jc_"
+			    + C.encode(list[i]) + "$object;");
+		}
+		out.println();
+	}
+
+	public void outputTypedefs() {
+
+		outputCommentLine("Typedefs");
+		if (!c.isInterface()) {
+			out.println("typedef struct "
+			    + prefix + "$sub_refs\t" + prefix + "$sub_refs;");
+			out.println("typedef struct "
+			    + prefix + "$sub_nonrefs\t"
+			    + prefix + "$sub_nonrefs;");
+			out.println("typedef struct "
+			    + prefix + "$refs\t" + prefix + "$refs;");
+			out.println("typedef struct "
+			    + prefix + "$nonrefs\t" + prefix + "$nonrefs;");
+			out.println("typedef struct "
+			    + prefix + "$object\t" + prefix + "$object;");
+			out.println();
+		}
+		if (staticFields.length > 0) {
+			out.println("typedef struct " + prefix
+			    + "$fields_struct\t" + prefix + "$fields_struct;");
+		}
+		if (!c.isInterface()) {
+			out.println("typedef const struct "
+			    + prefix + "$vmethods\t" + prefix + "$vmethods;");
+			out.println("typedef const struct "
+			    + prefix + "$vtable\t" + prefix + "$vtable;");
+		}
+		out.println("typedef const struct "
+		    + prefix + "$vtype\t" + prefix + "$vtype;");
+		out.println();
+	}
+
+	// Output static fields structure, reference fields first
+	public void outputStaticFieldStructure() {
+		if (staticFields.length == 0)
+			return;
+		outputCommentLine("Class fields structure");
+		out.println("struct " + prefix + "$fields_struct {");
+		out.indent();
+		for (int i = 0; i < staticFields.length; i++) {
+			SootField field = staticFields[i];
+			out.println(C.type(field, true) + "\t"
+			    + (Util.isReference(field) ? "*" : "")
+			    + (Modifier.isVolatile(field.getModifiers()) ?
+			      "volatile " : "")
+			    + C.name(field) + ";");
+		}
+		out.undent();
+		out.println("};");
+		out.print("extern ");
+//		if (c.isInterface())
+//			out.print("const ");
+		out.println(prefix + "$fields_struct "
+		    + prefix + "$class_fields;");
+		out.println();
+	}
+
+	public void outputMethodDeclarations() {
+
+		// Declare constructors
+		if (constructors.length > 0) {
+			outputCommentLine("Constructors");
+			for (int i = 0; i < constructors.length; i++) {
+				SootMethod method = constructors[i];
+				out.print("extern ");
+				out.print(C.type(method, true) + " ");
+				if (Util.isReference(method))
+					out.print('*');
+				out.println(prefix + "$method$" + C.name(method)
+				    + C.paramsDecl(method, false)
+				    + " _JC_JCNI_ATTR;");
+			}
+			out.println();
+		}
+
+		// Declare virtual methods
+		if (!c.isInterface() && virtualMethods.length > 0) {
+			outputCommentLine("Virtual methods");
+			for (int i = 0; i < virtualMethods.length; i++) {
+				SootMethod method = virtualMethods[i];
+				out.print("extern ");
+				out.print(C.type(method, true) + " ");
+				if (Util.isReference(method))
+					out.print('*');
+				out.println(prefix + "$method$" + C.name(method)
+				    + C.paramsDecl(method, false)
+				    + " _JC_JCNI_ATTR;");
+			}
+			out.println();
+		}
+
+		// Declare virtual method descriptors for use in
+		// subclass interface method hash tables
+		if (!c.isInterface() && virtualMethods.length > 0) {
+			outputCommentLine("Virtual method descriptors");
+			for (int i = 0; i < virtualMethods.length; i++) {
+				SootMethod method = virtualMethods[i];
+				out.println("extern _jc_method " + prefix
+				    + "$method_info$" + C.name(method) + ";");
+			}
+			out.println();
+		}
+
+		// Declare static methods
+		if (staticMethods.length > 0) {
+			outputCommentLine("Static methods");
+			for (int i = 0; i < staticMethods.length; i++) {
+				SootMethod method = staticMethods[i];
+				out.print("extern ");
+				out.print(C.type(method, true) + " ");
+				if (Util.isReference(method))
+					out.print('*');
+				out.println(prefix + "$method$" + C.name(method)
+				    + C.paramsDecl(method, false)
+				    + " _JC_JCNI_ATTR;");
+			}
+			out.println();
+		}
+	}
+
+	public void outputVirtualMethodStructure() {
+		if (c.isInterface())
+			return;
+		outputCommentLine("Virtual methods structure");
+		out.println("struct " + prefix + "$vmethods {");
+		out.indent();
+		for (int i = 0; i < virtualMethods.length; i++) {
+			SootMethod m = virtualMethods[i];
+			out.print(C.type(m, true) + "\t");
+			if (Util.isReference(m))
+				out.print('*');
+			out.println("(*" + C.name(m) + ")"
+			    + C.paramsDecl(m, false) + " _JC_JCNI_ATTR;");
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputVtable() {
+		if (c.isInterface())
+			return;
+		outputCommentLine("Vtable");
+		out.println("struct " + prefix + "$vtable {");
+		out.indent();
+		for (int i = superclasses.size() - 1; i >= 0; i--) {
+			String sc = C.name((SootClass)superclasses.get(i));
+			out.println("_jc_" + sc + "$vmethods\t" + sc + ";");
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputVtype() {
+		outputCommentLine("Vtype");
+		out.println("struct " + prefix + "$vtype {");
+		out.indent();
+		out.println("_jc_type\t\t\ttype;");
+		if (!c.isInterface())
+			out.println(prefix + "$vtable\tvtable;");
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputObject() {
+
+		// Skip for interfaces
+		if (c.isInterface())
+			return;
+
+		// Do structure containing subclass reference fields
+		outputCommentLine("Reference instance fields (subclass)");
+		out.println("struct " + prefix + "$sub_refs {");
+		out.indent();
+		for (Iterator i = c.getFields().iterator(); i.hasNext(); ) {
+			SootField f = (SootField)i.next();
+			if (!Util.isReference(f) || f.isStatic())
+				continue;
+			out.println(C.type(f, true) + "\t*"
+			    + (Modifier.isVolatile(f.getModifiers()) ?
+			      "volatile " : "")
+			    + C.name(f) + ";");
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+
+		// Do structure containing reference fields
+		outputCommentLine("Reference instance fields (object)");
+		out.println("struct " + prefix + "$refs {");
+		for (int i = 0; i < superclasses.size(); i++) {
+			SootClass sc = (SootClass)superclasses.get(i);
+			String scname = C.name(sc);
+			out.println("    _jc_"
+			    + scname + "$sub_refs\t" + scname + ";");
+		}
+		out.println("};");
+		out.println();
+
+		// Do structure containing subclass non-reference fields
+		outputCommentLine("Non-reference instance fields (subclass)");
+		out.println("struct " + prefix + "$sub_nonrefs {");
+		out.indent();
+		for (Iterator i = c.getFields().iterator(); i.hasNext(); ) {
+			SootField f = (SootField)i.next();
+			if (Util.isReference(f) || f.isStatic())
+				continue;
+			out.println(C.type(f) + "\t"
+			    + (Modifier.isVolatile(f.getModifiers()) ?
+			      "volatile " : "")
+			    + C.name(f) + ";");
+		}
+		out.undent();
+		out.println("};");
+		out.println();
+
+		// Do structure containing non-reference fields
+		outputCommentLine("Non-reference instance fields (object)");
+		out.println("struct " + prefix + "$nonrefs {");
+		for (int i = superclasses.size() - 1; i >= 0; i--) {
+			SootClass sc = (SootClass)superclasses.get(i);
+			String scname = C.name(sc);
+			out.println("    _jc_"
+			    + scname + "$sub_nonrefs\t" + scname + ";");
+		}
+		out.println("};");
+		out.println();
+
+		// Do object structure
+		outputCommentLine("Object instance structure");
+		out.println("struct " + prefix + "$object {");
+		out.indent();
+
+		// Reference fields (this class first)
+		out.println(prefix + "$refs\trefs[0];");
+
+		// Head structure
+		out.println("_jc_word\t\tlockword;");
+		out.println(prefix + "$vtype\t*vtype;");
+
+		// Non-reference fields (this class last)
+		out.println(prefix + "$nonrefs\tnonrefs;");
+
+		// End object structure
+		out.undent();
+		out.println("};");
+		out.println();
+	}
+
+	public void outputClassInfoDecl() {
+		outputCommentLine("Type structure");
+		out.println("extern " + prefix + "$vtype " + prefix + "$type;");
+		out.println();
+		outputCommentLine("Array types class info structures");
+		out.println("_JC_DECL_ARRAYS(" + cname + ", type);");
+		out.println();
+		outputCommentLine("java.lang.Class instance");
+		out.println("extern struct _jc_java_lang_Class$object "
+		    + prefix + "$class_object;");
+		out.println();
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/JCObjectGenerator.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/JCObjectGenerator.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/JCObjectGenerator.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/JCObjectGenerator.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,593 @@
+
+//
+// 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: JCObjectGenerator.java,v 1.8 2005/03/13 02:29:51 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.dellroad.jc.ClassfileFinder;
+import org.dellroad.jc.ObjectGenerator;
+import org.dellroad.jc.Generate;
+import org.dellroad.jc.SearchpathFinder;
+
+/**
+ * The default JC object file generator class. This class uses a
+ * {@link CodeGenerator} to generate C source and header files,
+ * then compiles them into ELF object files using GCC.
+ *
+ * <p>
+ * The generated source files are expected to contain initial
+ * double-slash comment lines with <code>@dep_header</code> tags
+ * for each required header file and <code>@dep_class</code> tags
+ * for each class file on which the generated source depends.
+ */
+public class JCObjectGenerator implements ObjectGenerator {
+
+	private final CodeGenerator codeGenerator;
+	private final String sourcePath[];
+	private final boolean verbose;
+	private final boolean debugSymbols;
+	private final boolean sourcesOnly;
+	private final boolean force;
+
+	/**
+	 * Instantiate an object with an instance of
+	 * {@link SootCodeGenerator} using a custom {@link SourceLocator}
+	 * as the underlying source file generator, and use system properties
+	 * to determine where source and object files go, whether to be
+	 * verbose, and what {@link MethodOptimizer} to use. This constructor
+	 * should only be used when JC is the JVM.
+	 */
+	public JCObjectGenerator() {
+		this(new SootCodeGenerator(
+		    new SourceLocator(null), null,
+		      Boolean.getBoolean("jc.include.line.numbers")),
+		    System.getProperty("jc.source.path", "."),
+		    Boolean.getBoolean("jc.verbose.gen"),
+		    Boolean.getBoolean("jc.include.line.numbers"),
+		    false, Boolean.getBoolean("jc.gen.force"));
+	}
+
+	/**
+	 * Instantiate an object using the supplied configuration.
+	 *
+	 * @param codeGenerator Object that can generate JC C source code.
+	 * @param sourcePath Search path for C source and header files.
+	 *	First component of path is where newly generated files go.
+	 * @param verbose Whether to print verbose output to standard error
+	 * @param debugSymbols Whether to compile with the <code>-g</code> flag.
+	 * @param sourcesOnly If <code>true</code> generate sources only,
+	 *	don't compile them into ELF objects.
+	 */
+	public JCObjectGenerator(CodeGenerator codeGenerator,
+	    String sourcePath, boolean verbose, boolean debugSymbols,
+	    boolean sourcesOnly, boolean force) {
+		this.codeGenerator = codeGenerator;
+		this.sourcePath = SearchpathFinder.splitPath(sourcePath);
+		this.verbose = verbose;
+		this.debugSymbols = debugSymbols;
+		this.sourcesOnly = sourcesOnly;
+		this.force = force;
+	}
+
+	/**
+	 * Generate object file using analysis via Soot.
+	 * 
+	 * <p>
+	 * This method is synchronized because Soot is not reentrant.
+	 */
+	public synchronized void generateObject(String className,
+	    ClassfileFinder finder, File objectFile) throws Exception {
+		int ci;
+
+		// Reset generator
+		codeGenerator.reset();
+
+		// Verify existing C file or generate a new one
+		if (force
+		    || (ci = verifySource(className, true, finder)) == -1) {
+			genCFile(className, finder);
+			if ((ci = verifySource(className,
+			    true, finder)) == -1) {
+				throw new Exception("generated file `"
+				    + cFile(className, 0) + "' is not valid");
+			}
+		}
+
+		// Get list of header files required by the C file
+		Set hdrs = readDeps(cFile(className, ci), "@dep_header", false);
+
+		// Recursively ensure all required header files exist
+		Set doneHdrs = new HashSet();
+		while (hdrs.size() > 0) {
+			int hi;
+
+			// Get the next unverified header file dependency
+			Iterator i = hdrs.iterator();
+			Dep dep = (Dep)i.next();
+			i.remove();
+
+			// Verify existing header file or generate a new one
+			if (force
+			    || (hi = verifySource(dep.className,
+			      false, finder)) == -1) {
+				genHFile(dep.className, finder);
+				if ((hi = verifySource(dep.className,
+				    false, finder)) == -1) {
+					throw new Exception("generated file"
+					    + "`" + hFile(className, 0)
+					    + "' is not valid");
+				}
+			}
+			doneHdrs.add(dep);
+
+			// Add in dependencies from header file itself
+			for (Iterator j = readDeps(hFile(dep.className, hi),
+			    "@dep_header", false).iterator(); j.hasNext(); ) {
+				Dep dep2 = (Dep)j.next();
+				if (!doneHdrs.contains(dep2))
+					hdrs.add(dep2);
+			}
+		}
+
+		// Create directories for object file
+		if (!sourcesOnly)
+			mkdirs(objectFile);
+
+		// Now compile the C file
+		if (!sourcesOnly)
+			compile(cFile(className, ci), objectFile);
+
+		// Reset generator
+		codeGenerator.reset();
+	}
+
+	public boolean objectIsValid(String className,
+	    ClassfileFinder finder, File objectFile) throws Exception {
+		int ci;
+
+		// Verify object file exists and is non-empty
+		if (!objectFile.exists() || objectFile.length() == 0)
+			return false;
+
+		// Verify existing C file and check timestamp
+		if ((ci = verifySource(className, true, finder)) == -1)
+			return false;
+		if (cFile(className, ci).lastModified()
+		   > objectFile.lastModified())
+			return false;
+
+		// Get list of header files required by the C file
+		Set hdrs = readDeps(cFile(className, ci), "@dep_header", false);
+
+		// Recursively ensure all required header files exist
+		Set doneHdrs = new HashSet();
+		while (hdrs.size() > 0) {
+			int hi;
+
+			// Get the next unverified header file dependency
+			Iterator i = hdrs.iterator();
+			Dep dep = (Dep)i.next();
+			i.remove();
+
+			// Verify existing header file and check timestamp
+			if ((hi = verifySource(dep.className,
+			    false, finder)) == -1)
+				return false;
+			if (hFile(className, ci).lastModified()
+			   > objectFile.lastModified())
+				return false;
+			doneHdrs.add(dep);
+
+			// Add in dependencies from header file itself
+			for (Iterator j = readDeps(hFile(dep.className, hi),
+			    "@dep_header", false).iterator(); j.hasNext(); ) {
+				Dep dep2 = (Dep)j.next();
+				if (!doneHdrs.contains(dep2))
+					hdrs.add(dep2);
+			}
+		}
+
+		// Looks OK
+		return true;
+	}
+
+	// Generate a C source file using our CodeGenerator
+	private void genCFile(String className, ClassfileFinder finder)
+	    throws Exception {
+		File file = cFile(className, 0);
+		file.delete();
+		mkdirs(file);
+		OutputStream output = new FileOutputStream(file);
+		if (verbose)
+			System.out.println("Generating `" + file + "'");
+		boolean ok = false;
+		try {
+			codeGenerator.generateC(className, finder, output);
+			ok = true;
+		} finally {
+			output.close();
+			if (!ok)
+				file.delete();
+		}
+	}
+
+	// Generate a C header file using our CodeGenerator
+	private void genHFile(String className, ClassfileFinder finder)
+	    throws Exception {
+		File file = hFile(className, 0);
+		file.delete();
+		mkdirs(file);
+		OutputStream output = new FileOutputStream(file);
+		if (verbose)
+			System.out.println("Generating `" + file + "'");
+		boolean ok = false;
+		try {
+			codeGenerator.generateH(className, finder, output);
+			ok = true;
+		} finally {
+			output.close();
+			if (!ok)
+				file.delete();
+		}
+	}
+
+	private void mkdirs(File file) {
+		if ((file = file.getParentFile()) == null)
+			return;
+		if (file.exists())
+			return;
+		file.mkdirs();
+	}
+
+	// Verify there is a valid source file. Delete any invalid ones.
+	private int verifySource(String className,
+	    boolean c, ClassfileFinder finder) throws Exception {
+
+search:
+		// Check all directories in source path
+		for (int i = 0; i < sourcePath.length; i++) {
+
+			// Get file name
+			File file = new File(sourcePath[i],
+			    C.encode(className, true).replace('/',
+			    Generate.FILE_SEPARATOR) + (c ? ".c" : ".h"));
+
+			// See if file exists, is normal, and is non-empty
+			if (!file.exists())
+				continue;
+			else if (!file.isFile() || file.length() == 0) {
+				file.delete();
+				continue;
+			}
+
+			// Read and verify @dep_class tags
+			Set deps = readDeps(file, "@dep_class", true);
+			for (Iterator j = deps.iterator(); j.hasNext(); ) {
+				Dep dep = (Dep)j.next();
+
+				// If tag is correct, check the next one
+				try {
+					if (finder.getClassfileHash(
+					    dep.className) == dep.hash)
+						continue;
+				} catch (ClassNotFoundException e) {
+				}
+
+				// If file can be "hidden" don't delete it
+				if (i > 0) {
+					if (verbose) {
+						System.out.println("Ignoring"
+						    + " obsolete file `"
+						    + file + "'");
+					}
+					return -1;
+				}
+
+				// Delete the file and try next directory
+				if (file.delete() && verbose) {
+					System.out.println("Removing"
+					    + " obsolete file `"
+					    + file + "'");
+				}
+				continue search;
+			}
+
+			// Looks OK
+			return i;
+		}
+
+		// Not found
+		return -1;
+	}
+
+	/**
+	 * Compile a C file into an ELF object.
+	 *
+	 * This assumes the class name contains slashes, not dots.
+	 */
+	private void compile(File sourceFile, File objectFile)
+	    throws Exception {
+
+		// Assemble gcc command
+		ArrayList args = new ArrayList(40);
+		args.add(System.getProperty("jc.gnu.compiler"));
+		args.add("-c");
+		args.add("-O2");
+		args.add("-pipe");
+		if (debugSymbols)
+			args.add("-g");
+		args.add("-fno-common");
+		args.add("-w");		// don't warn for implicit casts
+		args.add("-Wall");
+		args.add("-Waggregate-return");
+		args.add("-Wcast-align");
+		args.add("-Wcast-qual");
+		args.add("-Wchar-subscripts");
+		args.add("-Wcomment");
+		args.add("-Wformat");
+		args.add("-Wimplicit");
+		args.add("-Wmissing-declarations");
+		args.add("-Wmissing-prototypes");
+		args.add("-Wnested-externs");
+		args.add("-Wno-long-long");
+		args.add("-Wparentheses");
+		args.add("-Wpointer-arith");
+		args.add("-Wreturn-type");
+		args.add("-Wshadow");
+		args.add("-Wstrict-prototypes");
+		args.add("-Wswitch");
+		args.add("-Wtrigraphs");
+		args.add("-Wuninitialized");
+		args.add("-Wunused");
+		args.add("-Wwrite-strings");
+	//	args.add("-Werror");
+		args.add("-Wa,-W");	// avoid ".rodata' attribute warnings
+		args.add("-I" + System.getProperty("jc.include.dir"));
+		for (int i = 0; i < sourcePath.length; i++)
+			args.add("-I" + sourcePath[i]);
+		args.add("-o");
+		args.add(objectFile.toString());
+		args.add(sourceFile.toString());
+		String[] cmd = (String[])args.toArray(new String[args.size()]);
+
+		// Execute gcc command
+		boolean ok = false;
+		try {
+			exec(cmd);
+			ok = true;
+		} finally {
+			if (!ok)
+				objectFile.delete();
+		}
+	}
+
+	/**
+	 * Execute a command.
+	 */
+	private void exec(String[] cmd) throws Exception {
+
+		// Get command as a String
+		StringBuffer buf = new StringBuffer(cmd.length * 20);
+		for (int i = 0; i < cmd.length; i++) {
+			if (i > 0)
+				buf.append(' ');
+			buf.append(cmd[i]);
+		}
+		String cmdString = buf.toString();
+
+		// Print command to console in verbose mode
+		if (verbose)
+			System.out.println(buf.toString());
+
+		// Execute command
+		Process p = Runtime.getRuntime().exec(cmd, null, null);
+
+		// Copy command output to console in verbose mode
+		if (verbose) {
+			CopyOut stdout = new CopyOut(
+			    new BufferedInputStream(p.getInputStream()));
+			CopyOut stderr = new CopyOut(
+			    new BufferedInputStream(p.getErrorStream()));
+			stdout.start();
+			stderr.start();
+			stdout.join();
+			stderr.join();
+		}
+
+		// Wait for command to finish
+		int r = p.waitFor();
+		if (r != 0) {
+			throw new RuntimeException("command exited with"
+			    + " non-zero return status " + r
+			    + ": " + cmdString);
+		}
+
+		// Close streams to immediately free up file descriptors
+		p.getOutputStream().close();
+		p.getInputStream().close();
+		p.getErrorStream().close();
+	}
+
+	/**
+	 * Thread to copy output from external process to the console.
+	 */
+	private static class CopyOut extends Thread {
+		private final InputStream input;
+		CopyOut(InputStream input) {
+			this.input = input;
+		}
+		public void run() {
+			byte[] buf = new byte[1024];
+			while (true) {
+				int r;
+				try {
+					r = input.read(buf);
+				} catch (IOException e) {
+					return;
+				}
+				if (r == -1)
+					return;
+				System.out.write(buf, 0, r);
+			}
+		}
+	}
+
+	/**
+	 * Return the file that contains the C source code for the class.
+	 */
+	public File cFile(String className, int i) {
+		return new File(sourcePath[i],
+		    C.encode(className, true).replace('/',
+		    Generate.FILE_SEPARATOR) + ".c");
+	}
+
+	/**
+	 * Return the file that contains the C header source for the class.
+	 */
+	public File hFile(String className, int i) {
+		return new File(sourcePath[i],
+		    C.encode(className, true).replace('/',
+		    Generate.FILE_SEPARATOR) + ".h");
+	}
+
+	// Class dependency object
+	private static class Dep {
+		final String className;
+		final long hash;
+		Dep(String className, long hash) {
+			this.className = className;
+			this.hash = hash;
+		}
+		Dep(String className) {
+			this(className, 0);
+		}
+		public boolean equals(Object obj) {
+			if (!(obj instanceof Dep))
+				return false;
+			Dep that = (Dep)obj;
+			return this.className.equals(that.className)
+			    && this.hash == that.hash;
+		}
+		public int hashCode() {
+			return className.hashCode() ^ (int)hash;
+		}
+	}
+
+	/**
+	 * Read dependency lines from the top of a C source file.
+	 */
+	private Set readDeps(File file, String tag, boolean withHash)
+	    throws Exception {
+		HashSet deps = new HashSet();
+		BufferedReader r = new BufferedReader(
+		    new InputStreamReader(
+		    new FileInputStream(file), "8859_1"));
+		try {
+			String line;
+			while ((line = r.readLine()) != null) {
+
+				// Parse line
+				String[] toks = split(line, 4);
+
+				// Ignore blank lines
+				if (toks.length == 1 && toks[0].length() == 0)
+					continue;
+
+				// Stop at the first non //-comment
+				if (!toks[0].equals("//"))
+					break;
+
+				// Is this a tag line?
+				if (toks.length < 3 + (withHash ? 1 : 0))
+					continue;
+				if (!toks[1].equals(tag))
+					continue;
+
+				// Parse class name and optional hash
+				long hash;
+				String cname;
+				if (withHash) {
+					hash = parseHash(toks[2]);
+					cname = Generate.decode(toks[3]);
+				} else {
+					hash = 0;
+					cname = Generate.decode(toks[2]);
+				}
+
+				// Add dependency
+				deps.add(new Dep(cname, hash));
+			}
+			return deps;
+		} finally {
+			r.close();
+		}
+	}
+
+	/**
+	 * Parse an unsigned 8 byte hex value. This method is required
+	 * because Long.parseLong() only parses signed values.
+	 */
+	public long parseHash(String s) throws NumberFormatException {
+		if (s.length() > 16)
+			throw new NumberFormatException(s);
+		long val = 0;
+		for (int i = 0; i < s.length(); i++) {
+			int digit;
+			if ((digit = Character.digit(s.charAt(i), 16)) == -1)
+				throw new NumberFormatException(s);
+			val = (val << 4) | digit;
+		}
+		return val;
+	}
+
+	// Classpath doesn't support String.split() yet so we have to do this
+	private String[] split(String s, int max) {
+		ArrayList toks = new ArrayList();
+		int pos = 0;
+		for (int i = 0; i < max; i++) {
+			while (pos < s.length()
+			    && Character.isSpace(s.charAt(pos)))
+				pos++;
+			if (pos == s.length())
+				break;
+			int start = pos;
+			while (pos < s.length()
+			    && !Character.isSpace(s.charAt(pos)))
+				pos++;
+			toks.add(s.substring(start, pos));
+		}
+		toks.add("");		// stupid compat with String.split()
+		return (String[])toks.toArray(new String[toks.size()]);
+	}
+}
+
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Makefile.am
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Makefile.am?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Makefile.am (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Makefile.am Tue Oct  4 19:19:16 2005
@@ -0,0 +1,27 @@
+## $Id: Makefile.am,v 1.4 2004/12/24 21:55:56 archiecobbs Exp $
+
+SUBDIRS=	analysis escape
+
+EXTRA_DIST=	ActiveUseCheckStmt.java \
+		C.java \
+		CExpr.java \
+		CFile.java \
+		CMethod.java \
+		CStmtSwitch.java \
+		CValueSwitch.java \
+		ClassConstant.java \
+		CodeGenerator.java \
+		CodeWriter.java \
+		Constants.java \
+		DefaultMethodOptimizer.java \
+		HFile.java \
+		JCObjectGenerator.java \
+		MethodOptimizer.java \
+		NullCheckStmt.java \
+		SootCodeGenerator.java \
+		SourceFile.java \
+		SourceLocator.java \
+		StmtTagCopierSwitch.java \
+		Util.java \
+		package.html
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/MethodOptimizer.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/MethodOptimizer.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/MethodOptimizer.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/MethodOptimizer.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,57 @@
+
+//
+// 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: MethodOptimizer.java,v 1.5 2004/12/19 21:01:03 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import java.util.List;
+import java.util.Set;
+import soot.SootMethod;
+import soot.jimple.StmtBody;
+import soot.toolkits.graph.CompleteUnitGraph;
+
+/**
+ * Interface for optimizing the Jimple code associated with a method.
+ * An implementation of this interface is assocated with each
+ * {@link SootCodeGenerator SootCodeGenerator}.
+ */
+public interface MethodOptimizer {
+
+	/**
+	 * Optimize the given method's body.
+	 *
+	 * <p>
+	 * Depedencies should be added
+	 * to <code>deps</code> when the class may not be explicitly
+	 * referenced in the new body. For example, if a call to
+	 * <code>Arrays.sort()</code> were inlined, then <code>Arrays</code>
+	 * would need to be added as an explicit dependency, because the
+	 * inlined code might not explicitly refer to the <code>Arrays</code>
+	 * class.
+	 *
+	 * @param method method to optimize
+	 * @param deps set to which to add any class file dependencies
+	 *	which may not be reflected in the byte code. To add a
+	 *	dependency, add the class' {@link soot.SootClass SootClass}
+	 *	object.
+	 * @return control flow graph of optimized method body
+	 */
+	public CompleteUnitGraph optimize(SootMethod method, Set deps);
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/NullCheckStmt.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/NullCheckStmt.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/NullCheckStmt.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/NullCheckStmt.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,80 @@
+
+//
+// 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: NullCheckStmt.java,v 1.3 2004/07/16 15:11:32 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import soot.*;
+import soot.jimple.*;
+import soot.jimple.internal.JInvokeStmt;
+
+/**
+ * Jimple statement that represents a null pointer check.
+ * This is a hack, as we have to look like a normal Jimple stmt.
+ */
+public class NullCheckStmt extends JInvokeStmt {
+
+	public NullCheckStmt(Value value) {
+		super(Jimple.v().newSpecialInvokeExpr(
+		    (Local)value, getNullCheckMethod()));
+	}
+
+	public Value getNullCheckValue() {
+	    return ((InstanceInvokeExpr)getInvokeExpr()).getBase();
+	}
+
+	public void toString(UnitPrinter up)
+	{
+	    up.literal("nullcheck ");
+	    getNullCheckValue().toString(up);
+	}
+
+	public String toString()
+	{
+	    return "nullcheck " + getNullCheckValue();
+	}
+
+	// Use a method we know is always going to be available...
+	public static SootMethod getNullCheckMethod() {
+	    return Scene.v().getSootClass("java.lang.Object")
+		.getMethodByName("getClass");
+	}
+
+	public static void insertNullCheck(PatchingChain units,
+	    Stmt stmt, Value value) {
+		NullCheckStmt nullCheck = new NullCheckStmt(value);
+		units.insertBefore(nullCheck, stmt);
+		stmt.redirectJumpsToThisTo(nullCheck);
+	}
+
+	public static boolean isNullCheck(Stmt stmt) {
+
+		// Check the obvious first
+		if (stmt instanceof NullCheckStmt)
+			return true;
+
+		// It seems our NullCheckStmt's get replicated
+		// sometimes and turn into plain old InvokeStmt's
+		if (stmt instanceof InvokeStmt
+		    && stmt.getInvokeExpr().getMethod() == getNullCheckMethod())
+			return true;
+		return false;
+	}
+}
+