Allow to compile with Jack.

Even those tests and generated code compiled by the java build tool.

Change-Id: Ib38b2f5d6d8518cb4fa7bd78abf93f9beef73514
diff --git a/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java b/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
index c772c33..4ce8c38 100644
--- a/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
+++ b/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
@@ -78,6 +78,7 @@
 
     private int testClassCnt = 0;
     private int testMethodsCnt = 0;
+    private boolean useJack;
 
     /*
      * using a linked hashmap to keep the insertion order for iterators.
@@ -101,39 +102,47 @@
      */
     public static void main(String[] args) throws IOException {
 
-        if (args.length > 5) {
-            JAVASRC_FOLDER = args[0];
-            OUTPUT_FOLDER = args[1];
-            CLASS_PATH = args[2];
-            MAIN_SRC_OUTPUT_FOLDER = args[3];
-            CLASSES_OUTPUT_FOLDER = MAIN_SRC_OUTPUT_FOLDER + "/classes";
-
-            COMPILED_CLASSES_FOLDER = args[4];
-
-            HOSTJUNIT_SRC_OUTPUT_FOLDER = args[5];
-            HOSTJUNIT_CLASSES_OUTPUT_FOLDER = HOSTJUNIT_SRC_OUTPUT_FOLDER + "/classes";
-
-            if (args.length > 6) {
-                // optional: restrict to e.g. "opcodes.add_double"
-                restrictTo = args[6];
-                System.out.println("restricting build to: " + restrictTo);
-            }
-
-        } else {
-            System.out.println("usage: java-src-folder output-folder classpath " +
-                    "generated-main-files compiled_output generated-main-files " +
-            "[restrict-to-opcode]");
-            System.exit(-1);
-        }
+        parseArgs(args);
 
         long start = System.currentTimeMillis();
-        BuildDalvikSuite cat = new BuildDalvikSuite();
+        BuildDalvikSuite cat = new BuildDalvikSuite(false);
         cat.compose();
         long end = System.currentTimeMillis();
 
         System.out.println("elapsed seconds: " + (end - start) / 1000);
     }
 
+    public static void parseArgs(String[] args) {
+      if (args.length > 5) {
+          JAVASRC_FOLDER = args[0];
+          OUTPUT_FOLDER = args[1];
+          CLASS_PATH = args[2];
+          MAIN_SRC_OUTPUT_FOLDER = args[3];
+          CLASSES_OUTPUT_FOLDER = MAIN_SRC_OUTPUT_FOLDER + "/classes";
+
+          COMPILED_CLASSES_FOLDER = args[4];
+
+          HOSTJUNIT_SRC_OUTPUT_FOLDER = args[5];
+          HOSTJUNIT_CLASSES_OUTPUT_FOLDER = HOSTJUNIT_SRC_OUTPUT_FOLDER + "/classes";
+
+          if (args.length > 6) {
+              // optional: restrict to e.g. "opcodes.add_double"
+              restrictTo = args[6];
+              System.out.println("restricting build to: " + restrictTo);
+          }
+
+      } else {
+          System.out.println("usage: java-src-folder output-folder classpath " +
+                  "generated-main-files compiled_output generated-main-files " +
+          "[restrict-to-opcode]");
+          System.exit(-1);
+      }
+    }
+
+    public BuildDalvikSuite(boolean useJack) {
+      this.useJack = useJack;
+    }
+
     public void compose() throws IOException {
         System.out.println("Collecting all junit tests...");
         new TestRunner() {
@@ -182,19 +191,21 @@
         li.add(method);
     }
     private String curJunitFileName = null;
+    private String curJunitName = null;
     private String curJunitFileData = "";
 
-    private JavacBuildStep javacHostJunitBuildStep;
+    private SourceBuildStep hostJunitBuildStep;
 
     private void flushHostJunitFile() {
         if (curJunitFileName != null) {
             File toWrite = new File(curJunitFileName);
             String absPath = toWrite.getAbsolutePath();
             // add to java source files for later compilation
-            javacHostJunitBuildStep.addSourceFile(absPath);
+            hostJunitBuildStep.addSourceFile(absPath);
             // write file
             curJunitFileData += "\n}\n";
             writeToFileMkdir(toWrite, curJunitFileData);
+
             curJunitFileName = null;
             curJunitFileData = "";
         }
@@ -267,11 +278,11 @@
         String datafileContent = "";
         Set<BuildStep> targets = new TreeSet<BuildStep>();
 
-        javacHostJunitBuildStep = new JavacBuildStep(HOSTJUNIT_CLASSES_OUTPUT_FOLDER, CLASS_PATH);
+        SourceBuildStep srcBuildStep;
+        hostJunitBuildStep = new JavacBuildStep(
+            HOSTJUNIT_CLASSES_OUTPUT_FOLDER, CLASS_PATH);
 
-
-        JavacBuildStep javacBuildStep = new JavacBuildStep(
-                CLASSES_OUTPUT_FOLDER, CLASS_PATH);
+        srcBuildStep = new JavacBuildStep(CLASSES_OUTPUT_FOLDER, CLASS_PATH);
 
         for (Entry<String, List<String>> entry : map.entrySet()) {
 
@@ -334,19 +345,25 @@
                 "    public static void main(String[] args) throws Exception {" +
                 methodContent + "\n}\n";
 
-                String fileName = getFileName(pName, method, ".java");
                 File sourceFile = getFileFromPackage(pName, method);
 
-                File classFile = new File(CLASSES_OUTPUT_FOLDER + "/" +
-                        getFileName(pName, method, ".class"));
-                // if (sourceFile.lastModified() > classFile.lastModified()) {
                 writeToFile(sourceFile, content);
-                javacBuildStep.addSourceFile(sourceFile.getAbsolutePath());
+                if (useJack) {
+                    File jackFile = new File(CLASSES_OUTPUT_FOLDER + "/" +
+                            getFileName(pName, method, ".jack"));
+                    JackBuildStep step = new JackBuildStep(jackFile.getAbsolutePath(), CLASS_PATH);
+                    step.addSourceFile(sourceFile.getAbsolutePath());
+                    if (!step.build()) {
+                        System.out.println("main src dalvik-cts-buildutil build step failed");
+                        System.exit(1);
+                    }
+                } else {
+                    srcBuildStep.addSourceFile(sourceFile.getAbsolutePath());
+                }
 
                 BuildStep dexBuildStep = generateDexBuildStep(
-                        CLASSES_OUTPUT_FOLDER, getFileName(pName, method, ""));
+                        CLASSES_OUTPUT_FOLDER, getFileName(pName, method, ""), null);
                 targets.add(dexBuildStep);
-                // }
 
 
                 // prepare the entry in the data file for the bash script.
@@ -442,22 +459,23 @@
         scriptDataDir.mkdirs();
         writeToFile(new File(scriptDataDir, "scriptdata"), datafileContent);
 
-        if (!javacHostJunitBuildStep.build()) {
+        if (!hostJunitBuildStep.build()) {
             System.out.println("main javac cts-host-hostjunit-classes build step failed");
             System.exit(1);
         }
 
-        if (javacBuildStep.build()) {
-            for (BuildStep buildStep : targets) {
-                if (!buildStep.build()) {
-                    System.out.println("building failed. buildStep: " +
-                            buildStep.getClass().getName() + ", " + buildStep);
-                    System.exit(1);
-                }
+        if (!useJack) {
+            if (!srcBuildStep.build()) {
+                System.out.println("main src dalvik-cts-buildutil build step failed");
+                System.exit(1);
             }
-        } else {
-            System.out.println("main javac dalvik-cts-buildutil build step failed");
-            System.exit(1);
+        }
+        for (BuildStep buildStep : targets) {
+            if (!buildStep.build()) {
+                System.out.println("building failed. buildStep: " +
+                        buildStep.getClass().getName() + ", " + buildStep);
+                System.exit(1);
+            }
         }
     }
 
@@ -514,19 +532,37 @@
             return;
         }
 
-        if (new File(sourceFolder, fileName + ".java").exists()) {
-
+        File srcFile = new File(sourceFolder, fileName + ".java");
+        if (srcFile.exists()) {
+            JackBuildStep jackBuildStep = null;
+            if (useJack) {
+                jackBuildStep = new JackBuildStep(
+                        COMPILED_CLASSES_FOLDER + File.separator + fileName + ".jack",
+                        CLASS_PATH);
+                jackBuildStep.addSourceFile(srcFile.getAbsolutePath());
+            }
             BuildStep dexBuildStep = generateDexBuildStep(
-                    COMPILED_CLASSES_FOLDER, fileName);
+                COMPILED_CLASSES_FOLDER, fileName, jackBuildStep);
             targets.add(dexBuildStep);
             return;
         }
 
         try {
             if (Class.forName(dependentTestClassName) != null) {
+                JillBuildStep jillBuildStep = null;
+                if (useJack) {
+                    BuildStep.BuildFile classFile = new BuildStep.BuildFile(
+                        COMPILED_CLASSES_FOLDER, fileName + ".class");
 
+                    BuildStep.BuildFile jackFile = new BuildStep.BuildFile(
+                        COMPILED_CLASSES_FOLDER,
+                        fileName + ".jack");
+
+                    jillBuildStep = new JillBuildStep(classFile,
+                        jackFile);
+                }
                 BuildStep dexBuildStep = generateDexBuildStep(
-                        COMPILED_CLASSES_FOLDER, fileName);
+                    COMPILED_CLASSES_FOLDER, fileName, jillBuildStep);
                 targets.add(dexBuildStep);
                 return;
             }
@@ -539,24 +575,50 @@
     }
 
     private BuildStep generateDexBuildStep(String classFileFolder,
-            String classFileName) {
-        BuildStep.BuildFile classFile = new BuildStep.BuildFile(
-                classFileFolder, classFileName + ".class");
+            String classFileName, BuildStep dependency) {
+        if (!useJack) {
+            BuildStep.BuildFile classFile = new BuildStep.BuildFile(
+                    classFileFolder, classFileName + ".class");
 
-        BuildStep.BuildFile tmpJarFile = new BuildStep.BuildFile(OUTPUT_FOLDER,
-                classFileName + "_tmp.jar");
+            BuildStep.BuildFile tmpJarFile = new BuildStep.BuildFile(
+                    OUTPUT_FOLDER,
+                    classFileName + "_tmp.jar");
 
-        JarBuildStep jarBuildStep = new JarBuildStep(classFile, classFileName +
-                ".class", tmpJarFile, false);
+            JarBuildStep jarBuildStep = new JarBuildStep(classFile,
+                    classFileName + ".class", tmpJarFile, false);
 
-        BuildStep.BuildFile outputFile = new BuildStep.BuildFile(OUTPUT_FOLDER,
-                classFileName + ".jar");
+            if (dependency != null) {
+                jarBuildStep.addChild(dependency);
+            }
 
-        DexBuildStep dexBuildStep = new DexBuildStep(tmpJarFile, outputFile,
-                true);
+            BuildStep.BuildFile outputFile = new BuildStep.BuildFile(
+                    OUTPUT_FOLDER,
+                    classFileName + ".jar");
 
-        dexBuildStep.addChild(jarBuildStep);
-        return dexBuildStep;
+            DxBuildStep dexBuildStep = new DxBuildStep(tmpJarFile,
+                    outputFile,
+                    true);
+
+            dexBuildStep.addChild(jarBuildStep);
+            return dexBuildStep;
+        } else {
+          BuildStep.BuildFile jackFile = new BuildStep.BuildFile(
+              classFileFolder, classFileName + ".jack");
+
+          BuildStep.BuildFile outputFile = new BuildStep.BuildFile(
+                  OUTPUT_FOLDER,
+                  classFileName + ".jar");
+
+          JackDexBuildStep dexBuildStep = new JackDexBuildStep(jackFile,
+                  outputFile,
+                  true);
+
+          if (dependency != null) {
+              dexBuildStep.addChild(dependency);
+          }
+          return dexBuildStep;
+
+        }
 
     }
 
@@ -747,7 +809,7 @@
 
     private void writeToFile(File file, String content) {
         try {
-            if (file.length() == content.length()) {
+            if (file.exists() && file.length() == content.length()) {
                 FileReader reader = new FileReader(file);
                 char[] charContents = new char[(int) file.length()];
                 reader.read(charContents);
diff --git a/tools/vm-tests-tf/src/util/build/DexBuildStep.java b/tools/vm-tests-tf/src/util/build/DxBuildStep.java
similarity index 93%
rename from tools/vm-tests-tf/src/util/build/DexBuildStep.java
rename to tools/vm-tests-tf/src/util/build/DxBuildStep.java
index 6aba51c..6e347b2 100644
--- a/tools/vm-tests-tf/src/util/build/DexBuildStep.java
+++ b/tools/vm-tests-tf/src/util/build/DxBuildStep.java
@@ -19,11 +19,11 @@
 import com.android.dx.command.dexer.Main;
 import java.io.IOException;
 
-public class DexBuildStep extends BuildStep {
+public class DxBuildStep extends BuildStep {
 
     private final boolean deleteInputFileAfterBuild;
 
-    DexBuildStep(BuildFile inputFile, BuildFile outputFile,
+    DxBuildStep(BuildFile inputFile, BuildFile outputFile,
             boolean deleteInputFileAfterBuild) {
         super(inputFile, outputFile);
         this.deleteInputFileAfterBuild = deleteInputFileAfterBuild;
@@ -71,7 +71,7 @@
     @Override
     public boolean equals(Object obj) {
         if (super.equals(obj)) {
-            DexBuildStep other = (DexBuildStep) obj;
+            DxBuildStep other = (DxBuildStep) obj;
 
             return inputFile.equals(other.inputFile)
                     && outputFile.equals(other.outputFile);
diff --git a/tools/vm-tests-tf/src/util/build/JackBuildDalvikSuite.java b/tools/vm-tests-tf/src/util/build/JackBuildDalvikSuite.java
new file mode 100644
index 0000000..a508e5b
--- /dev/null
+++ b/tools/vm-tests-tf/src/util/build/JackBuildDalvikSuite.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package util.build;
+
+import java.io.IOException;
+
+public class JackBuildDalvikSuite {
+
+    public static void main(String[] args) throws IOException {
+
+        BuildDalvikSuite.parseArgs(args);
+
+        long start = System.currentTimeMillis();
+        BuildDalvikSuite cat = new BuildDalvikSuite(true);
+        cat.compose();
+        long end = System.currentTimeMillis();
+
+        System.out.println("elapsed seconds: " + (end - start) / 1000);
+    }
+}
diff --git a/tools/vm-tests-tf/src/util/build/JackBuildStep.java b/tools/vm-tests-tf/src/util/build/JackBuildStep.java
new file mode 100644
index 0000000..9e93475
--- /dev/null
+++ b/tools/vm-tests-tf/src/util/build/JackBuildStep.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package util.build;
+
+import com.android.jack.Jack;
+import com.android.jack.Main;
+import com.android.jack.Options;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class JackBuildStep extends SourceBuildStep {
+
+    private final String destPath;
+    private final String classPath;
+    private final Set<String> sourceFiles = new HashSet<String>();
+
+    public JackBuildStep(String destPath, String classPath) {
+        this.destPath = destPath;
+        this.classPath = classPath;
+    }
+
+    @Override
+    public void addSourceFile(String sourceFile) {
+        sourceFiles.add(sourceFile);
+    }
+
+    @Override
+    boolean build() {
+        if (super.build()) {
+            if (sourceFiles.isEmpty()) {
+                return true;
+            }
+
+            File outDir = new File(destPath).getParentFile();
+            if (!outDir.exists() && !outDir.mkdirs()) {
+                System.err.println("failed to create output dir: "
+                        + outDir.getAbsolutePath());
+                return false;
+            }
+            List<String> commandLine = new ArrayList(4 + sourceFiles.size());
+            commandLine.add("--classpath");
+            commandLine.add(classPath);
+            commandLine.add("--output-jack");
+            commandLine.add(destPath);
+            commandLine.addAll(sourceFiles);
+
+            try {
+                Options options = Main.parseCommandLine(commandLine);
+                Jack.run(options);
+            } catch (Throwable ex) {
+                ex.printStackTrace();
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (super.equals(obj)) {
+            JackBuildStep other = (JackBuildStep) obj;
+            return destPath.equals(other.destPath) && classPath.equals(other.classPath)
+                    && sourceFiles.equals(other.sourceFiles);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return destPath.hashCode() ^ classPath.hashCode() ^ sourceFiles.hashCode();
+    }
+}
diff --git a/tools/vm-tests-tf/src/util/build/JackDexBuildStep.java b/tools/vm-tests-tf/src/util/build/JackDexBuildStep.java
new file mode 100644
index 0000000..8d9771c
--- /dev/null
+++ b/tools/vm-tests-tf/src/util/build/JackDexBuildStep.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package util.build;
+
+import com.android.jack.Jack;
+import com.android.jack.Main;
+import com.android.jack.Options;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JackDexBuildStep extends BuildStep {
+
+    private final boolean deleteInputFileAfterBuild;
+
+    JackDexBuildStep(BuildFile inputFile, BuildFile outputFile,
+            boolean deleteInputFileAfterBuild) {
+        super(inputFile, outputFile);
+        this.deleteInputFileAfterBuild = deleteInputFileAfterBuild;
+    }
+
+    @Override
+    boolean build() {
+
+        if (super.build()) {
+            String outputFilePath = outputFile.fileName.getAbsolutePath();
+            if (outputFilePath.endsWith(".dex")) {
+              throw new AssertionError(
+                  "DexBuildStep does not support dex output outside of an archive");
+            }
+
+            File outDir = outputFile.fileName.getParentFile();
+            if (!outDir.exists() && !outDir.mkdirs()) {
+                System.err.println("failed to create output dir: "
+                        + outDir.getAbsolutePath());
+                return false;
+            }
+
+            List<String> commandLine = new ArrayList<String>(4);
+            commandLine.add("--output-dex-zip");
+            commandLine.add(outputFilePath);
+            commandLine.add("--import");
+            commandLine.add(inputFile.fileName.getAbsolutePath());
+
+            try {
+               Options options = Main.parseCommandLine(commandLine);
+               Jack.run(options);
+                if (deleteInputFileAfterBuild) {
+                    inputFile.fileName.delete();
+                }
+                return true;
+            } catch (Throwable ex) {
+                System.err.println("exception while dexing "
+                        + inputFile.fileName.getAbsolutePath() + " to "
+                        + outputFile.fileName.getAbsolutePath());
+                ex.printStackTrace();
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return inputFile.hashCode() ^ outputFile.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (super.equals(obj)) {
+            JackDexBuildStep other = (JackDexBuildStep) obj;
+
+            return inputFile.equals(other.inputFile)
+                    && outputFile.equals(other.outputFile);
+        }
+        return false;
+    }
+
+
+}
diff --git a/tools/vm-tests-tf/src/util/build/JavacBuildStep.java b/tools/vm-tests-tf/src/util/build/JavacBuildStep.java
index 7d7033f..d08a2c6 100644
--- a/tools/vm-tests-tf/src/util/build/JavacBuildStep.java
+++ b/tools/vm-tests-tf/src/util/build/JavacBuildStep.java
@@ -23,7 +23,7 @@
 import java.util.HashSet;
 import java.util.Set;
 
-public class JavacBuildStep extends BuildStep {
+public class JavacBuildStep extends SourceBuildStep {
 
     private final String destPath;
     private final String classPath;
@@ -32,12 +32,13 @@
         this.destPath = destPath;
         this.classPath = classPath;
     }
-    
+
+    @Override
     public void addSourceFile(String sourceFile)
     {
         sourceFiles.add(sourceFile);
     }
-    
+
     @Override
     boolean build() {
         if (super.build())
@@ -46,7 +47,7 @@
             {
                 return true;
             }
-            
+
             File destFile = new File(destPath);
             if (!destFile.exists() && !destFile.mkdirs())
             {
@@ -59,13 +60,12 @@
             commandLine[1] = classPath;
             commandLine[2] = "-d";
             commandLine[3] = destPath;
-             
+
             String[] files = new String[sourceFiles.size()];
             sourceFiles.toArray(files);
-            
+
             System.arraycopy(files, 0, commandLine, args, files.length);
-            
-            
+
             return Main.compile(commandLine, new PrintWriter(System.err)) == 0;
         }
         return false;
@@ -73,17 +73,16 @@
 
     @Override
     public boolean equals(Object obj) {
-        // TODO Auto-generated method stub
         if (super.equals(obj))
         {
             JavacBuildStep other = (JavacBuildStep) obj;
-            return destPath.equals(other.destPath) 
+            return destPath.equals(other.destPath)
                 && classPath.equals(other.classPath)
                 && sourceFiles.equals(other.sourceFiles);
         }
         return false;
     }
-    
+
     @Override
     public int hashCode() {
         return destPath.hashCode() ^ classPath.hashCode() ^ sourceFiles.hashCode();
diff --git a/tools/vm-tests-tf/src/util/build/JillBuildStep.java b/tools/vm-tests-tf/src/util/build/JillBuildStep.java
new file mode 100644
index 0000000..aff3bb0
--- /dev/null
+++ b/tools/vm-tests-tf/src/util/build/JillBuildStep.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package util.build;
+
+import com.android.jill.Main;
+import com.android.jill.Options;
+
+import java.io.File;
+
+public class JillBuildStep extends BuildStep {
+
+    JillBuildStep(BuildFile inputFile, BuildFile outputFile) {
+        super(inputFile, outputFile);
+    }
+
+    @Override
+    boolean build() {
+        if (super.build()) {
+
+            File outDir = outputFile.fileName.getParentFile();
+            if (!outDir.exists() && !outDir.mkdirs()) {
+                System.err.println("failed to create output dir: "
+                        + outDir.getAbsolutePath());
+                return false;
+            }
+
+            int args = 3;
+            String[] commandLine = new String[args];
+            commandLine[0] = "--output";
+            commandLine[1] = outputFile.fileName.getAbsolutePath();
+            commandLine[2] = inputFile.fileName.getAbsolutePath();
+
+            try {
+                Options options = Main.getOptions(commandLine);
+                Main.run(options);
+            } catch (Throwable ex) {
+                ex.printStackTrace();
+                return false;
+            }
+
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (super.equals(obj)) {
+            JillBuildStep other = (JillBuildStep) obj;
+
+            return inputFile.equals(other.inputFile) && outputFile.equals(other.outputFile);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return inputFile.hashCode() ^ outputFile.hashCode();
+    }
+}
diff --git a/tools/vm-tests-tf/src/util/build/SourceBuildStep.java b/tools/vm-tests-tf/src/util/build/SourceBuildStep.java
new file mode 100644
index 0000000..4a68a05
--- /dev/null
+++ b/tools/vm-tests-tf/src/util/build/SourceBuildStep.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package util.build;
+
+public abstract class SourceBuildStep extends BuildStep {
+
+  public abstract void addSourceFile(String sourceFile);
+
+}