changeset 6334:a558348bb5f9

Merge
author briangoetz
date Sat, 20 Oct 2012 13:44:44 -0400
parents 80332caeac10 752fe6045da0
children 6ba8d0b9bd8d
files
diffstat 12 files changed, 1156 insertions(+), 189 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/separate/AttributeInjector.java	Sat Oct 20 13:44:44 2012 -0400
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.openjdk.tests.separate;
+
+import java.io.*;
+
+public class AttributeInjector implements ClassFilePreprocessor {
+
+    private String attributeName;
+    private byte[] attributeData;
+
+    public AttributeInjector(String attributeName, byte[] attributeData) {
+        this.attributeName = attributeName;
+        this.attributeData = attributeData;
+    }
+
+    public byte[] preprocess(String name, byte[] cf) {
+        ClassFile classfile = new ClassFile(cf);
+
+        short cpIndex = (short)classfile.constant_pool.size();
+
+        ClassFile.CpUtf8 entry = new ClassFile.CpUtf8();
+        entry.bytes = new byte[attributeName.length()];
+        for (int i = 0; i < attributeName.length(); ++i) {
+            entry.bytes[i] = (byte)attributeName.charAt(i);
+        }
+        
+        classfile.constant_pool.add(entry); 
+
+        ClassFile.Attribute attr = new ClassFile.Attribute();
+        attr.attribute_name_index = cpIndex;
+        attr.info = attributeData;
+
+        classfile.attributes.add(attr);
+        return classfile.toByteArray();
+    }
+
+/*
+    public static void main(String argv[]) throws Exception {
+        File input = new File(argv[0]);
+        byte[] buffer = new byte[(int)input.length()];
+        new FileInputStream(input).read(buffer);
+
+        ClassFilePreprocessor cfp = 
+            new AttributeInjector("RequiresBridges", new byte[0]);
+        byte[] cf = cfp.preprocess(argv[0], buffer);
+        new FileOutputStream(argv[0] + ".mod").write(cf);
+    }
+*/
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/separate/ClassFile.java	Sat Oct 20 13:44:44 2012 -0400
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.openjdk.tests.separate;
+
+import java.io.*;
+import java.util.*;
+
+class CfInputStream extends ByteArrayInputStream {
+    private int ct;
+    public CfInputStream(byte[] input) { 
+        super(input);
+    }
+
+    byte u1() { return (byte)read(); }
+    short u2() { 
+        int b0 = read() << 8;
+        int b1 = read();
+        return (short)(b0 | b1);
+    }
+    int u4() { 
+        int b0 = read() << 24;
+        int b1 = read() << 16;
+        int b2 = read() << 8;
+        int b3 = read();
+        return b0 | b1 | b2 | b3;
+    }
+    byte[] array(int count) {
+        byte[] ret = new byte[count];
+        read(ret, 0, count);
+        return ret;
+    }
+};
+
+class CfOutputStream extends ByteArrayOutputStream {
+    void u1(byte b) { write((int)b); }
+    void u2(short s) { 
+        write((s >> 8) & 0xff);
+        write(s & 0xff);
+    }
+    void u4(int i) {
+        write((i >> 24) & 0xff);   
+        write((i >> 16) & 0xff);   
+        write((i >> 8) & 0xff);   
+        write(i & 0xff);
+    }
+    void array(byte[] a) {
+        write(a, 0, a.length);
+    }
+
+    public byte[] toByteArray() { return super.toByteArray(); }
+};
+
+// A quick and dirty class file parser and representation
+public class ClassFile {
+
+    int magic;
+    short minor_version;
+    short major_version;
+    ArrayList<CpEntry> constant_pool;
+    short access_flags;
+    short this_class;
+    short super_class;
+    ArrayList<Interface> interfaces;
+    ArrayList<Field> fields;
+    ArrayList<Method> methods;
+    ArrayList<Attribute> attributes;
+
+    ClassFile(byte[] cf) {
+        CfInputStream in = new CfInputStream(cf);
+
+        magic = in.u4();
+        minor_version = in.u2();
+        major_version = in.u2();
+
+        short cpCount = in.u2();
+        constant_pool = new ArrayList<>();
+        constant_pool.add(new CpNull());
+        for (int i = 1; i < cpCount; ++i) {
+            constant_pool.add(CpEntry.newCpEntry(in));
+        }
+
+        access_flags = in.u2();
+        this_class = in.u2();
+        super_class = in.u2();
+
+        short ifaceCount = in.u2();
+        interfaces = new ArrayList<>();
+        for (int i = 0; i < ifaceCount; ++i) {
+            interfaces.add(new Interface(in));
+        }
+
+        short fieldCount = in.u2();
+        fields = new ArrayList<>();
+        for (int i = 0; i < fieldCount; ++i) {
+            fields.add(new Field(in));
+        }
+
+        short methodCount = in.u2();
+        methods = new ArrayList<>();
+        for (int i = 0; i < methodCount; ++i) {
+            methods.add(new Method(in));
+        }
+
+        short attributeCount = in.u2();
+        attributes = new ArrayList<>();
+        for (int i = 0; i < attributeCount; ++i) {
+            attributes.add(new Attribute(in));
+        }
+    }
+
+    byte[] toByteArray() {
+        CfOutputStream out = new CfOutputStream();
+
+        out.u4(magic);
+        out.u2(minor_version);
+        out.u2(major_version);
+
+        out.u2((short)(constant_pool.size()));
+        for (CpEntry cp : constant_pool) {
+            cp.write(out);
+        }
+
+        out.u2(access_flags);
+        out.u2(this_class);
+        out.u2(super_class);
+
+        out.u2((short)interfaces.size());
+        for (Interface iface : interfaces) {
+            iface.write(out);
+        }
+
+        out.u2((short)fields.size());
+        for (Field field : fields) {
+            field.write(out);
+        }
+
+        out.u2((short)methods.size());
+        for (Method method : methods) {
+            method.write(out);
+        }
+
+        out.u2((short)attributes.size());
+        for (Attribute attribute : attributes) {
+            attribute.write(out);
+        }
+      
+        return out.toByteArray();
+    }
+
+    static abstract class CpEntry {
+        byte tag;
+
+        CpEntry(byte t) { tag = t; }
+        void write(CfOutputStream out) {
+            out.u1(tag);
+        }
+
+        static CpEntry newCpEntry(CfInputStream in) {
+            byte tag = in.u1();
+            switch (tag) {
+                case CpUtf8.TAG: return new CpUtf8(in);
+                case CpInteger.TAG: return new CpInteger(in);
+                case CpFloat.TAG: return new CpFloat(in);
+                case CpLong.TAG: return new CpLong(in);
+                case CpDouble.TAG: return new CpDouble(in);
+                case CpClass.TAG: return new CpClass(in);
+                case CpString.TAG: return new CpString(in);
+                case CpFieldRef.TAG: return new CpFieldRef(in);
+                case CpMethodRef.TAG: return new CpMethodRef(in);
+                case CpInterfaceMethodRef.TAG: 
+                    return new CpInterfaceMethodRef(in);
+                case CpNameAndType.TAG: return new CpNameAndType(in);
+                case CpMethodHandle.TAG: return new CpMethodHandle(in);
+                case CpMethodType.TAG: return new CpMethodType(in);
+                case CpInvokeDynamic.TAG: return new CpInvokeDynamic(in);
+                default: throw new RuntimeException("Bad cp entry tag: " + tag);
+            }
+        }
+    }
+
+    static class CpNull extends CpEntry {
+        CpNull() { super((byte)0); }
+        CpNull(CfInputStream in) { super((byte)0); }
+        void write(CfOutputStream out) {}
+    }
+
+    static class CpUtf8 extends CpEntry {
+        static final byte TAG = 1;
+        byte[] bytes;
+
+        CpUtf8() { super(TAG); }
+        CpUtf8(CfInputStream in) {
+            this();
+            short length = in.u2();
+            bytes = in.array(length);            
+        }
+        void write(CfOutputStream out) {
+            super.write(out);
+            out.u2((short)bytes.length);
+            out.array(bytes);
+        }
+    }
+
+    static class CpU4Constant extends CpEntry {
+        byte[] bytes;
+
+        CpU4Constant(byte tag) { super(tag); }
+        CpU4Constant(byte tag, CfInputStream in) { 
+            this(tag); 
+            bytes = in.array(4); 
+        }
+        void write(CfOutputStream out) { super.write(out); out.array(bytes); }
+    }
+    static class CpInteger extends CpU4Constant { 
+        static final byte TAG = 3;
+        CpInteger() { super(TAG); } 
+        CpInteger(CfInputStream in) { super(TAG, in); }
+    }
+    static class CpFloat extends CpU4Constant {
+        static final byte TAG = 4;
+        CpFloat() { super(TAG); }
+        CpFloat(CfInputStream in) { super(TAG, in); }
+    }
+
+    static class CpU8Constant extends CpEntry {
+        byte[] bytes;
+
+        CpU8Constant(byte tag) { super(tag); }
+        CpU8Constant(byte tag, CfInputStream in) { 
+            this(tag); 
+            bytes = in.array(8); 
+        }
+        void write(CfOutputStream out) { super.write(out); out.array(bytes); }
+    }
+    static class CpLong extends CpU8Constant {
+        static final byte TAG = 5;
+        CpLong() { super(TAG); }
+        CpLong(CfInputStream in) { super(TAG, in); }
+    }
+    static class CpDouble extends CpU8Constant {
+        static final byte TAG = 6;
+        CpDouble() { super(TAG); }
+        CpDouble(CfInputStream in) { super(TAG, in); }
+    }
+
+    static class CpClass extends CpEntry {
+        static final byte TAG = 7;
+        short name_index;
+
+        CpClass() { super(TAG); }
+        CpClass(CfInputStream in) { super(TAG); name_index = in.u2(); }
+        void write(CfOutputStream out) {
+            super.write(out);
+            out.u2(name_index);
+        }
+    }
+
+    static class CpString extends CpEntry {
+        static final byte TAG = 8;
+        short string_index;
+
+        CpString() { super(TAG); }
+        CpString(CfInputStream in) { super(TAG); string_index = in.u2(); }
+        void write(CfOutputStream out) {
+            super.write(out);
+            out.u2(string_index);
+        }
+    }
+
+    static class CpRef extends CpEntry {
+        short class_index;
+        short name_and_type_index;
+
+        CpRef(byte tag) { super(tag); }
+        CpRef(byte tag, CfInputStream in) { 
+            this(tag);
+            class_index = in.u2();
+            name_and_type_index = in.u2();
+        }
+        void write(CfOutputStream out) {
+            super.write(out);
+            out.u2(class_index);
+            out.u2(name_and_type_index);
+        }
+    }
+    static class CpFieldRef extends CpRef {
+        static final byte TAG = 9;
+        CpFieldRef() { super(TAG); }
+        CpFieldRef(CfInputStream in) { super(TAG, in); }
+    }
+    static class CpMethodRef extends CpRef {
+        static final byte TAG = 10;
+        CpMethodRef() { super(TAG); }
+        CpMethodRef(CfInputStream in) { super(TAG, in); }
+    }
+    static class CpInterfaceMethodRef extends CpRef {
+        static final byte TAG = 11;
+        CpInterfaceMethodRef() { super(TAG); }
+        CpInterfaceMethodRef(CfInputStream in) { super(TAG, in); }
+    }
+
+    static class CpNameAndType extends CpEntry {
+        static final byte TAG = 12;
+        short name_index;
+        short descriptor_index;
+
+        CpNameAndType() { super(TAG); }
+        CpNameAndType(CfInputStream in) { 
+            this();
+            name_index = in.u2();
+            descriptor_index = in.u2();
+        }
+        void write(CfOutputStream out) {
+            super.write(out);
+            out.u2(name_index);
+            out.u2(descriptor_index);
+        }
+    }
+
+    static class CpMethodHandle extends CpEntry {
+        static final byte TAG = 15;
+        byte reference_kind;
+        short reference_index;
+
+        CpMethodHandle() { super(TAG); }
+        CpMethodHandle(CfInputStream in) {
+            this();
+            reference_kind = in.u1();
+            reference_index = in.u2();
+        }
+        void write(CfOutputStream out) {
+            super.write(out);
+            out.u1(reference_kind);
+            out.u2(reference_index);
+        }
+    }
+
+    static class CpMethodType extends CpEntry {
+        static final byte TAG = 16;
+        short descriptor_index;
+
+        CpMethodType() { super(TAG); }
+        CpMethodType(CfInputStream in) { 
+            this();
+            descriptor_index = in.u2(); 
+        }
+        void write(CfOutputStream out) {
+            super.write(out);
+            out.u2(descriptor_index);
+        }
+    }
+
+    static class CpInvokeDynamic extends CpEntry {
+        static final byte TAG = 18;
+        short bootstrap_index;
+        short name_and_type_index;
+
+        CpInvokeDynamic() { super(TAG); }
+        CpInvokeDynamic(CfInputStream in) {
+            this();
+            bootstrap_index = in.u2();
+            name_and_type_index = in.u2();
+        }
+        void write(CfOutputStream out) {
+            super.write(out);
+            out.u2(bootstrap_index);
+            out.u2(name_and_type_index);
+        }
+    }
+
+    static class Interface {
+        short index;
+
+        Interface() {}
+        Interface(CfInputStream in) { index = in.u2(); }
+        void write(CfOutputStream out) { out.u2(index); }
+    }
+
+    static class FieldOrMethod {
+        short access_flags;
+        short name_index;
+        short descriptor_index;
+        ArrayList<Attribute> attributes;
+
+        FieldOrMethod() { attributes = new ArrayList<>(); }
+        FieldOrMethod(CfInputStream in) {
+            access_flags = in.u2();
+            name_index = in.u2();
+            descriptor_index = in.u2();
+
+            short attrCount = in.u2();
+            attributes = new ArrayList<>();
+            for (int i = 0; i < attrCount; ++i) {
+                attributes.add(new Attribute(in));
+            }
+        }
+        void write(CfOutputStream out) {
+            out.u2(access_flags);
+            out.u2(name_index);
+            out.u2(descriptor_index);
+            out.u2((short)attributes.size());
+            for (Attribute attribute : attributes) { attribute.write(out); }
+        }
+    }
+
+    static class Field extends FieldOrMethod {
+        Field() {}
+        Field(CfInputStream in) { super(in); }
+    }
+    static class Method extends FieldOrMethod {
+        Method() {}
+        Method(CfInputStream in) { super(in); }
+    }
+
+    static class Attribute {
+        short attribute_name_index;
+        byte[] info;
+
+        Attribute() { info = new byte[0]; }
+        Attribute(CfInputStream in) {
+            attribute_name_index = in.u2();
+            int length = in.u4();
+            info = in.array(length);
+        }
+        void write(CfOutputStream out) {
+            out.u2(attribute_name_index);
+            out.u4(info.length);
+            out.array(info);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/separate/ClassFilePreprocessor.java	Sat Oct 20 13:44:44 2012 -0400
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.openjdk.tests.separate;
+
+public interface ClassFilePreprocessor {
+    public byte[] preprocess(String name, byte[] classfile);
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/separate/ClassToInterfaceConverter.java	Sat Oct 20 13:44:44 2012 -0400
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.openjdk.tests.separate;
+
+import java.io.*;
+import java.util.*;
+
+public class ClassToInterfaceConverter implements ClassFilePreprocessor {
+
+    private String whichClass;
+
+    public ClassToInterfaceConverter(String className) {
+        this.whichClass = className;
+    }
+
+    private boolean utf8Matches(ClassFile.CpEntry entry, String v) {
+        if (!(entry instanceof ClassFile.CpUtf8)) {
+            return false;
+        }
+        ClassFile.CpUtf8 utf8 = (ClassFile.CpUtf8)entry;
+        if (v.length() != utf8.bytes.length) {
+            return false;
+        }
+        for (int i = 0; i < v.length(); ++i) {
+            if (v.charAt(i) != utf8.bytes[i]) {
+                return false;
+            } 
+        }
+        return true;
+    }
+
+    private void convertToInterface(ClassFile cf) {
+        cf.access_flags = 0x0601; // ACC_INTERFACE | ACC_ABSTRACT | ACC_PUBLIC
+        ArrayList<ClassFile.Method> new_methods = new ArrayList<>();
+        // Find <init> method and delete it
+        for (int i = 0; i < cf.methods.size(); ++i) {
+            ClassFile.Method method = cf.methods.get(i);
+            ClassFile.CpEntry name = cf.constant_pool.get(method.name_index);
+            if (!utf8Matches(name, "<init>")) {
+                new_methods.add(method);
+            }
+        }
+        cf.methods = new_methods;
+    }
+
+    public byte[] preprocess(String classname, byte[] bytes) {
+        ClassFile cf = new ClassFile(bytes);
+        
+        ClassFile.CpEntry entry = cf.constant_pool.get(cf.this_class);
+        ClassFile.CpEntry name = cf.constant_pool.get(
+            ((ClassFile.CpClass)entry).name_index);
+        if (utf8Matches(name, whichClass)) {
+            convertToInterface(cf);
+            return cf.toByteArray();
+        } else {
+            return bytes; // unmodified
+        }
+    }
+
+/*
+    public static void main(String argv[]) throws Exception {
+        File input = new File(argv[0]);
+        byte[] buffer = new byte[(int)input.length()];
+        new FileInputStream(input).read(buffer);
+
+        ClassFilePreprocessor cfp = new ClassToInterfaceConverter("Hello");
+        byte[] cf = cfp.preprocess(argv[0], buffer);
+        new FileOutputStream(argv[0] + ".mod").write(cf);
+    }
+*/
+}
--- a/test-ng/tests/org/openjdk/tests/separate/Compiler.java	Sat Oct 20 13:44:10 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/separate/Compiler.java	Sat Oct 20 13:44:44 2012 -0400
@@ -61,6 +61,7 @@
     private JavaCompiler systemJavaCompiler;
     private StandardJavaFileManager fm;
     private List<File> tempDirs;
+    private List<ClassFilePreprocessor> postprocessors;
 
     private static class SourceFile extends SimpleJavaFileObject {
         private final String content;
@@ -80,6 +81,7 @@
     public Compiler(Flags ... flags) {
         setFlags(flags);
         this.tempDirs = new ArrayList<>();
+        this.postprocessors = new ArrayList<>();
         this.systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
         this.fm = systemJavaCompiler.getStandardFileManager(null, null, null);
     }
@@ -88,15 +90,22 @@
         this.flags = new HashSet<Flags>(Arrays.asList(flags));
     }
 
+    public void addPostprocessor(ClassFilePreprocessor cfp) {
+        this.postprocessors.add(cfp);
+    }
+
     /**
      * Compile hierarchies starting with each of the 'types' and return 
      * a ClassLoader that can be used to load the compiled classes.
      */
     public ClassLoader compile(Type ... types) {
-        DirectedClassLoader dcl = new DirectedClassLoader();
+        ClassFilePreprocessor[] cfps = this.postprocessors.toArray(
+            new ClassFilePreprocessor[0]);
+
+        DirectedClassLoader dcl = new DirectedClassLoader(cfps);
     
         for (Type t : types) {
-            for( Map.Entry<String,File> each : compileHierarchy(t).entrySet()) {
+            for (Map.Entry<String,File> each : compileHierarchy(t).entrySet()) {
                 dcl.setLocationFor(each.getKey(), each.getValue());
             }
         }
@@ -206,8 +215,8 @@
         if (!this.flags.contains(Flags.USECACHE)) {
             tempDirs.forEach(dir -> { deleteDir(dir); });
             tempDirs = new ArrayList<>();
+        }
     }
-}
 
     // Removes all of the elements in the cache and deletes the associated
     // output directories.  This may not actually empty the cache if there
--- a/test-ng/tests/org/openjdk/tests/separate/DirectedClassLoader.java	Sat Oct 20 13:44:10 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/separate/DirectedClassLoader.java	Sat Oct 20 13:44:44 2012 -0400
@@ -34,19 +34,25 @@
 
     private HashMap<String,File> loadLocations;
     private File defaultLocation;
+    private ClassFilePreprocessor[] preprocessors;
 
-    public DirectedClassLoader(HashMap<String,File> locations, File fallback) {
+    public DirectedClassLoader(
+            HashMap<String,File> locations, File fallback, 
+            ClassFilePreprocessor ... preprocessors) {
         loadLocations = new HashMap<>(locations);
         defaultLocation = fallback;
+        this.preprocessors = preprocessors;
     }
 
-    public DirectedClassLoader(File fallback) {
+    public DirectedClassLoader(
+            File fallback, ClassFilePreprocessor ... preprocessors) {
         loadLocations = new HashMap<>();
         defaultLocation = fallback;
+        this.preprocessors = preprocessors;
     }
 
-    public DirectedClassLoader() {
-        this(null);
+    public DirectedClassLoader(ClassFilePreprocessor ... preprocessors) {
+        this((File)null, preprocessors);
     }
 
     public void setDefaultLocation(File dir) { this.defaultLocation = dir; }
@@ -74,15 +80,20 @@
         FileInputStream fis = null;
         try {
             try {
-               fis = new FileInputStream(file);
-               byte[] bytes = new byte[fis.available()];
-               int read = fis.read(bytes);
-               if (read != bytes.length) {
-                  return null;
-               }
-               return defineClass(name, bytes, 0, bytes.length);
+                fis = new FileInputStream(file);
+                byte[] bytes = new byte[fis.available()];
+                int read = fis.read(bytes);
+                if (read != bytes.length) {
+                    return null;
+                }
+                if (preprocessors != null) {
+                    for (ClassFilePreprocessor cfp : preprocessors) {
+                        bytes = cfp.preprocess(name, bytes);
+                    }
+                 }
+                return defineClass(name, bytes, 0, bytes.length);
             } finally {
-               fis.close();
+                fis.close();
             }
         } catch (IOException e) {}
         return null;
--- a/test-ng/tests/org/openjdk/tests/separate/SourceModel.java	Sat Oct 20 13:44:10 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/separate/SourceModel.java	Sat Oct 20 13:44:44 2012 -0400
@@ -50,6 +50,29 @@
         }
     };
 
+    public static class AccessFlag extends Element {
+        private String flag;
+
+        public AccessFlag(String name) { flag = name; }
+
+        protected void generate(PrintWriter pw) {
+            pw.print(flag);
+        }
+
+        public String toString() { return flag; }
+
+        public static final AccessFlag PUBLIC = new AccessFlag("public");
+        public static final AccessFlag PRIVATE = new AccessFlag("private");
+        public static final AccessFlag PROTECTED = new AccessFlag("protected");
+        public static final AccessFlag STATIC = new AccessFlag("static");
+        public static final AccessFlag FINAL = new AccessFlag("final");
+        public static final AccessFlag SYNCHRONIZED = new AccessFlag("synchronized");
+        public static final AccessFlag VOLATILE = new AccessFlag("volatile");
+        public static final AccessFlag NATIVE = new AccessFlag("native");
+        public static final AccessFlag ABSTRACT = new AccessFlag("abstract");
+        public static final AccessFlag STRICTFP = new AccessFlag("strictfp");
+    }
+
     public static class TypeParameter extends Element {
         private String parameter;
 
@@ -86,10 +109,13 @@
         protected void generate(PrintWriter pw) {
             pw.printf("%s %s", this.type, this.name);
         }
+
+        public String toString() { return type + " " + name; }
     }
 
     public static abstract class Type extends Element {
         private String name;
+        private List<AccessFlag> accessFlags;
         private List<TypeParameter> parameters;
         private List<Extends> supertypes;
         private List<Method> methods;
@@ -99,9 +125,11 @@
         private Set<Method> methodDependencies;
         private List<Type> typeDependencies;
     
-        protected Type(String name, List<TypeParameter> params, 
+        protected Type(String name, 
+                List<AccessFlag> flags, List<TypeParameter> params, 
                 List<Extends> ifaces, List<Method> methods) {
             this.name = name; 
+            this.accessFlags = flags == null ? new ArrayList<>() : flags;
             this.parameters = params == null ? new ArrayList<>() : params;
             this.supertypes = ifaces == null ? new ArrayList<>() : ifaces;
             this.methods = methods == null ? new ArrayList<>() : methods;
@@ -110,6 +138,7 @@
         }
 
         public String getName() { return this.name; }
+        public List<AccessFlag> getAccessFlags() { return this.accessFlags; }
         public List<TypeParameter> getParameters() { return this.parameters; }
         public List<Extends> getSupertypes() { return this.supertypes; }
         public List<Method> getMethods() { return this.methods; }
@@ -132,6 +161,10 @@
             this.methods.add(m);
         }
 
+        public void addAccessFlag(AccessFlag f) {
+            this.accessFlags.add(f);
+        }
+
         // Convenience method for creation.  Parameters are interpreted
         // according to their type.  Class (or Extends with a Class type) is
         // considered a superclass (only one allowed).  TypeParameters are
@@ -155,6 +188,8 @@
                 this.parameters.add((TypeParameter)p);
             } else if (p instanceof Method) {
                 addMethod((Method)p);
+            } else if (p instanceof AccessFlag) {
+                addAccessFlag((AccessFlag)p);
             } else {
                 assert false : "What is this thing?";
             }
@@ -204,10 +239,16 @@
             pw.println("{ ");
             pw.print(this.methods.stream()
                 .map(x->x.toString())
-                .into(new StringJoiner(", ", "\n    ", "\n")
+                .into(new StringJoiner("\n    ", "\n    ", "\n")
                           .setEmptyOutput("")));
             pw.println("}");
         }
+
+        protected void generateAccessFlags(PrintWriter pw) {
+            pw.print(this.accessFlags.stream()
+                .map(x -> x.toString())
+                .into(new StringJoiner(" ", "", " ")));
+        }
     
         protected void generateBodyAsDependency(
             PrintWriter pw, Set<Method> neededMethods) {
@@ -239,23 +280,32 @@
     
     public static class Class extends Type {
         private Extends superClass; 
-        private boolean isAbstract;
     
-        public Class(String name, List<TypeParameter> params, 
-            Extends sprClass, List<Extends> interfaces, List<Method> methods) {
-            super(name, params, interfaces, methods);
+        public Class(String name, List<AccessFlag> flags, 
+                List<TypeParameter> params, Extends sprClass, 
+                List<Extends> interfaces, List<Method> methods) {
+            super(name, flags, params, interfaces, methods);
             this.superClass = sprClass;
-            this.isAbstract = false;
+            addAccessFlag(AccessFlag.PUBLIC); // should remove this
         }
 
         public Class(String name, Element ... components) {
-            super(name, null, null, null);
+            super(name, null, null, null, null);
             this.superClass = null;
-            this.isAbstract = false;
 
             for (Element p : components) {
                 addComponent(p);
             }
+            addAccessFlag(AccessFlag.PUBLIC); // should remove this
+        }
+
+        public boolean isAbstract() {
+            for (AccessFlag flag : getAccessFlags()) {
+                if (flag == AccessFlag.ABSTRACT) {
+                    return true;
+                }
+            }
+            return false;
         }
 
         @Override
@@ -274,9 +324,6 @@
             return superClass == null ? null : (Class)superClass.supertype; 
         }
 
-        public boolean getIsAbstract() { return this.isAbstract; }
-        public void setIsAbstract(boolean v) { this.isAbstract = v; }
-
         public void generate(SourceProcessor processor) {
             StringWriter sw = new StringWriter();
             PrintWriter pw = new PrintWriter(sw);
@@ -285,7 +332,8 @@
         }
 
         public void generate(PrintWriter pw) {
-            pw.printf("public %sclass ", getIsAbstract() ? "abstract " : "");
+            generateAccessFlags(pw);
+            pw.print("class ");
             generateName(pw);
             if (superClass != null) {
                 pw.print("extends ");
@@ -299,7 +347,8 @@
                 SourceProcessor processor, Set<Method> neededMethods) {
             StringWriter sw = new StringWriter();
             PrintWriter pw = new PrintWriter(sw);
-            pw.print("public class ");
+            generateAccessFlags(pw);
+            pw.print("class ");
             generateName(pw);
             pw.print(" ");
             generateBodyAsDependency(pw, neededMethods);
@@ -310,13 +359,14 @@
     
     public static class Interface extends Type {
 
-        public Interface(String name, List<TypeParameter> params, 
+        public Interface(String name, 
+                  List<AccessFlag> flags, List<TypeParameter> params, 
                   List<Extends> interfaces, List<Method> methods) {
-            super(name, params, interfaces, methods);
+            super(name, flags, params, interfaces, methods);
         }
 
         public Interface(String name, Element ... components) {
-            super(name, null, null, null);
+            super(name, null, null, null, null);
             for (Element c : components) {
                 addComponent(c);
             }
@@ -334,6 +384,7 @@
         }
 
         public void generate(PrintWriter pw) {
+            generateAccessFlags(pw);
             pw.print("interface ");
             generateName(pw);
             pw.print(" ");
@@ -345,6 +396,7 @@
             StringWriter sw = new StringWriter();
             PrintWriter pw = new PrintWriter(sw);
     
+            generateAccessFlags(pw);
             pw.print("interface ");
             generateName(pw);
             pw.print(" ");
@@ -386,14 +438,27 @@
     public static abstract class Method extends Element {
         private String name;
         private String returnType;
+        private List<AccessFlag> accessFlags;
         private List<MethodParameter> parameters;
         private boolean emitSuppressWarnings;
     
-        protected Method(String ret, String name, MethodParameter ... params) {
+        protected Method(String ret, String name, Element ... params) {
             this.name = name;
             this.returnType = ret;
-            this.parameters = Arrays.asList(params);
+            this.accessFlags = new ArrayList<>();
+            this.parameters = new ArrayList<>();
             this.emitSuppressWarnings = false;
+
+            Arrays.asList(params).stream()
+                .filter(x -> x instanceof MethodParameter)
+                .map(x -> (MethodParameter)x)
+                .into(this.parameters); 
+            Arrays.asList(params).stream()
+                .filter(x -> x instanceof AccessFlag)
+                .map(x -> (AccessFlag)x)
+                .into(this.accessFlags); 
+            assert accessFlags.size() + parameters.size() == params.length : 
+                   "Non method parameters or access flags in constructor";
         }
 
         public String getName() { return this.name; }
@@ -401,15 +466,29 @@
         public List<MethodParameter> getParameters() { 
             return this.parameters;
         }
+        public List<AccessFlag> getAccessFlags() { 
+            return this.accessFlags;
+        }
+        public Element[] getElements() {
+            ArrayList<Element> elements = new ArrayList<>();
+            getParameters().stream().into(elements);
+            getAccessFlags().stream().into(elements);
+            return elements.toArray(new Element[0]);
+        }
 
         public void suppressWarnings() { this.emitSuppressWarnings = true; } 
-        public void generatePrefix(PrintWriter pw) { 
+
+        public void generateWarningSuppression(PrintWriter pw) { 
             if (this.emitSuppressWarnings) {
                 pw.printf("@SuppressWarnings(\"unchecked\")\n    ");
             }
         }
     
         protected void generateDecl(PrintWriter pw) {
+            generateWarningSuppression(pw);
+            pw.print(this.accessFlags.stream()
+                .map(x -> x.toString())
+                .into(new StringJoiner(" ", "", " ")));
             pw.printf("%s %s(", returnType, name);
             pw.print(parameters.stream()
                 .map(x->x.toString())
@@ -418,106 +497,65 @@
         }
     }
     
-    public static class PresentMethod extends Method {
-
-        public PresentMethod(
-                String ret, String name, MethodParameter ... params) {
+    public static class AbstractMethod extends Method {
+        public AbstractMethod(
+                String ret, String name, Element ... params) {
             super(ret, name, params);
-        }
-
-        public PresentMethod() {
-            super("int", SourceModel.stdMethodName);
+            this.getAccessFlags().add(AccessFlag.ABSTRACT);
         }
     
         public void generate(PrintWriter pw) {
-            generatePrefix(pw);
             generateDecl(pw);
             pw.print(";");
         }
-    }
-    
-    public static class AbstractMethod extends Method {
-        public AbstractMethod(
-                String ret, String name, MethodParameter ... params) {
-            super(ret, name, params);
-        }
-    
-        public void generate(PrintWriter pw) {
-            generatePrefix(pw);
-            pw.print("public abstract ");
-            generateDecl(pw);
-            pw.print(";");
+
+        public static AbstractMethod std() {
+            return new AbstractMethod(
+                "int", SourceModel.stdMethodName, AccessFlag.PUBLIC);
         }
     }
 
-    public static abstract class ImplementationMethod extends Method {
+    public static class ConcreteMethod extends Method {
         protected String body;
 
-        protected ImplementationMethod(String ret, String name, 
-                String body, MethodParameter ... params) {
+        public ConcreteMethod(String ret, String name, 
+                String body, Element ... params) {
             super(ret, name, params);
             this.body = body;
         }
 
-        public String getBody() { return this.body; }
-    }
-    
-    public static class ConcreteMethod extends ImplementationMethod {
-
-        public ConcreteMethod(String ret, String name, 
-                String body, MethodParameter ... params) {
-            super(ret, name, body, params);
-        }
-
         public void generate(PrintWriter pw) {
-            generatePrefix(pw);
-            pw.print("public ");
             generateDecl(pw);
             pw.printf(" { %s }", this.body);
         }
     
-        public static ConcreteMethod returns(String value) {
+        public static ConcreteMethod std(String value) {
             return new ConcreteMethod(
-                "int", SourceModel.stdMethodName, "return " + value + ";");
+                "int", SourceModel.stdMethodName, "return " + value + ";",
+                AccessFlag.PUBLIC);
         }
     }
     
-    public static class DefaultMethod extends ImplementationMethod {
+    // When the default method flag gets moved into the traditional 
+    // access flags location, we can remove this class completely and 
+    // use a ConcreteMethod with an AccessFlag("default") in the constructor
+    public static class DefaultMethod extends Method {
+        protected String body;
     
         public DefaultMethod(String ret, String name, String body, 
-                MethodParameter ... params) {
-            super(ret, name, body, params);
+                Element ... params) {
+            super(ret, name, params);
+            this.body = body;
         }
 
         public void generate(PrintWriter pw) {
-            generatePrefix(pw);
             generateDecl(pw);
             pw.printf(" default { %s }", this.body);
         }
     
-        public static DefaultMethod returns(String value) {
+        public static DefaultMethod std(String value) {
             return new DefaultMethod(
                 "int", SourceModel.stdMethodName, "return " + value + ";");
         }
     }
-    
-    public static class StaticMethod extends ImplementationMethod {
-    
-        public StaticMethod(String ret, String name, String body, 
-                     MethodParameter ... params) {
-            super(ret, name, body, params);
-        }
-    
-        public void generate(PrintWriter pw) {
-            generatePrefix(pw);
-            pw.print("public static ");
-            generateDecl(pw);
-            pw.printf(" { %s }", this.body);
-        }
-    
-        public static StaticMethod returns(String value) {
-            return new StaticMethod("int", 
-                SourceModel.stdMethodName, "return " + value + ";");
-        }
-    }
 }
--- a/test-ng/tests/org/openjdk/tests/separate/TestHarness.java	Sat Oct 20 13:44:10 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/separate/TestHarness.java	Sat Oct 20 13:44:44 2012 -0400
@@ -99,9 +99,9 @@
         }
     }
 
-    private static final ConcreteMethod stdCM = ConcreteMethod.returns("-1");
-    private static final PresentMethod stdPM =
-            new PresentMethod("int", stdMethodName);
+    private static final ConcreteMethod stdCM = ConcreteMethod.std("-1");
+    private static final AbstractMethod stdAM =
+            new AbstractMethod("int", stdMethodName);
 
     /**
      * Returns a class which has a static method with the same name as
@@ -117,17 +117,17 @@
             String returns, String ... args) {
         Method cm = new ConcreteMethod(
             method.getReturnType(), method.getName(),
-            "return " + returns + ";",
-            method.getParameters().toArray(new MethodParameter[0]));
+            "return " + returns + ";",  method.getElements());
         Class stub = new Class(specimen.getName(), cm);
 
         String params =
             Arrays.asList(args).stream().into(new StringJoiner(", ")).toString();
 
-        StaticMethod sm = new StaticMethod(
+        ConcreteMethod sm = new ConcreteMethod(
             method.getReturnType(), method.getName(),
             String.format("return (new %s()).%s(%s);",
-                          specimen.getName(), method.getName(), params));
+                          specimen.getName(), method.getName(), params),
+            new AccessFlag("public"), new AccessFlag("static"));
 
         Class iv = new Class("IV_" + specimen.getName(), sm);
 
@@ -145,19 +145,23 @@
      * function call parameters.
      */
     private Class invokeInterfaceHarness(Class specimen, Extends iface,
-            PresentMethod method, String ... args) {
+            AbstractMethod method, String ... args) {
         Interface istub = new Interface(
-            iface.getType().getName(), iface.getType().getParameters(),
+            iface.getType().getName(), iface.getType().getAccessFlags(), 
+            iface.getType().getParameters(),
             null, Arrays.asList((Method)method));
         Class cstub = new Class(specimen.getName());
 
-        String params =
-            Arrays.asList(args).stream().into(new StringJoiner(", ")).toString();
+        String params = Arrays.asList(args).stream().into(
+            new StringJoiner(", ")).toString();
 
-        StaticMethod sm = StaticMethod.returns(
-            String.format("((%s)(new %s())).%s(%s)", iface.toString(),
-                specimen.getName(), method.getName(), params));
+        ConcreteMethod sm = new ConcreteMethod(
+            "int", SourceModel.stdMethodName,
+            String.format("return ((%s)(new %s())).%s(%s);", iface.toString(),
+                specimen.getName(), method.getName(), params),
+            new AccessFlag("public"), new AccessFlag("static"));
         sm.suppressWarnings();
+
         Class ii = new Class("II_" + specimen.getName() + "_" + 
             iface.getType().getName(), sm);
         ii.addCompilationDependency(istub);
@@ -236,7 +240,7 @@
      * 'value' then a test failure is indicated.
      */
     public void assertInvokeInterfaceEquals(Object value, Class target,
-            Extends iface, PresentMethod method, String ... args) {
+            Extends iface, AbstractMethod method, String ... args) {
 
         Compiler compiler = compilerLocal.get();
         compiler.setFlags(compilerFlags());
@@ -259,7 +263,7 @@
         compiler.setFlags(compilerFlags());
 
         assertInvokeInterfaceEquals(
-            new Integer(value), target, new Extends(iface), stdPM);
+            new Integer(value), target, new Extends(iface), stdAM);
 
         compiler.cleanup();
     }
--- a/test-ng/tests/org/openjdk/tests/vm/DefaultMethodsTest.java	Sat Oct 20 13:44:10 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/vm/DefaultMethodsTest.java	Sat Oct 20 13:44:44 2012 -0400
@@ -50,7 +50,7 @@
      * TEST: C c = new C(); c.m() == 22
      */
     public void testHarnessInvokeVirtual() {
-        Class C = new Class("C", ConcreteMethod.returns("22"));
+        Class C = new Class("C", ConcreteMethod.std("22"));
         assertInvokeVirtualEquals(22, C);
     }
 
@@ -61,8 +61,8 @@
      * TEST: I i = new C(); i.m() == 33;
      */
     public void testHarnessInvokeInterface() {
-        Interface I = new Interface("I", new PresentMethod());
-        Class C = new Class("C", I, ConcreteMethod.returns("33"));
+        Interface I = new Interface("I", AbstractMethod.std());
+        Class C = new Class("C", I, ConcreteMethod.std("33"));
         assertInvokeInterfaceEquals(33, C, I);
     }
     
@@ -84,7 +84,7 @@
      * TEST: I i = new C(); i.m() == 44;
      */
     public void testBasicDefault() {
-        Interface I = new Interface("I", DefaultMethod.returns("44"));
+        Interface I = new Interface("I", DefaultMethod.std("44"));
         Class C = new Class("C", I);
 
         assertInvokeVirtualEquals(44, C);
@@ -101,7 +101,7 @@
      * TEST: I i = new C(); i.m() == 44;
      */
     public void testFarDefault() {
-        Interface I = new Interface("I", DefaultMethod.returns("44"));
+        Interface I = new Interface("I", DefaultMethod.std("44"));
         Interface J = new Interface("J", I);
         Interface K = new Interface("K", J);
         Class C = new Class("C", K);
@@ -120,8 +120,8 @@
      * TEST: K k = new C(); k.m() == 44;
      */
     public void testOverrideAbstract() {
-        Interface I = new Interface("I", new PresentMethod());
-        Interface J = new Interface("J", I, DefaultMethod.returns("44"));
+        Interface I = new Interface("I", AbstractMethod.std());
+        Interface J = new Interface("J", I, DefaultMethod.std("44"));
         Interface K = new Interface("K", J);
         Class C = new Class("C", K);
 
@@ -137,8 +137,8 @@
      * TEST: I i = new C(); i.m() == 55;
      */
     public void testExisting() {
-        Interface I = new Interface("I", DefaultMethod.returns("44"));
-        Class C = new Class("C", I, ConcreteMethod.returns("55"));
+        Interface I = new Interface("I", DefaultMethod.std("44"));
+        Class C = new Class("C", I, ConcreteMethod.std("55"));
 
         assertInvokeVirtualEquals(55, C);
         assertInvokeInterfaceEquals(55, C, I);
@@ -153,7 +153,7 @@
      * TEST: I i = new C(); i.m() == 99;
      */
     public void testInherited() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
         Class B = new Class("B", I);
         Class C = new Class("C", B); 
 
@@ -170,8 +170,8 @@
      * TEST: I i = new D(); i.m() == 11;
      */
     public void testExistingInherited() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
-        Class C = new Class("C", ConcreteMethod.returns("11"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
+        Class C = new Class("C", ConcreteMethod.std("11"));
         Class D = new Class("D", C, I);
 
         assertInvokeVirtualEquals(11, D);
@@ -187,9 +187,9 @@
      * TEST: I i = new D(); i.m() == 22;
      */
     void testExistingInheritedOverride() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
-        Class C = new Class("C", I, ConcreteMethod.returns("11"));
-        Class D = new Class("D", C, ConcreteMethod.returns("22"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
+        Class C = new Class("C", I, ConcreteMethod.std("11"));
+        Class D = new Class("D", C, ConcreteMethod.std("22"));
 
         assertInvokeVirtualEquals(22, D);
         assertInvokeInterfaceEquals(22, D, I);
@@ -206,10 +206,10 @@
      * TEST: J j = new E(); j.m() == 22;
      */
     public void testExistingInheritedPlusDefault() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
-        Interface J = new Interface("J", DefaultMethod.returns("88"));
-        Class C = new Class("C", I, ConcreteMethod.returns("11"));
-        Class D = new Class("D", C, ConcreteMethod.returns("22"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
+        Interface J = new Interface("J", DefaultMethod.std("88"));
+        Class C = new Class("C", I, ConcreteMethod.std("11"));
+        Class D = new Class("D", C, ConcreteMethod.std("22"));
         Class E = new Class("E", D, J);
 
         assertInvokeVirtualEquals(22, E);
@@ -225,9 +225,9 @@
      * TEST: I i = new C(); i.m() == 77;
      */
     public void testInheritedWithConcrete() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
         Class B = new Class("B", I);
-        Class C = new Class("C", B, ConcreteMethod.returns("77"));
+        Class C = new Class("C", B, ConcreteMethod.std("77"));
 
         assertInvokeVirtualEquals(77, C);
         assertInvokeInterfaceEquals(77, C, I);
@@ -242,9 +242,9 @@
      * TEST: I i = new C(); i.m() == 66;
      */
     public void testInheritedWithConcreteAndImpl() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
         Class B = new Class("B", I);
-        Class C = new Class("C", B, I, ConcreteMethod.returns("66"));
+        Class C = new Class("C", B, I, ConcreteMethod.std("66"));
 
         assertInvokeVirtualEquals(66, C);
         assertInvokeInterfaceEquals(66, C, I);
@@ -259,8 +259,8 @@
      */
     public void testConflict() {
         // debugTest();
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
-        Interface J = new Interface("J", DefaultMethod.returns("88"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
+        Interface J = new Interface("J", DefaultMethod.std("88"));
         Class C = new Class("C", I, J);
 
         assertThrows(AbstractMethodError.class, C);
@@ -274,8 +274,8 @@
      * TEST: C c = new C(); c.m() throws AME
      */
     public void testAmbiguousReabstract() {
-        Interface I = new Interface("I", new PresentMethod());
-        Interface J = new Interface("J", DefaultMethod.returns("88"));
+        Interface I = new Interface("I", AbstractMethod.std());
+        Interface J = new Interface("J", DefaultMethod.std("88"));
         Class C = new Class("C", I, J);
 
         assertThrows(AbstractMethodError.class, C);
@@ -293,7 +293,7 @@
      * TEST: I i = new C(); i.m() == 99
      */
     public void testDiamond() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
         Interface J = new Interface("J", I);
         Interface K = new Interface("K", I);
         Class C = new Class("C", J, K);
@@ -320,7 +320,7 @@
      * TEST: M m = new C(); m.m() == 99
      */
     public void testExpandedDiamond() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
         Interface J = new Interface("J", I);
         Interface K = new Interface("K", I);
         Interface L = new Interface("L", I);
@@ -343,8 +343,8 @@
      * TEST: C c = new C(); c.m() throws AME
      */
     public void testReabstract() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
-        Interface J = new Interface("J", I, new PresentMethod());
+        Interface I = new Interface("I", DefaultMethod.std("99"));
+        Interface J = new Interface("J", I, AbstractMethod.std());
         Class C = new Class("C", J);
 
         assertThrows(AbstractMethodError.class, C);
@@ -360,8 +360,8 @@
      * TEST: I i = new C(); i.m() == 99;
      */
     public void testShadow() {
-        Interface I = new Interface("I", DefaultMethod.returns("88"));
-        Interface J = new Interface("J", I, DefaultMethod.returns("99"));
+        Interface I = new Interface("I", DefaultMethod.std("88"));
+        Interface J = new Interface("J", I, DefaultMethod.std("99"));
         Class C = new Class("C", J);
 
         assertInvokeVirtualEquals(99, C);
@@ -379,8 +379,8 @@
      * TEST: I i = new C(); i.m() == 99;
      */
     public void testDisqualified() {
-        Interface I = new Interface("I", DefaultMethod.returns("88"));
-        Interface J = new Interface("J", I, DefaultMethod.returns("99"));
+        Interface I = new Interface("I", DefaultMethod.std("88"));
+        Interface J = new Interface("J", I, DefaultMethod.std("99"));
         Class C = new Class("C", I, J);
 
         assertInvokeVirtualEquals(99, C);
@@ -405,12 +405,13 @@
         DefaultMethod dm = new DefaultMethod(
             "int", "m", "return 99;", new MethodParameter("T", "t")); 
         ConcreteMethod cm = new ConcreteMethod(
-            "int", "m", "return 88;", new MethodParameter("String", "s")); 
+            "int", "m", "return 88;", AccessFlag.PUBLIC, 
+            new MethodParameter("String", "s")); 
 
         Interface I = new Interface("I", new TypeParameter("T"), dm);
         Class C = new Class("C", I.with("String"), cm);
 
-        PresentMethod pm = new PresentMethod(
+        AbstractMethod pm = new AbstractMethod(
             "int", "m", new MethodParameter("T", "t"));
 
         assertInvokeVirtualEquals(new Integer(88), C, cm, "-1", "\"string\"");
@@ -425,7 +426,7 @@
      * TEST: C.class.getMethod("m").invoke(new C()) == 99
      */
     public void testReflectCall() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
         Class C = new Class("C", I);
  
         Compiler.Flags[] flags = this.verbose ? 
@@ -486,19 +487,20 @@
             new MethodParameter("T", "t"), new MethodParameter("V", "v"), 
             new MethodParameter("W", "w"));
 
-        PresentMethod pm0 = new PresentMethod("int", stdMethodName,
+        AbstractMethod pm0 = new AbstractMethod("int", stdMethodName,
             new MethodParameter("T", "t"), new MethodParameter("V", "v"), 
             new MethodParameter("W", "w"));
 
-        PresentMethod pm1 = new PresentMethod("int", stdMethodName,
+        AbstractMethod pm1 = new AbstractMethod("int", stdMethodName,
             new MethodParameter("T", "t"), new MethodParameter("V", "v"), 
             new MethodParameter("String", "w"));
 
-        PresentMethod pm2 = new PresentMethod("int", stdMethodName,
+        AbstractMethod pm2 = new AbstractMethod("int", stdMethodName,
             new MethodParameter("T", "t"), new MethodParameter("String", "v"), 
             new MethodParameter("String", "w"));
 
         ConcreteMethod cm = new ConcreteMethod("int",stdMethodName,"return 88;",
+            AccessFlag.PUBLIC,
             new MethodParameter("String", "t"), 
             new MethodParameter("String", "v"), 
             new MethodParameter("String", "w"));
@@ -532,7 +534,7 @@
     public void testSuperBasic() {
         // debugTest();
 
-        Interface J = new Interface("J", DefaultMethod.returns("88"));
+        Interface J = new Interface("J", DefaultMethod.std("88"));
         Interface I = new Interface("I", J, new DefaultMethod(
             "int", stdMethodName, "return J.super.m();"));
         I.addCompilationDependency(J.findMethod(stdMethodName));
@@ -555,12 +557,12 @@
     public void testSuperConflict() {
         // debugTest();
 
-        Interface K = new Interface("K", DefaultMethod.returns("99"));
-        Interface L = new Interface("L", DefaultMethod.returns("101"));
+        Interface K = new Interface("K", DefaultMethod.std("99"));
+        Interface L = new Interface("L", DefaultMethod.std("101"));
         Interface J = new Interface("J", K, L);
         Interface I = new Interface("I", J, K, new DefaultMethod(
             "int", stdMethodName, "return J.super.m();"));
-        Interface Jstub = new Interface("J", DefaultMethod.returns("-1"));
+        Interface Jstub = new Interface("J", DefaultMethod.std("-1"));
         I.addCompilationDependency(Jstub);
         I.addCompilationDependency(Jstub.findMethod(stdMethodName));
         Class C = new Class("C", I);
@@ -577,10 +579,11 @@
      * TODO: add case for J j = new C(); j.m() throws AME
      */
     public void testSuperDisqual() {
-        Interface I = new Interface("I", DefaultMethod.returns("99"));
-        Interface J = new Interface("J", I, DefaultMethod.returns("55"));
-        Class C = new Class("C", I, J, new ConcreteMethod(
-            "int", stdMethodName, "return I.super.m();"));
+        Interface I = new Interface("I", DefaultMethod.std("99"));
+        Interface J = new Interface("J", I, DefaultMethod.std("55"));
+        Class C = new Class("C", I, J, 
+            new ConcreteMethod("int", stdMethodName, "return I.super.m();", 
+                AccessFlag.PUBLIC));
         C.addCompilationDependency(I.findMethod(stdMethodName));
 
         assertThrows(AbstractMethodError.class, C);
@@ -595,10 +598,10 @@
      * TODO: add case for I i = new C(); i.m() throws AME
      */
     public void testSuperNull() {
-        Interface J = new Interface("J", new PresentMethod());
+        Interface J = new Interface("J", AbstractMethod.std());
         Interface I = new Interface("I", J, new DefaultMethod(
             "int", stdMethodName, "return J.super.m();"));
-        Interface Jstub = new Interface("J", DefaultMethod.returns("99"));
+        Interface Jstub = new Interface("J", DefaultMethod.std("99"));
         I.addCompilationDependency(Jstub);
         I.addCompilationDependency(Jstub.findMethod(stdMethodName));
         Class C = new Class("C", I);
@@ -625,7 +628,7 @@
         I.addCompilationDependency(J.findMethod(stdMethodName));
         Class C = new Class("C", I);
 
-        PresentMethod pm = new PresentMethod("int", stdMethodName, 
+        AbstractMethod pm = new AbstractMethod("int", stdMethodName, 
             new MethodParameter("String", "s"));
 
         assertInvokeInterfaceEquals(
@@ -650,11 +653,13 @@
         Interface J = new Interface("J", I.with("String"), 
             new DefaultMethod("int", stdMethodName, "return 55;", s));
         Class C = new Class("C", I.with("String"), J, 
-            new ConcreteMethod("int", stdMethodName,"return I.super.m(s);", s));
+            new ConcreteMethod("int", stdMethodName,
+                "return I.super.m(s);", AccessFlag.PUBLIC, s));
         C.addCompilationDependency(I.findMethod(stdMethodName));
 
         assertThrows(AbstractMethodError.class, C, 
-            new ConcreteMethod("int", stdMethodName, "return -1;", s), 
+            new ConcreteMethod(
+                "int", stdMethodName, "return -1;", AccessFlag.PUBLIC, s), 
             "-1", "\"string\"");
     }
 
@@ -669,15 +674,15 @@
         Interface I = new Interface("I", new DefaultMethod(
             "Integer", "m", "return new Integer(88);"));
         Class C = new Class("C", new ConcreteMethod(
-            "Number", "m", "return new Integer(99);"));
+            "Number", "m", "return new Integer(99);", AccessFlag.PUBLIC));
         Class D = new Class("D", I, C);
 
-        ConcreteMethod DstubMethod = 
-            new ConcreteMethod("Integer", "m", "return null;");
+        ConcreteMethod DstubMethod = new ConcreteMethod(
+            "Integer", "m", "return null;", AccessFlag.PUBLIC);
         Class Dstub = new Class("D", DstubMethod);
 
         ConcreteMethod toCall = new ConcreteMethod(
-            "Object", "foo", "return (new D()).m();");
+            "Object", "foo", "return (new D()).m();", AccessFlag.PUBLIC);
         Class S = new Class("S", D, toCall);
         S.addCompilationDependency(Dstub);
         S.addCompilationDependency(DstubMethod);
@@ -696,15 +701,15 @@
         Interface I = new Interface("I", new DefaultMethod(
             "Integer", "m", "return new Integer(88);"));
         Class C = new Class("C", new ConcreteMethod(
-            "int", "m", "return 99;"));
+            "int", "m", "return 99;", AccessFlag.PUBLIC));
         Class D = new Class("D", I, C);
 
-        ConcreteMethod DstubMethod = 
-            new ConcreteMethod("Integer", "m", "return null;");
+        ConcreteMethod DstubMethod = new ConcreteMethod(
+            "Integer", "m", "return null;", AccessFlag.PUBLIC);
         Class Dstub = new Class("D", DstubMethod);
 
         ConcreteMethod toCall = new ConcreteMethod(
-            "Object", "foo", "return (new D()).m();");
+            "Object", "foo", "return (new D()).m();", AccessFlag.PUBLIC);
         Class S = new Class("S", D, toCall);
         S.addCompilationDependency(Dstub);
         S.addCompilationDependency(DstubMethod);
@@ -725,8 +730,8 @@
      * inherited and the supertypes don't have any overpass methods.
      */   
     public void testNoNewMiranda() {
-        Interface J = new Interface("J", new PresentMethod());
-        Interface I = new Interface("I", J, DefaultMethod.returns("99"));
+        Interface J = new Interface("J", AbstractMethod.std());
+        Interface I = new Interface("I", J, DefaultMethod.std("99"));
         Class B = new Class("B", J);
         Class C = new Class("C", B, I);
         assertInvokeVirtualEquals(99, C);
@@ -748,7 +753,7 @@
      * non-language-level matching methods
      */
     public void testNonConcreteFill() {
-        PresentMethod ipm = new PresentMethod("int", "m", 
+        AbstractMethod ipm = new AbstractMethod("int", "m", 
             new MethodParameter("T", "t"),
             new MethodParameter("V", "s"), 
             new MethodParameter("W", "w")); 
@@ -757,7 +762,7 @@
             new TypeParameter("V"), 
             new TypeParameter("W"), ipm);
 
-        PresentMethod jpm = new PresentMethod("int", "m", 
+        AbstractMethod jpm = new AbstractMethod("int", "m", 
             new MethodParameter("T", "t"),
             new MethodParameter("V", "s"), 
             new MethodParameter("String", "w")); 
@@ -766,7 +771,7 @@
             new TypeParameter("V"), 
             I.with("T", "V", "String"), jpm);
 
-        PresentMethod kpm = new PresentMethod("int", "m", 
+        AbstractMethod kpm = new AbstractMethod("int", "m", 
             new MethodParameter("T", "t"),
             new MethodParameter("String", "s"), 
             new MethodParameter("String", "w")); 
@@ -781,6 +786,7 @@
         Class C = new Class("C",
             K.with("String"),
             new ConcreteMethod("int", "m", "return 77;",
+                AccessFlag.PUBLIC,
                 new MethodParameter("Object", "t"),
                 new MethodParameter("Object", "v"),
                 new MethodParameter("String", "w")));
--- a/test-ng/tests/org/openjdk/tests/vm/FDSeparateCompilationTest.java	Sat Oct 20 13:44:10 2012 -0400
+++ b/test-ng/tests/org/openjdk/tests/vm/FDSeparateCompilationTest.java	Sat Oct 20 13:44:44 2012 -0400
@@ -85,7 +85,7 @@
     }
 
     private static final ConcreteMethod canonicalMethod = new ConcreteMethod(
-            "String", "m", "returns " + EMPTY + ";");
+            "String", "m", "returns " + EMPTY + ";", AccessFlag.PUBLIC);
 
     @Test(groups = "vm", dataProvider = "allShapes")
     public void separateCompilationTest(Hierarchy hs) {
@@ -95,7 +95,7 @@
         Class specimen = null;
         if (type instanceof Class) {
             Class ctype = (Class)type;
-            if (ctype.getIsAbstract()) {
+            if (ctype.isAbstract()) {
                 specimen = new Class("Test" + ctype.getName(), ctype);
             } else {
                 specimen = ctype;
@@ -159,7 +159,7 @@
                 cls.addSuperType(supertype);
             }
             if (cc.isAbstract()) { 
-                cls.setIsAbstract(true);  
+                cls.getAccessFlags().add(AccessFlag.ABSTRACT);  
             }
             type = cls;
         }
@@ -175,15 +175,15 @@
             case IVAC: 
             case CNONE: return null; 
             case IPRESENT: 
-                return new PresentMethod("String", "m"); 
+            case CABSTRACT:
+                return new AbstractMethod("String", "m", AccessFlag.PUBLIC); 
             case IDEFAULT:
                 return new DefaultMethod(
                     "String", "m", "return \"" + cc.getName() + "\";");
-            case CABSTRACT:
-                return new AbstractMethod("String", "m"); 
             case CCONCRETE:
                 return new ConcreteMethod(
-                    "String", "m", "return \"" + cc.getName() + "\";");
+                    "String", "m", "return \"" + cc.getName() + "\";", 
+                    AccessFlag.PUBLIC);
             default:
                 fail("Unknown method type in class");
                 return null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/vm/InterfaceAccessFlagsTest.java	Sat Oct 20 13:44:44 2012 -0400
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.openjdk.tests.vm;
+
+import java.io.*;
+
+import org.testng.annotations.Test;
+import org.openjdk.tests.separate.*;
+import org.openjdk.tests.separate.Compiler;
+
+import static org.testng.Assert.*;
+import static org.openjdk.tests.separate.SourceModel.*;
+import static org.openjdk.tests.separate.SourceModel.Class;
+
+public class InterfaceAccessFlagsTest extends TestHarness {
+    public InterfaceAccessFlagsTest() {
+        super(false, false);
+    }
+
+    public void testMethodCallWithFlag(AccessFlag ... flags) {
+        Class I = new Class("I", 
+            new ConcreteMethod("int", "m", "return priv();", AccessFlag.PUBLIC),
+            new ConcreteMethod("int", "priv", "return 99;", flags));
+        Interface Istub = new Interface("I", 
+            new DefaultMethod("int", "m", "return 0;"));
+        Class C = new Class("C", Istub, 
+            new ConcreteMethod("int", "foo", "return (new C()).m();", 
+                AccessFlag.PUBLIC, AccessFlag.STATIC));
+        C.addCompilationDependency(Istub.findMethod("m"));
+
+        Compiler compiler = new Compiler(/*Compiler.Flags.VERBOSE*/);
+        compiler.addPostprocessor(new ClassToInterfaceConverter("I"));
+        // Turns I from a class into an interface when loading
+
+        ClassLoader cl = compiler.compile(C, I);
+        try {
+            java.lang.Class<?> C_class = 
+                java.lang.Class.forName("C", true, cl);
+            assertNotNull(C_class); 
+            java.lang.reflect.Method m = C_class.getMethod("foo");
+            assertNotNull(m); 
+            Integer res = (Integer)m.invoke(null);
+            assertEquals(res.intValue(), 99);
+        } catch (java.lang.reflect.InvocationTargetException e) {
+            fail("Unexpected exception: " + e.getCause());
+        } catch (Throwable e) {
+            fail("Unexpected exception: " + e);
+        } finally {
+            compiler.cleanup();
+        }
+    }
+
+    @Test(groups = "vm_prototype")
+    public void testPrivateMethodCall() {
+        testMethodCallWithFlag(AccessFlag.PRIVATE);
+    }
+
+    @Test(groups = "vm_prototype")
+    public void testStaticMethodCall() {
+        testMethodCallWithFlag(AccessFlag.PUBLIC, AccessFlag.STATIC);
+    }
+
+    @Test(groups = "vm_prototype")
+    public void testPrivateStaticMethodCall() {
+        testMethodCallWithFlag(AccessFlag.PRIVATE, AccessFlag.STATIC);
+    }
+
+    // Test other combos?  Protected?
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/vm/JVMBridgingTest.java	Sat Oct 20 13:44:44 2012 -0400
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.openjdk.tests.vm;
+
+import java.io.*;
+
+import org.testng.annotations.Test;
+import org.openjdk.tests.separate.*;
+import org.openjdk.tests.separate.Compiler;
+
+import static org.testng.Assert.*;
+import static org.openjdk.tests.separate.SourceModel.*;
+import static org.openjdk.tests.separate.SourceModel.Class;
+
+public class JVMBridgingTest extends TestHarness {
+    public JVMBridgingTest() {
+        super(false, false);
+    }
+
+    private static final String STATIC_CLASS = "S";
+    private static final String STATIC_METHOD_NAME = "foo";
+    private static final int SUCCESS_VALUE = 99;
+
+    enum BridgeMode { AUTO_BRIDGE, NO_AUTO_BRIDGE };
+
+    private boolean equalsSuccessValue(
+            BridgeMode mode, Type[] compUnits) {
+        Compiler compiler = new Compiler(); 
+
+        if (mode == BridgeMode.AUTO_BRIDGE) {
+            compiler.addPostprocessor(
+                new AttributeInjector("RequiresBridges", new byte[0]));
+        }
+
+        ClassLoader cl = compiler.compile(compUnits);
+
+        try {
+            java.lang.Class<?> S_class = 
+                java.lang.Class.forName(STATIC_CLASS, true, cl);
+            assertNotNull(S_class); 
+            java.lang.reflect.Method m = S_class.getMethod(STATIC_METHOD_NAME);
+            assertNotNull(m); 
+            Integer res = (Integer)m.invoke(null);
+            return res.intValue() == SUCCESS_VALUE;
+        } catch (ClassNotFoundException e) {
+            fail("Could not find class");
+        } catch (NoSuchMethodException e) {
+            fail("Could not find method");
+        } catch (IllegalAccessException e) {
+            fail("Unexpected IllegalAccessException");
+        } catch (java.lang.reflect.InvocationTargetException e) {
+            return false; /* A valid situation: the method may not exist */
+        } finally {
+            compiler.cleanup();
+        }
+        fail("Unexpected result");
+        return false; // unreachable
+    }
+
+    public Type[] setupTraditionalBridgeTest() {
+        Interface I = new Interface("I", new TypeParameter("T"), 
+            new AbstractMethod("int", "m", new MethodParameter("T", "t")));
+        Class C = new Class("C", I.with("String"), new ConcreteMethod(
+            "int", "m", "return " + SUCCESS_VALUE + ";", AccessFlag.PUBLIC, 
+            new MethodParameter("String", "s")));
+        ConcreteMethod mStub = new ConcreteMethod(
+            "int", "m", "return 0;", AccessFlag.PUBLIC, 
+            new MethodParameter("Object", "o"));
+        Class Cstub = new Class("C", mStub);
+        Class S = new Class(STATIC_CLASS, new ConcreteMethod(
+            "int", STATIC_METHOD_NAME, "return (new C()).m(\"\");",
+            AccessFlag.PUBLIC, AccessFlag.STATIC));
+        S.addCompilationDependency(Cstub);
+        S.addCompilationDependency(mStub);
+        
+        return new Type[] { S, C, I };
+    }
+
+    private void runTest(Type[] compUnits) {
+        assertFalse(equalsSuccessValue(BridgeMode.NO_AUTO_BRIDGE, compUnits));
+        assertTrue(equalsSuccessValue(BridgeMode.AUTO_BRIDGE, compUnits));
+    }
+
+    @Test(groups = "vm_prototype")
+    public void testTraditionalBridge() {
+        runTest(setupTraditionalBridgeTest());
+    }
+
+    public Type[] setupCovarReturnTest() {
+        ConcreteMethod numberRet = new ConcreteMethod(
+            "Number", "m", "return 0;", AccessFlag.PUBLIC);
+        Class C = new Class("C", numberRet);
+        Class D = new Class("D", C, new ConcreteMethod("Integer", "m", 
+            "return " + SUCCESS_VALUE + ";", AccessFlag.PUBLIC)); 
+
+        Class Dstub = new Class("D", numberRet);
+        Class S = new Class(STATIC_CLASS, 
+            new ConcreteMethod("Integer", STATIC_METHOD_NAME, 
+                "return (Integer)(new D()).m();", 
+                AccessFlag.PUBLIC, AccessFlag.STATIC));
+        S.addCompilationDependency(Dstub);
+        S.addCompilationDependency(numberRet);
+ 
+        return new Type[] { S, D, C };
+    }
+
+    @Test(groups = "vm_prototype")
+    public void testCovarReturn() {
+        runTest(setupCovarReturnTest());
+    }
+
+    @Test(groups = "vm")
+    public void testNoBridgeNeeded() {
+        Interface I = new Interface("I", new TypeParameter("T"), 
+            new AbstractMethod("int", "m", new MethodParameter("T", "t")));
+
+        ConcreteMethod implementing = new ConcreteMethod("int", "m", 
+            "return 0;", AccessFlag.PUBLIC, new MethodParameter("String", "s"));
+        ConcreteMethod matching = new ConcreteMethod("int", "m", "return 99;", 
+            AccessFlag.PUBLIC, new MethodParameter("Object", "o"));
+
+        Class C = new Class("C", I.with("String"), implementing, matching);
+
+        Class S = new Class(STATIC_CLASS, new ConcreteMethod(
+            "int", STATIC_METHOD_NAME, "return (new C()).m(new Object());",
+            AccessFlag.PUBLIC, AccessFlag.STATIC));
+        S.addCompilationDependency(C);
+        S.addCompilationDependency(matching);
+        
+        Type[] compUnits = new Type[] { S, C, I };
+        assertTrue(equalsSuccessValue(BridgeMode.AUTO_BRIDGE, compUnits));
+    }
+}