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;
+ }
+}
+