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 [8/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/SootCodeGenerator.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SootCodeGenerator.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SootCodeGenerator.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SootCodeGenerator.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,201 @@
+
+//
+// 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: SootCodeGenerator.java,v 1.7 2005/02/22 15:14:02 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import java.io.BufferedWriter;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import org.dellroad.jc.ClassfileFinder;
+import org.dellroad.jc.Generate;
+import org.dellroad.jc.SearchpathFinder;
+import soot.G;
+import soot.PackManager;
+import soot.PhaseOptions;
+import soot.Scene;
+import soot.SootClass;
+import soot.Transform;
+import soot.jimple.toolkits.pointer.CastCheckEliminatorDumper;
+import soot.options.Options;
+
+/**
+ * JC's default source file generator. This class generates C code by
+ * first analyzing class files using the
+ * <a href="http://www.sable.mcgill.ca/soot/">Soot</a> framework, and
+ * then converting byte code into C statements using the various other
+ * helper classes in this package.
+ */
+public class SootCodeGenerator implements CodeGenerator {
+
+	private static final String DEFAULT_METHOD_OPTIMIZER
+	    = "org.dellroad.jc.cgen.DefaultMethodOptimizer";
+
+	/**
+	 * Current class file finder. This field is made package-visible
+	 * because other classes in this package need access to it.
+	 */
+	static ClassfileFinder finder;
+
+	private final SourceLocator sourceLocator;
+	private final MethodOptimizer optimizer;
+	private final boolean includeLineNumbers;
+
+	/**
+	 * Instantiate. Only one instance of this class should
+	 * be used at a time.
+	 *
+	 * @param sourceLocator How Soot should retrieve class files,
+	 *	or <code>null</code> in which case the <code>finder</code>
+	 *	parameter to {@link #generateC generateC()} and
+	 *	{@link #generateH generateH()} must be an instance of
+	 *	{@link SearchpathFinder SearchpathFinder}.
+	 * @param optimizer Object for optimizing method bodies, or
+	 *	<code>null</code> to use the default.
+	 */
+	public SootCodeGenerator(SourceLocator sourceLocator,
+	    MethodOptimizer optimizer, boolean includeLineNumbers) {
+
+		// Get default optimizer
+		if (optimizer == null) {
+			try {
+				optimizer = (MethodOptimizer)Class.forName(
+				    System.getProperty("jc.method.optimizer",
+				      DEFAULT_METHOD_OPTIMIZER)).newInstance();
+			} catch (Exception e) {
+				throw new RuntimeException(e);
+			}
+		}
+
+		// Save parameters
+		this.sourceLocator = sourceLocator;
+		this.optimizer = optimizer;
+		this.includeLineNumbers = includeLineNumbers;
+	}
+
+	/**
+	 * Reset Soot.
+	 */
+	public void reset() {
+
+		// Reset Soot
+		G.reset();
+		System.gc();
+
+		// Set global Soot options
+		Options.v().set_keep_line_number(true);
+		Options.v().set_keep_offset(true);
+
+		// Set Jimple optimization options
+		PhaseOptions.v().setPhaseOption("jop", "enabled:true");
+		PhaseOptions.v().setPhaseOption("tag.ln", "on");
+		PhaseOptions.v().setPhaseOption("jb.lp", "on");
+		PhaseOptions.v().setPhaseOption("jap", "enabled:true");
+		PhaseOptions.v().setPhaseOption("jap.npc", "on");
+		//PhaseOptions.v().setPhaseOption("jap.abc", "with-cse:true");
+		PhaseOptions.v().setPhaseOption("jap.abc", "on");
+		PhaseOptions.v().setPhaseOption("jap.abc",
+		    "with-classfield:true");
+
+		// Include cast check elimination tagging
+		PackManager.v().getPack("jap").add(
+		    new Transform("jap.cce", CastCheckEliminatorDumper.v()));
+		PhaseOptions.v().setPhaseOption("jap.cce", "on");
+
+		// We have to force Soot to use our custom SourceLocator
+		// using a native method because Soot doesn't let you
+		if (sourceLocator != null) {
+			setField(G.v(), "instanceSourceLocator",
+			    "Lsoot/util/SourceLocator;", sourceLocator);
+		}
+	}
+
+	/**
+	 * Wrapper for {@link #genH genH()} that handles properly
+	 * configuring Soot to find class files.
+	 */
+	public final void generateH(String className,
+	    ClassfileFinder finder, OutputStream output) throws Exception {
+		if (sourceLocator != null)
+			sourceLocator.setFinder(finder);
+		else if (finder instanceof SearchpathFinder) {
+			Options.v().set_soot_classpath(
+			    ((SearchpathFinder)finder).getPath());
+		} else
+			throw new Exception("can't set Soot class finder");
+		SootCodeGenerator.finder = finder;
+		genH(className.replace('/', '.'), output);
+	}
+
+	/**
+	 * Wrapper for {@link #genC genC()} that handles properly
+	 * configuring Soot to find class files.
+	 */
+	public final void generateC(String className,
+	    ClassfileFinder finder, OutputStream output) throws Exception {
+		if (sourceLocator != null)
+			sourceLocator.setFinder(finder);
+		else if (finder instanceof SearchpathFinder) {
+			Options.v().set_soot_classpath(
+			    ((SearchpathFinder)finder).getPath());
+		} else
+			throw new Exception("can't set Soot class finder");
+		SootCodeGenerator.finder = finder;
+		genC(className.replace('/', '.'), output);
+	}
+
+	/**
+	 * Generate the C header file for the class using the Soot framework.
+	 * Subclasses should override this method instead of
+	 # {@link #generateH generateH()}.
+	 *
+	 * @param className Class name with dots instead of slashes
+	 */
+	public void genH(String className, OutputStream output)
+	    throws Exception {
+		SootClass c = Scene.v().loadClassAndSupport(className);
+		c.setApplicationClass();
+		new HFile(c,
+		    new BufferedWriter(
+		    new OutputStreamWriter(output, "8859_1"))).output();
+	}
+
+	/**
+	 * Generate the C source file for the class using the Soot framework.
+	 * Subclasses should override this method instead of
+	 * {@link #generateC generateC()}.
+	 *
+	 * @param className Class name with dots instead of slashes
+	 */
+	public void genC(String className, OutputStream output)
+	    throws Exception {
+		SootClass c = Scene.v().loadClassAndSupport(className);
+		c.setApplicationClass();
+		new CFile(c,
+		    new BufferedWriter(
+		    new OutputStreamWriter(output, "8859_1")),
+		    optimizer, includeLineNumbers).output();
+	}
+
+	// This method is required to set a custom SourceLocator in Soot
+	private static native void setField(Object o,
+	    String name, String signature, Object val);
+}
+
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SourceFile.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SourceFile.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SourceFile.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SourceFile.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,302 @@
+
+//
+// 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: SourceFile.java,v 1.7 2005/03/13 00:18:50 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import soot.*;
+import soot.tagkit.*;
+import java.util.*;
+import java.io.*;
+
+/**
+ * Represents a Java class file being converted into C source
+ * and/or header files. Contains analysis and formatting code
+ * common to both C source and C header file generation.
+ */
+public abstract class SourceFile implements Constants {
+	protected SootClass c;
+	protected String cname;
+	protected String prefix;
+	protected ArrayList superclasses;
+	protected CodeWriter out;
+	protected int numVirtualRefFields;
+	protected String sourceFile;
+	protected boolean hasStaticInitializer;
+	protected SootField[] virtualFields;
+	protected SootField[] staticFields;
+	protected SootMethod[] virtualMethods;
+	protected SootMethod[] staticMethods;
+	protected SootMethod[] constructors;
+	protected InnerClass innerClasses[];
+	protected SootClass outerClass;
+
+	static class InnerClass {
+		final SootClass inner;
+		final int flags;
+		InnerClass(String inner, int flags) {
+			this.inner = Scene.v().loadClassAndSupport(
+			    inner.replace('/', '.'));
+			this.flags = flags;
+		}
+	}
+
+	public SourceFile(SootClass c, Writer out) {
+		if (c == null)
+			throw new IllegalArgumentException();
+		this.c = c;
+		this.out = new CodeWriter(out);
+		this.cname = C.name(c);
+		this.prefix = "_jc_" + cname;
+		prepare();
+	}
+
+	private void prepare() {
+
+		// Generate list containing class and superclasses
+		superclasses = new ArrayList();
+		for (SootClass s = c; true; s = s.getSuperclass()) {
+			superclasses.add(s);
+			if (!s.hasSuperclass())
+				break;
+		}
+
+		// Get source file name
+		try {
+			sourceFile = new String(c.getTag(
+			    "SourceFileTag").getValue(), "UTF8");
+		} catch (Exception e) {
+			sourceFile = "unknown";
+		}
+
+		// Locate inner and outer classes
+		ArrayList ilist = new ArrayList();
+		for (Iterator i = c.getTags().iterator(); i.hasNext(); ) {
+			Tag nextTag = (Tag)i.next();
+			if (!(nextTag instanceof InnerClassTag))
+				continue;
+			InnerClassTag tag = (InnerClassTag)nextTag;
+			String inner = tag.getInnerClass();
+			String outer = tag.getOuterClass();
+			String myName = c.getName().replace('.', '/');
+			if (myName.equals(inner) && outer != null) {
+				outerClass = Scene.v().loadClassAndSupport(
+				    outer.replace('/', '.'));
+			} else if (myName.equals(outer) && inner != null) {
+				ilist.add(new InnerClass(inner,
+				    tag.getAccessFlags()));
+			}
+		}
+		innerClasses = (InnerClass[])ilist.toArray(
+		    new InnerClass[ilist.size()]);
+
+		// Prepare fields and methods
+		prepareFieldsAndMethods();
+	}
+
+	// Sort fields and methods into static and non-static,
+	// then sort each list alphabetically by name
+	private void prepareFieldsAndMethods() {
+
+		// Compute virtualFields
+		ArrayList temp = new ArrayList();
+		for (Iterator i = c.getFields().iterator(); i.hasNext(); ) {
+			SootField f = (SootField)i.next();
+			if (!f.isStatic())
+				temp.add(f);
+		}
+		virtualFields = (SootField[])temp.toArray(
+		    new SootField[temp.size()]);
+		Arrays.sort(virtualFields, Util.fieldComparator);
+
+		// Count number of reference virtual fields in an instance.
+		// We must include fields declared in all superclasses.
+		numVirtualRefFields = 0;
+		for (int i = 0; i < superclasses.size(); i++) {
+			SootClass sc = (SootClass)superclasses.get(i);
+			for (Iterator j = sc.getFields().iterator();
+			    j.hasNext(); ) {
+				SootField f = (SootField)j.next();
+				if (!f.isStatic() && Util.isReference(f))
+					numVirtualRefFields++;
+			}
+		}
+
+		// Compute staticFields
+		temp = new ArrayList();
+		for (Iterator i = c.getFields().iterator(); i.hasNext(); ) {
+			SootField f = (SootField)i.next();
+			if (f.isStatic())
+				temp.add(f);
+		}
+		staticFields = (SootField[])temp.toArray(
+		    new SootField[temp.size()]);
+		Arrays.sort(staticFields, Util.fieldComparator);
+
+		// Compute virtualMethods and look for <clinit>
+		temp = new ArrayList();
+		for (Iterator i = c.getMethods().iterator(); i.hasNext(); ) {
+			SootMethod m = (SootMethod)i.next();
+			if (Util.isVirtual(m))
+				temp.add(m);
+			if (Util.isClassInit(m))
+				hasStaticInitializer = true;
+		}
+		virtualMethods = (SootMethod[])temp.toArray(
+		    new SootMethod[temp.size()]);
+		Arrays.sort(virtualMethods, Util.methodComparator);
+
+		// Compute staticMethods
+		temp = new ArrayList();
+		for (Iterator i = c.getMethods().iterator(); i.hasNext(); ) {
+			SootMethod m = (SootMethod)i.next();
+			if (m.isStatic())
+				temp.add(m);
+		}
+		staticMethods = (SootMethod[])temp.toArray(
+		    new SootMethod[temp.size()]);
+		Arrays.sort(staticMethods, Util.methodComparator);
+
+		// Compute constructors
+		temp = new ArrayList();
+		for (Iterator i = c.getMethods().iterator(); i.hasNext(); ) {
+			SootMethod m = (SootMethod)i.next();
+			if (Util.isConstructor(m))
+				temp.add(m);
+		}
+		constructors = (SootMethod[])temp.toArray(
+		    new SootMethod[temp.size()]);
+		Arrays.sort(constructors, Util.methodComparator);
+	}
+
+	public void include(String filename) {
+		out.println("#include " + C.string(filename));
+	}
+
+	public void include(SootClass sc) {
+		StringBuffer b = new StringBuffer();
+		String name = sc.getName();
+		int next;
+		for (int i = 0; i < name.length(); i = next + 1) {
+			if ((next = name.indexOf('.', i)) == -1)
+				next = name.length();
+			if (i > 0)
+				b.append('/');
+			b.append(C.encode(name.substring(i, next)));
+		}
+		b.append(".h");
+		out.println("#include " + C.string(b.toString()));
+	}
+
+	public abstract void output();
+
+	public void outputInitialStuff(SootClass[] hlist,
+	    SootClass[] dlist, boolean defs) {
+
+		// Output initial comment
+//		outputCommentLine("generated by "
+//		    + this.getClass().getName() + " " + new Date()
+//		    + " (" + System.getProperty("java.vm.name") + ")");
+		String modString = Modifier.toString(c.getModifiers());
+		outputCommentLine(modString
+		    + (modString.equals("") ? "" : " ")
+		    + (c.isInterface() ? "" : "class ")
+		    + C.string(c.getName(), false));
+		out.println();
+
+		// Output classfile @dep_class tags
+		if (dlist.length > 0) {
+			Arrays.sort(dlist, Util.classComparator);
+			outputCommentLine("class file dependencies");
+			for (int i = 0; i < dlist.length; i++) {
+				outputCommentLine("@dep_class "
+				    + Long.toHexString(Util.classHash(dlist[i]))
+				    + " " + C.encode(dlist[i].getName(), true));
+			}
+			out.println();
+		}
+
+		// Output header file @dep_header tags
+		Arrays.sort(hlist, Util.classComparator);
+		if (hlist.length > 0) {
+			outputCommentLine("header file dependencies");
+			for (int i = 0; i < hlist.length; i++) {
+				outputCommentLine("@dep_header "
+				    + C.encode(hlist[i].getName(), true));
+			}
+			out.println();
+		}
+
+		// #include files: JC definitions
+		if (defs) {
+			include("jc_defs.h");
+			out.println();
+		}
+
+		// #include files: other classes
+		if (hlist.length > 0) {
+			for (int i = 0; i < hlist.length; i++)
+				include(hlist[i]);
+			out.println();
+		}
+	}
+
+	public void outputFinalStuff() {
+		out.flush();
+	}
+
+	public void outputCommentLine(String s) {
+		out.print("// ");
+		out.println(s);
+	}
+
+	public void outputBanner(String s) {
+		out.print('/');
+		for (int i = 0; i < 8; i++)
+			out.print("*********");
+		out.println();
+		out.print(" *");
+		int start = 2 + (70 - s.length()) / 2;
+		spaceFillTo(2, start);
+		out.print(s);
+		spaceFillTo(start + s.length(), 72);
+		out.println('*');
+		out.print(' ');
+		for (int i = 0; i < 8; i++)
+			out.print("*********");
+		out.println('/');
+		out.println();
+	}
+
+	public void spaceFillTo(int posn, int target) {
+		while (posn < target) {
+			int remain = target - posn;
+			int modpos = posn % 8;
+
+			if (remain >= 8 - modpos) {
+				out.print('\t');
+				posn += 8 - modpos;
+			} else {
+				out.print(' ');
+				posn++;
+			}
+		}
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SourceLocator.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SourceLocator.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SourceLocator.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/SourceLocator.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,61 @@
+
+//
+// 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: SourceLocator.java,v 1.1.1.1 2004/02/20 05:15:26 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import soot.Singletons;
+import soot.util.ClassInputStream;
+import org.dellroad.jc.ClassfileFinder;
+
+/**
+ * Implementation of Soot's {@link soot.util.SourceLocator} interface
+ * used by the {@link SootCodeGenerator} class. In order for
+ * Soot to pick up and analyze the correct class files, we must
+ * provide our own implementation which retrieves them from the
+ * JC virtual machine. This ensures that no matter how any particular
+ * ClassLoader retrieves a class file, that exact same class file
+ * will be made available to Soot for analysis.
+ */
+public class SourceLocator extends soot.util.SourceLocator {
+
+	private ClassfileFinder finder;
+
+	public SourceLocator(Singletons.Global g) {
+		super(g);
+	}
+
+	public void setFinder(ClassfileFinder finder) {
+		this.finder = finder;
+	}
+
+	/**
+	 * Retrieve the classfile contents for the named class,
+	 * as loaded by the ClassLoader associated with this object.
+	 */
+	public InputStream getInputStreamOf(String className)
+	    throws ClassNotFoundException {
+		return new ClassInputStream(
+		    new ByteArrayInputStream(
+		    finder.getClassfile(className)));
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/StmtTagCopierSwitch.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/StmtTagCopierSwitch.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/StmtTagCopierSwitch.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/StmtTagCopierSwitch.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,72 @@
+
+//
+// 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: StmtTagCopierSwitch.java,v 1.2 2004/12/21 01:54:03 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import soot.jimple.*;
+
+/**
+ * Copies tags from Jimple Stmt's to ValueBoxes.
+ * All tags are copied.
+ */
+public class StmtTagCopierSwitch extends AbstractStmtSwitch {
+
+	public void caseInvokeStmt(InvokeStmt stmt) {
+		stmt.getInvokeExprBox().addAllTagsOf(stmt);
+	}
+
+	public void caseAssignStmt(AssignStmt stmt) {
+		stmt.getRightOpBox().addAllTagsOf(stmt);
+		stmt.getLeftOpBox().addAllTagsOf(stmt);
+	}
+
+	public void caseIdentityStmt(IdentityStmt stmt) {
+		stmt.getRightOpBox().addAllTagsOf(stmt);
+	}
+
+	public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
+		stmt.getOpBox().addAllTagsOf(stmt);
+	}
+
+	public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
+		stmt.getOpBox().addAllTagsOf(stmt);
+	}
+
+	public void caseIfStmt(IfStmt stmt) {
+		stmt.getConditionBox().addAllTagsOf(stmt);
+	}
+
+	public void caseLookupSwitchStmt(LookupSwitchStmt stmt) {
+		stmt.getKeyBox().addAllTagsOf(stmt);
+	}
+
+	public void caseReturnStmt(ReturnStmt stmt) {
+		stmt.getOpBox().addAllTagsOf(stmt);
+	}
+
+	public void caseTableSwitchStmt(TableSwitchStmt stmt) {
+		stmt.getKeyBox().addAllTagsOf(stmt);
+	}
+
+	public void caseThrowStmt(ThrowStmt stmt) {
+		stmt.getOpBox().addAllTagsOf(stmt);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Util.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Util.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Util.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/Util.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,611 @@
+
+//
+// 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: Util.java,v 1.6 2005/03/13 00:18:50 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen;
+
+import soot.*;
+import soot.tagkit.*;
+import soot.jimple.*;
+import java.util.*;
+import java.io.*;
+import org.dellroad.jc.Generate;
+
+/**
+ * Various utility stuff used when analyzing class files and generating code.
+ */
+public class Util {
+
+	public static final int ACC_SUPER = 0x0020;
+
+	private Util() {
+	}
+
+	/**
+	 * Utility class that passes the appropriate string ("byte",
+	 * "char", etc.) to the {@link #prim prim()} method depending
+	 * on the primitive type.
+	 */
+	public static abstract class PrimTypeSwitch extends TypeSwitch {
+		public void caseBooleanType(BooleanType t) {
+			prim("boolean");
+		}
+		public void caseByteType(ByteType t) {
+			prim("byte");
+		}
+		public void caseCharType(CharType t) {
+			prim("char");
+		}
+		public void caseShortType(ShortType t) {
+			prim("short");
+		}
+		public void caseIntType(IntType t) {
+			prim("int");
+		}
+		public void caseLongType(LongType t) {
+			prim("long");
+		}
+		public void caseFloatType(FloatType t) {
+			prim("float");
+		}
+		public void caseDoubleType(DoubleType t) {
+			prim("double");
+		}
+		public void caseVoidType(VoidType t) {
+			prim("void");
+		}
+		public abstract void prim(String ptype);
+		public void defaultCase(Type t) {
+			Util.panic("non-primitive type " + t);
+		}
+	}
+
+	/**
+	 * Utility class that computes ordering preference in a C structure
+	 * of the various types. We want longer types first, then shorter
+	 * types, to avoid "holes". We always sort reference types first.
+	 */
+	public static abstract class OrderTypeSwitch extends TypeSwitch {
+		public void caseBooleanType(BooleanType t) {
+			order(4);
+		}
+		public void caseByteType(ByteType t) {
+			order(4);
+		}
+		public void caseCharType(CharType t) {
+			order(3);
+		}
+		public void caseShortType(ShortType t) {
+			order(3);
+		}
+		public void caseIntType(IntType t) {
+			order(2);
+		}
+		public void caseFloatType(FloatType t) {
+			order(2);
+		}
+		public void caseLongType(LongType t) {
+			order(1);
+		}
+		public void caseDoubleType(DoubleType t) {
+			order(1);
+		}
+		public void defaultCase(Type t) {
+			order(0);
+		}
+		public abstract void order(int order);
+	}
+
+	/**
+	 * Return the _JC_TYPE_* macro appropriate for the given type.
+	 */
+	public static String _JC_TYPE(Type t) {
+		if (isReference(t))
+			return "_JC_TYPE_REFERENCE";
+		TypeSwitch ts = new Util.PrimTypeSwitch() {
+		    public void prim(String name) {
+			setResult("_JC_TYPE_" + name.toUpperCase());
+		    }
+		};
+		t.apply(ts);
+		return (String)ts.getResult();
+	}
+
+	/**
+	 * Sorts Strings in the same way that strcmp() does on their
+	 * UTF-8 encodings.
+	 */
+	public static final Comparator utf8Comparator = new Comparator() {
+		public int compare(Object x, Object y) {
+			byte[] b1 = utf8Encode((String)x);
+			byte[] b2 = utf8Encode((String)y);
+			for (int i = 0; i < b1.length && i < b2.length; i++) {
+				int diff = (b1[i] & 0xff) - (b2[i] & 0xff);
+				if (diff != 0)
+					return diff;
+			}
+			return b1.length - b2.length;
+		}
+	};
+
+	/**
+	 * Sorts methods by name, then by signature.
+	 */
+	public static final Comparator methodComparator = new Comparator() {
+		public int compare(Object x, Object y) {
+			SootMethod mx = (SootMethod)x;
+			SootMethod my = (SootMethod)y;
+			int diff;
+			if ((diff = utf8Comparator.compare(mx.getName(),
+			    my.getName())) != 0)
+				return diff;
+			return utf8Comparator.compare(
+			    signature(mx), signature(my));
+		}
+	};
+
+	/**
+	 * Sorts local variables by name.
+	 */
+	public static final Comparator localComparator = new Comparator() {
+		public int compare(Object x, Object y) {
+			Local lx = (Local)x;
+			Local ly = (Local)y;
+			return lx.getName().compareTo(ly.getName());
+		}
+	};
+
+	/**
+	 * Sorts fields by staticness, basic type, name, then signature.
+	 */
+	public static final Comparator fieldComparator = new Comparator() {
+		private int ots_order;
+		private final OrderTypeSwitch ots = new OrderTypeSwitch() {
+			public void order(int order) {
+				ots_order = order;
+			}
+		};
+		private int getOrder(Type t) {
+			t.apply(ots);
+			return ots_order;
+		}
+		public int compare(Object x, Object y) {
+			SootField fx = (SootField)x;
+			SootField fy = (SootField)y;
+			int diff;
+
+			if (fx.isStatic() != fy.isStatic())
+				return fx.isStatic() ? -1 : 1;
+			if ((diff = getOrder(fx.getType())
+			    - getOrder(fy.getType())) != 0)
+				return diff;
+			if ((diff = utf8Comparator.compare(fx.getName(),
+			    fy.getName())) != 0)
+				return diff;
+			return utf8Comparator.compare(signature(fx),
+			    signature(fy));
+		}
+	};
+
+	/**
+	 * Sorts classes by their names' UTF-8 encoding.
+	 */
+	public static final Comparator classComparator = new Comparator() {
+		public int compare(Object x, Object y) {
+			SootClass cx = (SootClass)x;
+			SootClass cy = (SootClass)y;
+			return utf8Comparator.compare(
+			    cx.getName(), cy.getName());
+		}
+	};
+
+	public static boolean isReference(SootClass c) {
+		return (isReference(c.getType()));
+	}
+
+	public static boolean isReference(SootField f) {
+		return (isReference(f.getType()));
+	}
+
+	public static boolean isReference(SootMethod m) {
+		return (isReference(m.getReturnType()));
+	}
+
+	public static boolean isPrimitive(Type type) {
+		return type instanceof PrimType || type instanceof VoidType;
+	}
+
+	public static boolean isPrimitiveArray(Type type) {
+		return type instanceof ArrayType
+		    && isPrimitive(((ArrayType)type).getElementType());
+	}
+
+	public static boolean isFinal(SootClass c) {
+		return Modifier.isFinal(c.getModifiers());
+	}
+
+	public static boolean isFinal(SootField f) {
+		return Modifier.isFinal(f.getModifiers());
+	}
+
+	public static boolean isFinal(SootMethod m) {
+		return Modifier.isFinal(m.getModifiers());
+	}
+
+	public static boolean isVirtual(SootMethod m) {
+		return !m.isStatic() && m.getName().charAt(0) != '<';
+	}
+
+	public static boolean isConstructor(SootMethod m) {
+		return !m.isStatic() && m.getName().equals("<init>");
+	}
+
+	public static boolean isClassInit(SootMethod m) {
+		return m.isStatic() && m.getName().equals("<clinit>");
+	}
+
+	public static boolean hasSubtypes(SootClass c) {
+		return !isFinal(c);
+	}
+
+	public static boolean hasSubtypes(SootField f) {
+		return !isFinal(f);
+	}
+
+	public static boolean hasSubtypes(SootMethod m) {
+		return !isFinal(m);
+	}
+
+	public static boolean hasSubtypes(Type t) {
+		if (isPrimitive(t))
+			return false;
+		if (t instanceof RefType) {
+			SootClass c = ((RefType)t).getSootClass();
+			if (c.isInterface())
+				return true;
+			return !isFinal(c);
+		}
+		return hasSubtypes(((ArrayType)t).baseType);
+	}
+
+	/**
+	 * Return whether type <code>t</code> is a reference type or not.
+	 * <code>t</code> must be a normal Java type, i.e., a type that can
+	 * be the type of a variable.
+	 */
+	public static boolean isReference(Type t) {
+		return (t instanceof RefLikeType);
+	}
+
+	public static char typeLetter(Type t) {
+		TypeSwitch ts = new TypeSwitch() {
+		    public void caseBooleanType(BooleanType t) {
+			    setResult("z");
+		    }
+		    public void caseByteType(ByteType t) {
+			    setResult("b");
+		    }
+		    public void caseCharType(CharType t) {
+			    setResult("c");
+		    }
+		    public void caseShortType(ShortType t) {
+			    setResult("s");
+		    }
+		    public void caseIntType(IntType t) {
+			    setResult("i");
+		    }
+		    public void caseLongType(LongType t) {
+			    setResult("j");
+		    }
+		    public void caseFloatType(FloatType t) {
+			    setResult("f");
+		    }
+		    public void caseDoubleType(DoubleType t) {
+			    setResult("d");
+		    }
+		    public void caseArrayType(ArrayType t) {
+			    setResult("l");
+		    }
+		    public void caseRefType(RefType t) {
+			    setResult("l");
+		    }
+		    public void defaultCase(Type t) {
+			    Util.panic("bogus type " + t);
+		    }
+		};
+		t.apply(ts);
+		return ((String)ts.getResult()).charAt(0);
+	}
+
+	public static String fieldDescriptor(Type t) {
+		TypeSwitch ts = new TypeSwitch() {
+		    public void caseBooleanType(BooleanType t) {
+			    setResult("Z");
+		    }
+		    public void caseByteType(ByteType t) {
+			    setResult("B");
+		    }
+		    public void caseCharType(CharType t) {
+			    setResult("C");
+		    }
+		    public void caseShortType(ShortType t) {
+			    setResult("S");
+		    }
+		    public void caseIntType(IntType t) {
+			    setResult("I");
+		    }
+		    public void caseLongType(LongType t) {
+			    setResult("J");
+		    }
+		    public void caseFloatType(FloatType t) {
+			    setResult("F");
+		    }
+		    public void caseDoubleType(DoubleType t) {
+			    setResult("D");
+		    }
+		    public void caseArrayType(ArrayType t) {
+			    setResult("["
+				+ fieldDescriptor(t.getElementType()));
+		    }
+		    public void caseRefType(RefType t) {
+			    setResult("L"
+				+ t.getSootClass().getName().replace('.', '/')
+				+ ";");
+		    }
+		    public void caseVoidType(VoidType t) {
+			    setResult("V");
+		    }
+		    public void defaultCase(Type t) {
+			    Util.panic("bogus type " + t);
+		    }
+		};
+		t.apply(ts);
+		return (String)ts.getResult();
+	}
+
+	public static String typeWord(Type t) {
+		if (Util.isReference(t))
+			return "object";
+		TypeSwitch ts = new Util.PrimTypeSwitch() {
+		    public void prim(String name) {
+			setResult(name);
+		    }
+		};
+		t.apply(ts);
+		return (String)ts.getResult();
+	}
+
+	public static String signature(SootField f) {
+		return fieldDescriptor(f.getType());
+	}
+
+	public static String signature(SootMethod m) {
+		StringBuffer b = new StringBuffer(24);
+		b.append('(');
+		for (int i = 0; i < m.getParameterCount(); i++)
+			b.append(fieldDescriptor(m.getParameterType(i)));
+		b.append(')');
+		b.append(fieldDescriptor(m.getReturnType()));
+		return b.toString();
+	}
+
+	public static String fullSignature(SootMethod m) {
+		return m.getName() + signature(m);
+	}
+
+	public static String paramTypes(SootMethod m) {
+		StringBuffer b = new StringBuffer();
+		for (int i = 0; i < m.getParameterCount(); i++) {
+			b.append(fieldDescriptor(
+			    m.getParameterType(i)).charAt(0));
+		}
+		b.append(fieldDescriptor(m.getReturnType()));
+		return b.toString();
+	}
+
+	public static long hash(String s) {
+		return Generate.hash(new ByteArrayInputStream(utf8Encode(s)));
+	}
+
+	public static long sigHash(SootMethod m) {
+		return hash(fullSignature(m));
+	}
+
+	public static long classHash(SootClass sc) {
+		try {
+			return SootCodeGenerator.finder.getClassfileHash(
+			    sc.getName().replace('.', '/'));
+		} catch (ClassNotFoundException e) {
+			throw new RuntimeException(e);	// should never happen
+		}
+	}
+
+	/**
+	 * Determine if an INVOKESPECIAL can be implemented
+	 * like the old INVOKENONVIRTUAL.
+	 */
+	public static boolean isNonvirtual(SpecialInvokeExpr v,
+	    SootMethod callingMethod) {
+
+		// Get info
+		SootMethod targetMethod = v.getMethod();
+		SootClass callingClass = callingMethod.getDeclaringClass();
+
+		// Check the easy stuff first
+		if (targetMethod.getName().equals("<init>")
+		    || targetMethod.isPrivate()
+		    || (callingClass.getModifiers() & Util.ACC_SUPER) == 0)
+			return true;
+
+		// Determine if called method's class is a superclass
+		boolean isSuperclass = false;
+		SootClass calledClass = targetMethod.getDeclaringClass();
+		for (SootClass cls = callingClass; cls.hasSuperclass(); ) {
+			cls = cls.getSuperclass();
+			if (cls.equals(calledClass))
+				return false;
+		}
+
+		// OK
+		return true;
+	}
+
+	/**
+	 * Get the instanceof hash table hash.
+	 */
+	public static int instanceofHash(SootClass sc) {
+		return ((int)classHash(sc) & 0x7fffffff)
+		    % Constants.INSTANCEOF_HASHSIZE;
+	}
+
+	/**
+	 * Get the interface method hash table hash.
+	 */
+	public static int imethodHash(SootMethod m) {
+		return ((int)sigHash(m) & 0x7fffffff)
+		    % Constants.IMETHOD_HASHSIZE;
+	}
+
+	public static String sigHashString(SootMethod m) {
+		long hash = sigHash(m);
+		String s = Long.toHexString(hash);
+		if ((hash & 0xf000000000000000L) != 0)
+			return s;
+		StringBuffer b = new StringBuffer(s);
+		while (b.length() < 16)
+			b.insert(0, '0');
+		return b.toString();
+	}
+
+	/**
+	 * Find a method declared by a SootClass or any of its superclasses.
+	 */
+	public static SootMethod findMethod(SootClass c, String subSig) {
+		for (SootClass oc = c; true; c = c.getSuperclass()) {
+			try {
+				return c.getMethod(subSig);
+			} catch (RuntimeException e) {
+			}
+			if (!c.hasSuperclass()) {
+				throw new RuntimeException("no such method in "
+				    + "class " + oc.getName() + ": " + subSig);
+			}
+		}
+	}
+
+	public static Set getAllInterfaces(SootClass c) {
+		HashSet set = new HashSet();
+		addInterfaces(c, set);
+		return set;
+	}
+
+	private static void addInterfaces(SootClass c, Set set) {
+		if (c.isInterface())
+			set.add(c);
+		/* else */ if (c.hasSuperclass())
+			addInterfaces(c.getSuperclass(), set);
+		for (Iterator i = c.getInterfaces().iterator(); i.hasNext(); )
+			addInterfaces((SootClass)i.next(), set);
+	}
+
+	public static Set getAllSupertypes(SootClass c) {
+		HashSet set = new HashSet();
+		addSupertypes(c, set);
+		return set;
+	}
+
+	public static void addSupertypes(SootClass cls, Set set) {
+
+		// Add this class
+		set.add(cls);
+
+		// Recurse on superclass
+		if (cls.hasSuperclass()) {
+			SootClass superclass = cls.getSuperclass();
+			addSupertypes(superclass, set);
+		}
+
+		// Recurse on superinterfaces
+		for (Iterator i = cls.getInterfaces().iterator();
+		    i.hasNext(); ) {
+			SootClass superinterface = (SootClass)i.next();
+			addSupertypes(superinterface, set);
+		}
+	}
+
+	public static void require(boolean value) {
+		require(value, "assertion failure");
+	}
+
+	/**
+	 * Poor man's assert().
+	 */
+	public static void require(boolean value, String msg) {
+		if (!value)
+			throw new RuntimeException(msg);
+	}
+
+	/**
+	 * This method is required to work around a stupid bug
+	 * in Sun's JDK String.getBytes("UTF-8") (bug #4628881).
+	 */
+	public static byte[] utf8Encode(String s) {
+		final char[] chars = s.toCharArray();
+		int elen;
+
+		// Compute encoded length
+		elen = 0;
+		for (int i = 0; i < s.length(); i++) {
+			int ch = chars[i];
+			if (ch >= 0x0001 && ch <= 0x007f)
+				elen++;
+			else if (ch == 0x0000 || (ch >= 0x0080 && ch <= 0x07ff))
+				elen += 2;
+			else
+				elen += 3;
+		}
+
+		// Do the actual encoding
+		byte[] data = new byte[elen];
+		elen = 0;
+		for (int i = 0; i < s.length(); i++) {
+			int ch = chars[i];
+			if (ch >= 0x0001 && ch <= 0x007f)
+				data[elen++] = (byte)ch;
+			else if (ch == 0x0000
+			    || (ch >= 0x0080 && ch <= 0x07ff)) {
+				data[elen++]
+				    = (byte)(0xc0 | ((ch >> 6) & 0x1f));
+				data[elen++] = (byte)(0x80 | (ch & 0x3f));
+			} else {
+				data[elen++]
+				    = (byte)(0xe0 | ((ch >> 12) & 0x0f));
+				data[elen++]
+				    = (byte)(0x80 | ((ch >> 6) & 0x3f));
+				data[elen++] = (byte)(0x80 | (ch & 0x3f));
+			}
+		}
+		return data;
+	}
+
+	public static void panic(String msg) {
+		throw new RuntimeException("Panic: " + msg);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseAnalysis.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseAnalysis.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseAnalysis.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseAnalysis.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,129 @@
+
+//
+// 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: ActiveUseAnalysis.java,v 1.3 2004/12/24 21:55:56 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.analysis;
+
+import java.util.Iterator;
+import org.dellroad.jc.cgen.ActiveUseCheckStmt;
+import org.dellroad.jc.cgen.Util;
+import soot.Body;
+import soot.Scene;
+import soot.SootClass;
+import soot.Unit;
+import soot.ValueBox;
+import soot.jimple.Stmt;
+import soot.toolkits.graph.CompleteUnitGraph;
+import soot.toolkits.graph.UnitGraph;
+import soot.toolkits.scalar.ArraySparseSet;
+import soot.toolkits.scalar.FlowSet;
+import soot.toolkits.scalar.ForwardFlowAnalysis;
+
+/**
+ * Analysis used by {@link ActiveUseTagger ActiveUseTagger}.
+ */
+public class ActiveUseAnalysis extends ForwardFlowAnalysis {
+
+	private final UnitGraph graph;
+
+	/**
+	 * Equivalent to
+	 * <code>ActiveUseAnalysis(new CompleteUnitGraph(body))</code>.
+	 *
+	 * @param body method body to analyze
+	 */
+	public ActiveUseAnalysis(Body body) {
+		this(new CompleteUnitGraph(body));
+	}
+
+	/**
+	 * Do active use analysis on body using the supplied unit graph.
+	 *
+	 * @param graph method body to analyze
+	 */
+	public ActiveUseAnalysis(UnitGraph graph) {
+		super(graph);
+		this.graph = graph;
+		doAnalysis();
+	}
+
+	/**
+	 * Determine if a first active use check for class <code>cl</code>
+	 * would be needed before executing <code>unit</code>.
+	 */
+	public boolean isCheckNeeded(Unit unit, SootClass cl) {
+		FlowSet inSet = (FlowSet)unitToBeforeFlow.get(unit);
+		return !inSet.contains(cl);
+	}
+
+	protected Object entryInitialFlow() {
+		ArraySparseSet set = new ArraySparseSet();
+		addTransitive(set, graph.getBody()
+		    .getMethod().getDeclaringClass());
+		addTransitive(set, Scene.v().getSootClass("java.lang.Class"));
+		return set;
+	}
+
+	protected Object newInitialFlow() {
+		return new ArraySparseSet();
+	}
+
+	protected void flowThrough(Object in, Object obj, Object out) {
+		Stmt stmt = (Stmt)obj;
+		FlowSet inFlow = (FlowSet)in;
+		FlowSet outFlow = (FlowSet)out;
+		inFlow.copy(outFlow);
+		if (ActiveUseCheckStmt.isActiveUseCheck(stmt)) {
+			addTransitive(outFlow,
+			    ActiveUseCheckStmt.getSootClass(stmt));
+			return;
+		}
+		ActiveUseValueSwitch sw = new ActiveUseValueSwitch();
+		for (Iterator i = stmt.getUseBoxes().iterator();
+		    i.hasNext(); ) {
+			((ValueBox)i.next()).getValue().apply(sw);
+			SootClass cl = (SootClass)sw.getResult();
+			if (cl != null)
+				addTransitive(outFlow, cl);
+		}
+	}
+
+	protected void merge(Object in1, Object in2, Object out) {
+		FlowSet inSet1 = (FlowSet)in1;
+		FlowSet inSet2 = (FlowSet)in2;
+		FlowSet outSet = (FlowSet)out;
+		inSet1.intersection(inSet2, outSet);
+	}
+
+	protected void copy(Object src, Object dst) {
+		FlowSet srcSet = (FlowSet)src;
+		FlowSet dstSet = (FlowSet)dst;
+		srcSet.copy(dstSet);
+	}
+
+	// Add class and all superclasses
+	private void addTransitive(FlowSet set, SootClass cl) {
+		set.add(cl);
+		while (cl.hasSuperclass()) {
+			cl = cl.getSuperclass();
+			set.add(cl);
+		}
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseTag.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseTag.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseTag.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseTag.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,61 @@
+
+//
+// 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: ActiveUseTag.java,v 1.1 2004/12/19 21:01:04 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.analysis;
+
+import soot.tagkit.Tag;
+
+/**
+ * Tag for ``first active use'' class initialization checks.
+ */
+public class ActiveUseTag implements Tag {
+
+	private final static String NAME = "ActiveUseTag";
+
+	private final static ActiveUseTag NEEDED = new ActiveUseTag(true);
+	private final static ActiveUseTag NOT_NEEDED = new ActiveUseTag(false);
+
+	private final boolean checkNeeded;
+
+	public ActiveUseTag(boolean checkNeeded) {
+		this.checkNeeded = checkNeeded;
+	}
+
+	public boolean isCheckNeeded() {
+		return checkNeeded;
+	}
+
+	public byte[] getValue() {
+		return new byte[] { checkNeeded ? (byte)1 : (byte)0 };
+	}
+
+	public String getName() {
+		return NAME;
+	}
+
+	public String toString() {
+		return NAME;
+	}
+
+	public static ActiveUseTag v(boolean checkNeeded) {
+		return checkNeeded ? NEEDED : NOT_NEEDED;
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseTagger.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseTagger.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseTagger.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseTagger.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,90 @@
+
+//
+// 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: ActiveUseTagger.java,v 1.2 2004/12/24 21:55:56 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.analysis;
+
+import java.util.Iterator;
+import org.dellroad.jc.cgen.Util;
+import org.dellroad.jc.cgen.ActiveUseCheckStmt;
+import soot.Body;
+import soot.SootClass;
+import soot.SootField;
+import soot.Value;
+import soot.ValueBox;
+import soot.jimple.*;
+import soot.Unit;
+import soot.toolkits.graph.UnitGraph;
+
+/**
+ * Tags static field and method references which are known to not
+ * be the first ``active use'' of the associated class, and so for which
+ * it is not necessary to check if the class needs to be initialized.
+ */
+public class ActiveUseTagger {
+
+	private final ActiveUseAnalysis analysis;
+
+	public ActiveUseTagger(Body body) {
+		analysis = new ActiveUseAnalysis(body);
+		tag(body);
+	}
+
+	public ActiveUseTagger(UnitGraph graph) {
+		analysis = new ActiveUseAnalysis(graph);
+		tag(graph.getBody());
+	}
+
+	public ActiveUseAnalysis getAnalysis() {
+		return analysis;
+	}
+
+	private void tag(Body body) {
+		for (Iterator i = body.getUnits().iterator(); i.hasNext(); ) {
+			Stmt stmt = (Stmt)i.next();
+			if (stmt.containsInvokeExpr())
+				tagInvoke(stmt, stmt.getInvokeExprBox());
+			if (stmt.containsFieldRef())
+				tagField(stmt, stmt.getFieldRefBox());
+		}
+	}
+
+	private void tagInvoke(Stmt stmt, ValueBox box) {
+		Value value = box.getValue();
+		if (!(value instanceof StaticInvokeExpr))
+			return;
+		StaticInvokeExpr expr = (StaticInvokeExpr)value;
+		SootClass cl = expr.getMethod().getDeclaringClass();
+		if (ActiveUseCheckStmt.isActiveUseCheck(stmt))
+			cl = ActiveUseCheckStmt.getSootClass(stmt);
+		if (!analysis.isCheckNeeded(stmt, cl))
+			box.addTag(ActiveUseTag.v(false));
+	}
+
+	private void tagField(Stmt stmt, ValueBox box) {
+		Value value = box.getValue();
+		if (!(value instanceof FieldRef))
+			return;
+		SootField field = ((FieldRef)value).getField();
+		if (field.isStatic()
+		    && !analysis.isCheckNeeded(stmt, field.getDeclaringClass()))
+			box.addTag(ActiveUseTag.v(false));
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseValueSwitch.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseValueSwitch.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseValueSwitch.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ActiveUseValueSwitch.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,62 @@
+
+//
+// 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: ActiveUseValueSwitch.java,v 1.2 2004/12/22 23:39:06 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.analysis;
+
+import soot.jimple.*;
+import soot.grimp.AbstractGrimpValueSwitch;
+import soot.grimp.NewInvokeExpr;
+import soot.toolkits.scalar.FlowSet;
+
+/**
+ * Determine the SootClass which will definitely be initialized after
+ * evaluating the value, if any.
+ */
+public class ActiveUseValueSwitch extends AbstractGrimpValueSwitch {
+
+	public void caseNewInvokeExpr(NewInvokeExpr v) {
+		setResult(v.getMethod().getDeclaringClass());
+	}
+
+	public void caseSpecialInvokeExpr(SpecialInvokeExpr v) {
+		setResult(v.getMethod().getDeclaringClass());
+	}
+
+	public void caseStaticInvokeExpr(StaticInvokeExpr v) {
+		setResult(v.getMethod().getDeclaringClass());
+	}
+
+	public void caseVirtualInvokeExpr(VirtualInvokeExpr v) {
+		setResult(v.getMethod().getDeclaringClass());
+	}
+
+	public void caseNewExpr(NewExpr v) {
+		setResult(v.getBaseType().getSootClass());
+	}
+
+	public void caseInstanceFieldRef(InstanceFieldRef v) {
+		setResult(v.getField().getDeclaringClass());
+	}
+
+	public void caseStaticFieldRef(StaticFieldRef v) {
+		setResult(v.getField().getDeclaringClass());
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/FinalizeDetector.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/FinalizeDetector.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/FinalizeDetector.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/FinalizeDetector.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,48 @@
+
+//
+// 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: FinalizeDetector.java,v 1.1 2004/12/17 15:35:46 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.analysis;
+
+import java.util.*;
+import org.dellroad.jc.cgen.*;
+import soot.*;
+import soot.jimple.*;
+
+/**
+ * Instance of this class detect 'new' expressions of objects that
+ * override finalize(). The result is either <code>Boolean.TRUE</code>
+ * or <code>Boolean.FALSE</code>.
+ */
+public class FinalizeDetector extends AbstractJimpleValueSwitch {
+
+	public void caseNewExpr(NewExpr v) {
+		SootClass sc = v.getBaseType().getSootClass();
+		SootMethod finalize = sc.getMethod("finalize",
+		    Collections.EMPTY_LIST, VoidType.v());
+		setResult(Boolean.valueOf(
+		    !finalize.getDeclaringClass().getName()
+		      .equals("java.lang.Object")));
+	}
+
+	public void defaultCase(Object obj) {
+		setResult(Boolean.FALSE);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/FollowsAnalysis.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/FollowsAnalysis.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/FollowsAnalysis.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/FollowsAnalysis.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,87 @@
+
+//
+// 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: FollowsAnalysis.java,v 1.2 2004/12/19 21:01:04 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.analysis;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import soot.Body;
+import soot.Unit;
+import soot.toolkits.graph.CompleteUnitGraph;
+import soot.toolkits.scalar.ArraySparseSet;
+import soot.toolkits.scalar.FlowSet;
+import soot.toolkits.scalar.ForwardFlowAnalysis;
+
+/**
+ * Analysis that determines which statements can be executed
+ * after which other statements.
+ */
+public class FollowsAnalysis extends ForwardFlowAnalysis {
+
+	public FollowsAnalysis(Body body) {
+		super(new CompleteUnitGraph(body));
+		doAnalysis();
+	}
+
+	public FollowsAnalysis(CompleteUnitGraph graph) {
+		super(graph);
+		doAnalysis();
+	}
+
+	/**
+	 * Determine if <code>after</code> can execute after
+	 * <code>before</code>.
+	 */
+	public boolean canFollow(Unit before, Unit after) {
+		FlowSet inSet = (FlowSet)unitToBeforeFlow.get(after);
+		return inSet.contains(before);
+	}
+
+	protected Object entryInitialFlow() {
+		return new ArraySparseSet();
+	}
+
+	protected Object newInitialFlow() {
+		return new ArraySparseSet();
+	}
+
+	protected void flowThrough(Object in, Object stmt, Object out) {
+		FlowSet inFlow = (FlowSet)in;
+		FlowSet outFlow = (FlowSet)out;
+		inFlow.copy(outFlow);
+		outFlow.add(stmt);
+	}
+
+	protected void merge(Object in1, Object in2, Object out) {
+		FlowSet inSet1 = (FlowSet)in1;
+		FlowSet inSet2 = (FlowSet)in2;
+		FlowSet outSet = (FlowSet)out;
+		inSet1.union(inSet2, outSet);
+	}
+
+	protected void copy(Object src, Object dst) {
+		FlowSet srcSet = (FlowSet)src;
+		FlowSet dstSet = (FlowSet)dst;
+		srcSet.copy(dstSet);
+	}
+
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/Makefile.am
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/Makefile.am?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/Makefile.am (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/Makefile.am Tue Oct  4 19:19:16 2005
@@ -0,0 +1,12 @@
+## $Id: Makefile.am,v 1.5 2005/02/20 21:14:31 archiecobbs Exp $
+
+EXTRA_DIST=	ActiveUseAnalysis.java \
+		ActiveUseTag.java \
+		ActiveUseTagger.java \
+		ActiveUseValueSwitch.java \
+		FinalizeDetector.java \
+		FollowsAnalysis.java \
+		ReferenceDetector.java \
+		TypeAnalysis.java \
+		package.html
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ReferenceDetector.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ReferenceDetector.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ReferenceDetector.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/ReferenceDetector.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,54 @@
+
+//
+// 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: ReferenceDetector.java,v 1.1 2004/12/17 15:35:46 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.analysis;
+
+import java.util.*;
+import org.dellroad.jc.cgen.*;
+import soot.*;
+import soot.jimple.*;
+
+/**
+ * Instances of this class detect 'new' expressions of
+ * objects that subclass <code>java.lang.ref.Reference</code>.
+ * The result is either <code>Boolean.TRUE</code>
+ * or <code>Boolean.FALSE</code>.
+ */
+public class ReferenceDetector extends AbstractJimpleValueSwitch {
+
+	public void caseNewExpr(NewExpr v) {
+		SootClass sc = v.getBaseType().getSootClass();
+		while (true) {
+			if (sc.getName().equals("java.lang.ref.Reference")) {
+				setResult(Boolean.TRUE);
+				return;
+			}
+			if (!sc.hasSuperclass())
+				break;
+			sc = sc.getSuperclass();
+		}
+		setResult(Boolean.FALSE);
+	}
+
+	public void defaultCase(Object obj) {
+		setResult(Boolean.FALSE);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/TypeAnalysis.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/TypeAnalysis.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/TypeAnalysis.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/TypeAnalysis.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,89 @@
+
+//
+// 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: TypeAnalysis.java,v 1.6 2005/03/19 22:18:20 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.analysis;
+
+import java.util.*;
+import org.dellroad.jc.cgen.Util;
+import soot.*;
+import soot.jimple.*;
+import soot.toolkits.scalar.*;
+
+/**
+ * Determines the run-time type of a reference local as best we can based on
+ * information provided by a {@link LocalDefs LocalDefs} object.
+ */
+public class TypeAnalysis {
+
+	private final LocalDefs localDefs;
+
+	private final AbstractJimpleValueSwitch vs
+	    = new AbstractJimpleValueSwitch() {
+		public void caseNewArrayExpr(NewArrayExpr v) {
+			setResult(v.getType());
+		}
+		public void caseNewMultiArrayExpr(NewMultiArrayExpr v) {
+			setResult(v.getType());
+		}
+		public void caseNewExpr(NewExpr v) {
+			setResult(v.getType());
+		}
+		public void caseNullConstant(NullConstant v) {
+			setResult(v.getType());
+		}
+		public void defaultCase(Object obj) {
+			Value v = (Value)obj;
+			Type type = v.getType();
+			if (!(v.getType() instanceof RefType))
+				return;
+			SootClass c = ((RefType)type).getSootClass();
+			if (!Util.isFinal(c))
+				return;
+			setResult(type);
+		}
+	};
+
+	public TypeAnalysis(LocalDefs localDefs) {
+		this.localDefs = localDefs;
+	}
+
+	/**
+	 * Return the exact type of the reference local def if it's a reference
+	 * type and the Java class is known exactly, else <code>null</code>.
+	 */
+	public RefLikeType getExactType(Local local, Unit unit) {
+		RefLikeType type = null;
+		for (Iterator i = localDefs.getDefsOfAt(local, unit).iterator();
+		    i.hasNext(); ) {
+			DefinitionStmt def = (DefinitionStmt)i.next();
+			vs.setResult(null);
+			def.getRightOp().apply(vs);
+			RefLikeType type2 = (RefLikeType)vs.getResult();
+			if (type2 == null)
+				return null;
+			if (type == null)
+				type = type2;
+			else if (!type.equals(type2))
+				return null;
+		}
+		return type;
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/package.html
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/package.html?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/package.html (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/analysis/package.html Tue Oct  4 19:19:16 2005
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>
+Package description
+</title>
+</head>
+<body>
+
+<p>
+Classes used for general analysis.
+
+</body>
+</html>

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapeAnalysis.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapeAnalysis.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapeAnalysis.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapeAnalysis.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,350 @@
+
+//
+// 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: EscapeAnalysis.java,v 1.6 2005/02/20 21:14:31 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.escape;
+
+import java.util.*;
+import soot.*;
+import soot.jimple.*;
+import soot.jimple.toolkits.scalar.*;
+import soot.toolkits.graph.*;
+import soot.toolkits.scalar.*;
+import org.dellroad.jc.cgen.analysis.ReferenceDetector;
+import org.dellroad.jc.cgen.analysis.FinalizeDetector;
+import org.dellroad.jc.cgen.analysis.FollowsAnalysis;
+
+/**
+ * Class that performs escape analysis to determine objects that
+ * may be allocated on the stack (instead of the heap).
+ */
+public class EscapeAnalysis {
+
+	private static final boolean DEBUG = false;
+
+	private EscapeAnalysis() {
+	}
+
+	/**
+	 *
+	 * Find allocations of non-escaping objects. Our requirements:
+	 *
+	 * <ol>
+	 * <li>Object must not be thrown, returned, assigned to any field,
+	 *    assigned to any array element, or passed to any method.
+	 *    MONITORENTER is allowed, hence these must be balanced.</li>
+	 * <li>Allocation size must be known a priori.</li>
+	 * <li>Object must not override <code>finalize()</code>.</li>
+	 * <li>Object must not subclass
+	 *    <code>java.lang.ref.Reference</code>.</li>
+	 * <li>The allocation must not be within a loop</li>
+	 * </ol>
+	 *
+	 * <p>
+	 * We impose a maximum total size for all stack allocations in the
+	 * method. We prioritize allocations by size (smallest first).
+	 * </p>
+	 *
+	 * <p>
+	 * All allocations that may be stack allocated are tagged with
+	 * a {@link StackAllocTag StackAllocTag}.
+	 * </p>
+	 *
+	 * @param graph graph computed from method
+	 * @param maxAlloc max number of bytes of stack allocated objects
+	 */
+	public static void analyze(CompleteUnitGraph graph, int maxAlloc) {
+
+		// Avoid useless work if stack allocation is disabled
+		if (maxAlloc == 0)
+			return;
+
+		// Get method body
+		Body body = graph.getBody();
+
+		// Debug
+		HashMap indexMap = null;
+		if (DEBUG) {
+			System.out.println("NEW ESCAPE ANALYSIS");
+			indexMap = new HashMap();
+			int index = 0;
+			for (Iterator i = body.getUnits().iterator();
+			    i.hasNext(); ) {
+				Stmt stmt = (Stmt)i.next();
+			    	indexMap.put(stmt, new Integer(++index));
+				System.out.println("  [" + index + "] " + stmt);
+			}
+		}
+
+		// Our stack allocatable 'new' statements
+		HashSet stackAllocs = new HashSet();
+
+		// Find all new statements with a known size
+		KnownSizeDetector knownSizeDetector = new KnownSizeDetector();
+		for (Iterator i = body.getUnits().iterator(); i.hasNext(); ) {
+			Stmt stmt = (Stmt)i.next();
+			if (!(stmt instanceof AssignStmt))
+				continue;
+			AssignStmt astmt = (AssignStmt)stmt;
+			if (!(astmt.getLeftOp() instanceof Local))
+				continue;
+			astmt.getRightOp().apply(knownSizeDetector);
+			Integer size = (Integer)knownSizeDetector.getResult();
+			if (size != null)
+				stackAllocs.add(new StackAlloc(stmt));
+		}
+
+		// Debug
+		if (DEBUG) {
+			System.out.println(stackAllocs.size()
+			    + " FIXED SIZE ALLOCATIONS");
+			for (Iterator i = stackAllocs.iterator();
+			    i.hasNext(); ) {
+				StackAlloc alloc = (StackAlloc)i.next();
+				System.out.println("  ["
+				    + indexMap.get(alloc.stmt) + "] "
+				    + alloc.stmt);
+			}
+		}
+
+		// Eliminate new expressions of objects that override finalize()		// or that are instances of java.lang.ref.Reference.
+		FinalizeDetector finalizeDetector = new FinalizeDetector();
+		ReferenceDetector referenceDetector = new ReferenceDetector();
+		for (Iterator i = stackAllocs.iterator(); i.hasNext(); ) {
+			StackAlloc alloc = (StackAlloc)i.next();
+			alloc.value.apply(finalizeDetector);
+			if (((Boolean)finalizeDetector.getResult())
+			    .booleanValue()) {
+			    	if (DEBUG) {
+					System.out.println("FINALIZE: ["
+					    + indexMap.get(alloc.stmt) + "] "
+					    + alloc.stmt);
+				}
+				i.remove();
+			}
+			alloc.value.apply(referenceDetector);
+			if (((Boolean)referenceDetector.getResult())
+			    .booleanValue()) {
+			    	if (DEBUG) {
+					System.out.println("REFERENCE: ["
+					    + indexMap.get(alloc.stmt) + "] "
+					    + alloc.stmt);
+				}
+				i.remove();
+			}
+		}
+
+		// Do follows flow analysis to eliminate looped allocations
+		FollowsAnalysis follows = new FollowsAnalysis(body);
+		for (Iterator i = stackAllocs.iterator(); i.hasNext(); ) {
+			StackAlloc alloc = (StackAlloc)i.next();
+			if (follows.canFollow(alloc.stmt, alloc.stmt)) {
+			    	if (DEBUG) {
+					System.out.println("LOOPED: ["
+					    + indexMap.get(alloc.stmt) + "] "
+					    + alloc.stmt);
+				}
+				i.remove();
+			}
+		}
+
+		// If there are no more candidates, bail out early
+		if (stackAllocs.isEmpty())
+			return;
+
+		// Compute uses of each local
+		SimpleLocalUses localUses = new SimpleLocalUses(graph,
+		    new SimpleLocalDefs(graph));
+
+		// Initialize set of defs with known escape status
+		HashMap knowns = new HashMap();
+
+		// Initialize set of defs with unknown escape status
+		HashSet unknowns = new HashSet();
+		for (Iterator i = stackAllocs.iterator(); i.hasNext(); ) {
+			StackAlloc alloc = (StackAlloc)i.next();
+			unknowns.add(alloc.stmt);
+		}
+
+		// Keep eliminating unknowns until we're done
+		EscapingStmtSwitch ess = new EscapingStmtSwitch();
+		while (!unknowns.isEmpty()) {
+
+			// Debug
+			if (DEBUG) {
+				System.out.println(unknowns.size()
+				    + " remaining unknowns...");
+				for (Iterator i = unknowns.iterator();
+				    i.hasNext(); ) {
+					Stmt stmt = (Stmt)i.next();
+					System.out.println("  ["
+					    + indexMap.get(stmt) + "] " + stmt);
+				}
+				System.out.println("------------------------");
+			}
+
+			// Detect forward progress
+			boolean doMore = false;
+
+			// For each unknown def, check for escape
+		    unknown_loop:
+			for (Iterator i = ((HashSet)unknowns.clone())
+			    .iterator(); i.hasNext(); ) {
+
+				// Get next unknown def statment
+				AssignStmt stmt = (AssignStmt)i.next();
+				Local defLocal = (Local)stmt.getLeftOp();
+
+				// Look for uses that themselves escape
+				boolean anyUknowns = false;
+				for (Iterator j = localUses.getUsesOf(stmt)
+				    .iterator(); j.hasNext(); ) {
+
+					// Get next use of the local
+					UnitValueBoxPair up
+					    = (UnitValueBoxPair)j.next();
+					Stmt use = (Stmt)up.getUnit();
+
+					// Test if local escapes via this use
+					ess.setLocal(defLocal);
+					use.apply(ess);
+					Object result = ess.getResult();
+
+					// Only escapes maybe via this use?
+					// If so, and the escape of the use
+					// is unknown, then add the use to
+					// the set of unknowns we need to check
+					if (result == null) {
+						result = knowns.get(use);
+						if (result == null) {
+							if (DEBUG) {
+							    System.out.println(
+							      "  UNKNOWN USE ["
+							      + indexMap.get(
+							        use) + "]");
+							}
+							unknowns.add(use);
+							anyUknowns = true;
+							doMore = true;
+							continue;
+						}
+					}
+
+					// Does local escape via this use?
+					if (result == Boolean.TRUE) {
+						if (DEBUG) {
+						    System.out.println("["
+						        + indexMap.get(stmt)
+							+ "] ESCAPES via ["
+						        + indexMap.get(use)
+							+ "]");
+						}
+						unknowns.remove(stmt);
+						knowns.put(stmt, result);
+						doMore = true;
+						continue unknown_loop;
+					}
+
+					// Defintely does not escape this use
+					if (result != Boolean.FALSE)
+						throw new RuntimeException();
+				}
+
+				// Are all uses non-escaping?
+				if (!anyUknowns) {
+					if (DEBUG) {
+					    System.out.println("["
+					        + indexMap.get(stmt)
+						+ "] NO ESCAPE");
+					}
+					unknowns.remove(stmt);
+					knowns.put(stmt, Boolean.FALSE);
+					doMore = true;
+					continue;
+				}
+
+				// This def is still unknown
+				if (DEBUG) {
+				    System.out.println("["
+					+ indexMap.get(stmt)
+					+ "] STILL UNKNOWN");
+				}
+			}
+
+			// See if we're no longer making progress
+			if (!doMore) {
+				if (DEBUG)
+				    System.out.println("NO FURTHER PROGRESS");
+				for (Iterator i = unknowns.iterator();
+				    i.hasNext(); ) {
+					AssignStmt stmt = (AssignStmt)i.next();
+					knowns.put(stmt, Boolean.FALSE);
+				}
+				unknowns.clear();
+			}
+		}
+
+		// Now eliminate allocations whose locals can escape
+		for (Iterator i = stackAllocs.iterator(); i.hasNext(); ) {
+			AssignStmt stmt = ((StackAlloc)i.next()).stmt;
+			if (((Boolean)knowns.get(stmt)).booleanValue())
+				i.remove();
+		}
+
+		// Debug
+		if (DEBUG) {
+			System.out.println(stackAllocs.size()
+			    + " STACK ALLOCATABLES");
+			for (Iterator i = stackAllocs.iterator();
+			    i.hasNext(); ) {
+				StackAlloc alloc = (StackAlloc)i.next();
+				System.out.println("  ["
+				    + indexMap.get(alloc.stmt) + "] "
+				    + alloc.stmt);
+			}
+		}
+
+		// Sort the remaining allocations by size
+		StackAlloc[] allocs = (StackAlloc[])stackAllocs.toArray(
+		    new StackAlloc[stackAllocs.size()]);
+		Arrays.sort(allocs, new Comparator() {
+			public int compare(Object o1, Object o2) {
+				StackAlloc a1 = (StackAlloc)o1;
+				StackAlloc a2 = (StackAlloc)o2;
+				return a1.size < a2.size ? -1
+				    : a1.size > a2.size ? 1 : 0;
+			}
+		});
+
+		// Include as many as we can, up to maximum total size
+		int total = 0;
+		HashSet stmts = new HashSet();
+		for (int i = 0; i < allocs.length; i++) {
+			StackAlloc alloc = allocs[i];
+			if (total + alloc.cost <= maxAlloc) {
+				alloc.stmt.getRightOpBox().addTag(
+				    new StackAllocTag(i));
+				total += alloc.cost;
+			} else
+				break;
+		}
+	}
+}
+
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapingStmtSwitch.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapingStmtSwitch.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapingStmtSwitch.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapingStmtSwitch.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,117 @@
+
+//
+// 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: EscapingStmtSwitch.java,v 1.1 2004/11/27 23:11:04 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.escape;
+
+import java.util.*;
+import org.dellroad.jc.cgen.*;
+import soot.*;
+import soot.jimple.*;
+
+/**
+ * Checks for statements where the local can escape. The result
+ * is <code>Boolean.TRUE</code> if so, <code>Boolean.FALSE</code> if not,
+ * or <code>null</code> if the statement assigns the local to another local.
+ */
+public class EscapingStmtSwitch extends AbstractStmtSwitch {
+
+	private final EscapingValueSwitch escapingValueSwitch;
+	private Local local;
+
+	public EscapingStmtSwitch() {
+		escapingValueSwitch = new EscapingValueSwitch();
+	}
+
+	public Local getLocal() {
+		return local;
+	}
+
+	public void setLocal(Local local) {
+		this.local = local;
+		escapingValueSwitch.setLocal(local);
+	}
+
+	public void caseAssignStmt(AssignStmt stmt) {
+		Value lhs = stmt.getLeftOp();
+		Value rhs = stmt.getRightOp();
+
+		// Check if local can escape via the expression itself
+		rhs.apply(escapingValueSwitch);
+		Object valueResult = escapingValueSwitch.getResult();
+		if (valueResult != null) {
+			setResult(valueResult);
+			return;
+		}
+
+		// If we get here, the expression is the local..
+
+		// Check for assignment of local to a field
+		// XXX OK if field is in another non-escaping local
+		if (lhs instanceof FieldRef) {
+			setResult(Boolean.TRUE);
+			return;
+		}
+
+		// Check for assignment of local to an array element
+		// XXX OK if field is in another non-escaping array
+		if (lhs instanceof ArrayRef) {
+			setResult(Boolean.TRUE);
+			return;
+		}
+
+		// Assignment must be to some (possibly the same) local
+		if (!(lhs instanceof Local))
+			throw new RuntimeException("unexpected");
+
+		// Check for assignment of local to itself
+		if (lhs.equals(local)) {
+			setResult(Boolean.FALSE);
+			return;
+		}
+
+		// Escape depends on whether the assigned-to local can escape
+		setResult(null);
+	}
+
+	public void caseInvokeStmt(InvokeStmt stmt) {
+		if (NullCheckStmt.isNullCheck(stmt)) {
+			setResult(Boolean.FALSE);
+			return;
+		}
+		stmt.getInvokeExpr().apply(escapingValueSwitch);
+		Boolean result = (Boolean)escapingValueSwitch.getResult();
+		if (result == null)
+			result = Boolean.FALSE;	// return value is ignored
+		setResult(result);
+	}
+
+	public void caseReturnStmt(ReturnStmt stmt) {
+		setResult(Boolean.TRUE);
+	}
+
+	public void caseThrowStmt(ThrowStmt stmt) {
+		setResult(Boolean.TRUE);
+	}
+
+	public void defaultCase(Object obj) {
+		setResult(Boolean.FALSE);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapingValueSwitch.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapingValueSwitch.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapingValueSwitch.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/EscapingValueSwitch.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,95 @@
+
+//
+// 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: EscapingValueSwitch.java,v 1.1 2004/11/27 23:11:04 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.escape;
+
+import java.util.*;
+import org.dellroad.jc.cgen.*;
+import soot.*;
+import soot.jimple.*;
+
+/**
+ * Checks for values where the local can escape. The result
+ * is <code>Boolean.TRUE</code> if so, <code>Boolean.FALSE</code> if not,
+ * or <code>null</code> if the local can only escape as the 'return value'
+ * of the <code>Value</code> itself.
+ */
+public class EscapingValueSwitch extends AbstractJimpleValueSwitch {
+
+	private Local local;
+
+	public Local getLocal() {
+		return local;
+	}
+
+	public void setLocal(Local local) {
+		this.local = local;
+	}
+
+	public void caseCastExpr(CastExpr v) {
+		v.getOp().apply(this);
+	}
+
+	public void caseLocal(Local v) {
+		setResult(v.equals(local) ? null : Boolean.FALSE);
+	}
+
+	public void caseInterfaceInvokeExpr(InterfaceInvokeExpr expr) {
+		caseInstanceInvokeExpr(expr);
+	}
+
+	public void caseSpecialInvokeExpr(SpecialInvokeExpr expr) {
+		caseInstanceInvokeExpr(expr);
+	}
+
+	public void caseVirtualInvokeExpr(VirtualInvokeExpr expr) {
+		caseInstanceInvokeExpr(expr);
+	}
+
+	public void caseStaticInvokeExpr(StaticInvokeExpr expr) {
+		handleInvokeParameters(expr);
+	}
+
+	private void caseInstanceInvokeExpr(InstanceInvokeExpr expr) {
+		expr.getBase().apply(this);
+		if (getResult() != Boolean.FALSE) {
+			setResult(Boolean.TRUE);
+			return;
+		}
+		handleInvokeParameters(expr);
+	}
+
+	private void handleInvokeParameters(InvokeExpr expr) {
+		int argCount = expr.getArgCount();
+		for (int i = 0; i < argCount; i++) {
+			expr.getArg(i).apply(this);
+			if (getResult() != Boolean.FALSE) {
+				setResult(Boolean.TRUE);
+				return;
+			}
+		}
+		setResult(Boolean.FALSE);
+	}
+
+	public void defaultCase(Object obj) {
+		setResult(Boolean.FALSE);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/KnownSizeDetector.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/KnownSizeDetector.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/KnownSizeDetector.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/KnownSizeDetector.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,146 @@
+
+//
+// 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: KnownSizeDetector.java,v 1.1 2004/11/27 23:11:04 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.escape;
+
+import java.util.*;
+import org.dellroad.jc.cgen.*;
+import soot.*;
+import soot.jimple.*;
+
+/**
+ * Instances of this class detect 'new' expressions with a known
+ * instance size. The result is an <code>Integer</code> with the
+ * estimated size, or <code>null</code> if the type of the 'new'
+ * expression does not have a fixed size (or the value is not
+ * some kind of 'new' expression).
+ */
+public class KnownSizeDetector extends AbstractJimpleValueSwitch {
+
+	public static final int REFERENCE_SIZE = 4;
+	public static final int OBJECT_HEADER_SIZE = 8;
+
+	public void caseNewExpr(NewExpr v) {
+		setResult(new Integer(size(v.getBaseType())));
+	}
+
+	public void caseNewArrayExpr(NewArrayExpr v) {
+		doArray(v.getSize(), (ArrayType)v.getType());
+	}
+
+	public void caseNewMultiArrayExpr(NewMultiArrayExpr v) {
+		doArray(v.getSize(0), (ArrayType)v.getType());
+	}
+
+	private void doArray(Value length, ArrayType atype) {
+		if (!(length instanceof IntConstant)) {
+			setResult(null);
+			return;
+		}
+		Type etype = atype.getElementType();
+		int size = etype instanceof RefLikeType ?
+		    REFERENCE_SIZE : size(etype);
+		setResult(new Integer(((IntConstant)length).value * size));
+	}
+
+	public void defaultCase(Object obj) {
+		setResult(null);
+	}
+
+	/**
+	 * Computes the size in bytes of an instance of a type.
+	 *
+	 * @see KnownSizeDetector#size KnownSizeDetector.size()
+	 */
+	public static class SizeTypeSwitch extends TypeSwitch {
+	    public void caseBooleanType(BooleanType t) {
+		setResult(new Integer(1));
+	    }
+	    public void caseByteType(ByteType t) {
+		setResult(new Integer(1));
+	    }
+	    public void caseCharType(CharType t) {
+		setResult(new Integer(2));
+	    }
+	    public void caseShortType(ShortType t) {
+		setResult(new Integer(2));
+	    }
+	    public void caseIntType(IntType t) {
+		setResult(new Integer(4));
+	    }
+	    public void caseFloatType(FloatType t) {
+		setResult(new Integer(4));
+	    }
+	    public void caseLongType(LongType t) {
+		setResult(new Integer(8));
+	    }
+	    public void caseDoubleType(DoubleType t) {
+		setResult(new Integer(8));
+	    }
+	    public void defaultCase(Type t) {
+		if (!(t instanceof RefType)) {
+			throw new IllegalArgumentException(
+			    "non-reference type: " + t);
+		}
+		SootClass c = ((RefType)t).getSootClass();
+		if (c.isInterface()) {
+			throw new IllegalArgumentException(
+			    "interface type: " + t);
+		}
+		int sz = OBJECT_HEADER_SIZE;
+		while (true) {
+			for (Iterator i = c.getFields().iterator();
+			    i.hasNext(); ) {
+				SootField f = (SootField)i.next();
+				if (f.isStatic())
+					continue;
+				Type ftype = f.getType();
+				if (ftype instanceof RefLikeType) {
+					sz += REFERENCE_SIZE;
+					continue;
+				}
+				ftype.apply(this);
+				sz += ((Integer)getResult()).intValue();
+			}
+			if (!c.hasSuperclass())
+				break;
+			c = c.getSuperclass();
+		}
+		setResult(new Integer(sz));
+	    }
+	}
+
+
+	/**
+	 * Return our best guess of the size of an instance of the given type,
+	 * in bytes. We include {@link #OBJECT_HEADER_SIZE OBJECT_HEADER_SIZE}
+	 * for object overhead, but don't include any gaps for alignment.
+	 *
+	 * @param type a primitive type, or a non-interface, non-array
+	 *	reference type.
+	 * @throws IllegalArgumentException if <code>type</code>
+	 */
+	public static int size(Type type) {
+		SizeTypeSwitch sw = new SizeTypeSwitch();
+		type.apply(sw);
+		return ((Integer)sw.getResult()).intValue();
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/Makefile.am
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/Makefile.am?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/Makefile.am (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/Makefile.am Tue Oct  4 19:19:16 2005
@@ -0,0 +1,10 @@
+## $Id: Makefile.am,v 1.3 2004/12/28 22:28:26 archiecobbs Exp $
+
+EXTRA_DIST=	EscapeAnalysis.java \
+		EscapingStmtSwitch.java \
+		EscapingValueSwitch.java \
+		KnownSizeDetector.java \
+		StackAlloc.java \
+		StackAllocTag.java \
+		package.html
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/StackAlloc.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/StackAlloc.java?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/StackAlloc.java (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/java/org/dellroad/jc/cgen/escape/StackAlloc.java Tue Oct  4 19:19:16 2005
@@ -0,0 +1,45 @@
+
+//
+// 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: StackAlloc.java,v 1.2 2004/12/17 15:35:46 archiecobbs Exp $
+//
+
+package org.dellroad.jc.cgen.escape;
+
+import java.util.*;
+import soot.*;
+import soot.jimple.*;
+
+/**
+ * Holds information about a potential stack-allocatable 'new' statement.
+ */
+class StackAlloc {
+
+	AssignStmt stmt;
+	Local local;
+	Value value;		// the 'new' expression
+	Boolean escapes; 	// TRUE = yes, FALSE = no, null = unknown
+	int size;
+	int cost;
+
+	public StackAlloc(Stmt ostmt) {
+		this.stmt = (AssignStmt)ostmt;
+		this.local = (Local)stmt.getLeftOp();
+		this.value = stmt.getRightOp();
+	}
+}
+