changeset 59335:af87462e8dd4 foreign

8222919: jextract should compile generated java sources rather than use ASM to generate class files Reviewed-by: henryjen, jvernee
author sundar
date Fri, 26 Apr 2019 08:03:40 +0530
parents eba5ab1f9cd7
children 664abc4e7063
files src/java.base/share/classes/module-info.java src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactory.java src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactoryExt.java src/jdk.jextract/share/classes/com/sun/tools/jextract/InMemoryJavaCompiler.java src/jdk.jextract/share/classes/com/sun/tools/jextract/JModWriter.java src/jdk.jextract/share/classes/com/sun/tools/jextract/JType.java src/jdk.jextract/share/classes/com/sun/tools/jextract/JarWriter.java src/jdk.jextract/share/classes/com/sun/tools/jextract/JavaSourceFactory.java src/jdk.jextract/share/classes/com/sun/tools/jextract/JavaSourceFactoryExt.java src/jdk.jextract/share/classes/com/sun/tools/jextract/JextractTool.java src/jdk.jextract/share/classes/com/sun/tools/jextract/Writer.java src/jdk.jextract/share/classes/module-info.java test/jdk/com/sun/tools/jextract/Runner.java
diffstat 13 files changed, 203 insertions(+), 1024 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/module-info.java	Fri Apr 19 15:03:19 2019 +0530
+++ b/src/java.base/share/classes/module-info.java	Fri Apr 26 08:03:40 2019 +0530
@@ -167,8 +167,7 @@
         jdk.jartool,
         jdk.jfr,
         jdk.jlink,
-        jdk.scripting.nashorn,
-        jdk.jextract;
+        jdk.scripting.nashorn;
     exports jdk.internal.org.objectweb.asm.tree to
         jdk.jfr,
         jdk.jlink;
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactory.java	Fri Apr 19 15:03:19 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,490 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- *
- * 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 com.sun.tools.jextract;
-
-import java.foreign.layout.Layout;
-import java.nio.file.Path;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.sun.tools.jextract.parser.MacroParser;
-import jdk.internal.clang.SourceLocation;
-import jdk.internal.clang.Type;
-import jdk.internal.org.objectweb.asm.AnnotationVisitor;
-import jdk.internal.org.objectweb.asm.ClassVisitor;
-import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.MethodVisitor;
-import com.sun.tools.jextract.tree.EnumTree;
-import com.sun.tools.jextract.tree.FieldTree;
-import com.sun.tools.jextract.tree.FunctionTree;
-import com.sun.tools.jextract.tree.MacroTree;
-import com.sun.tools.jextract.tree.SimpleTreeVisitor;
-import com.sun.tools.jextract.tree.StructTree;
-import com.sun.tools.jextract.tree.Tree;
-import com.sun.tools.jextract.tree.TypedefTree;
-import com.sun.tools.jextract.tree.VarTree;
-
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ANNOTATION;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS;
-import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
-import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN;
-import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN;
-import static jdk.internal.org.objectweb.asm.Opcodes.I2B;
-import static jdk.internal.org.objectweb.asm.Opcodes.I2C;
-import static jdk.internal.org.objectweb.asm.Opcodes.I2S;
-import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
-import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
-import static jdk.internal.org.objectweb.asm.Opcodes.V1_8;
-
-/**
- * Scan a header file and generate classes for entities defined in that header
- * file. Tree visitor visit methods return true/false depending on whether a
- * particular Tree is processed or skipped.
- */
-class AsmCodeFactory extends SimpleTreeVisitor<Boolean, JType> {
-    private static final String ANNOTATION_PKG_PREFIX = "Ljava/foreign/annotations/";
-    private static final String NATIVE_CALLBACK = ANNOTATION_PKG_PREFIX + "NativeCallback;";
-    private static final String NATIVE_HEADER = ANNOTATION_PKG_PREFIX + "NativeHeader;";
-    private static final String NATIVE_LOCATION = ANNOTATION_PKG_PREFIX + "NativeLocation;";
-    private static final String NATIVE_STRUCT = ANNOTATION_PKG_PREFIX + "NativeStruct;";
-    private static final String NATIVE_FUNCTION = ANNOTATION_PKG_PREFIX + "NativeFunction;";
-    private static final String NATIVE_GETTER = ANNOTATION_PKG_PREFIX + "NativeGetter;";
-    private static final String NATIVE_SETTER = ANNOTATION_PKG_PREFIX + "NativeSetter;";
-    private static final String NATIVE_ADDRESSOF = ANNOTATION_PKG_PREFIX + "NativeAddressof;";
-    private static final String NATIVE_NUM_CONST = ANNOTATION_PKG_PREFIX + "NativeNumericConstant;";
-    private static final String NATIVE_STR_CONST = ANNOTATION_PKG_PREFIX + "NativeStringConstant;";
-
-    private final ClassWriter global_cw;
-    private final Set<Layout> global_layouts = new LinkedHashSet<>();
-    protected final String headerClassName;
-    protected final HeaderFile headerFile;
-    protected final Map<String, byte[]> types;
-    protected final List<String> libraryNames;
-    protected final List<String> libraryPaths;
-    protected final boolean noNativeLocations;
-
-    protected final Log log;
-
-    AsmCodeFactory(Context ctx, HeaderFile header) {
-        this.log = ctx.log;
-        log.print(Level.INFO, () -> "Instantiate AsmCodeFactory for " + header.path);
-        this.headerFile = header;
-        this.headerClassName = Utils.toInternalName(headerFile.pkgName, headerFile.headerClsName);
-        this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
-        this.types = new HashMap<>();
-        this.libraryNames = ctx.options.libraryNames;
-        this.libraryPaths = ctx.options.recordLibraryPath? ctx.options.libraryPaths : null;
-        this.noNativeLocations = ctx.options.noNativeLocations;
-        global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
-                headerClassName,
-                null, "java/lang/Object", null);
-    }
-
-    public Map<String, byte[]> generateNativeHeader(List<Tree> decls) {
-        //generate all decls
-        decls.forEach(this::generateDecl);
-        //generate functional interfaces
-        headerFile.dictionary().functionalInterfaces()
-                .forEach(fi -> createFunctionalInterface((JType.FunctionalInterfaceType)fi));
-
-        //generate header intf
-        AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true);
-        av.visit("path", headerFile.path.toAbsolutePath().toString());
-        if (!libraryNames.isEmpty()) {
-            AnnotationVisitor libNames = av.visitArray("libraries");
-            for (String name : libraryNames) {
-                libNames.visit(null, name);
-            }
-            libNames.visitEnd();
-            if (libraryPaths != null && !libraryPaths.isEmpty()) {
-                AnnotationVisitor libPaths = av.visitArray("libraryPaths");
-                for (String path : libraryPaths) {
-                    libPaths.visit(null, path);
-                }
-                libPaths.visitEnd();
-            }
-        }
-
-        AnnotationVisitor resolutionContext = av.visitArray("resolutionContext");
-        headerFile.dictionary().resolutionRoots()
-                .forEach(jt -> resolutionContext.visit(null,
-                        jdk.internal.org.objectweb.asm.Type.getObjectType(jt.clsName)));
-        resolutionContext.visitEnd();
-        AnnotationVisitor globals = av.visitArray("globals");
-        global_layouts.stream().map(Layout::toString).forEach(s -> globals.visit(null, s));
-        globals.visitEnd();
-        av.visitEnd();
-        global_cw.visitEnd();
-        addClassIfNeeded(headerClassName, global_cw.toByteArray());
-        return Collections.unmodifiableMap(types);
-    }
-
-    private void handleException(Exception ex) {
-        log.printError("cannot.write.class.file", headerFile.pkgName + "." + headerFile.headerClsName, ex);
-        log.printStackTrace(ex);
-    }
-
-    private void annotateNativeLocation(ClassVisitor cw, Tree tree) {
-        if (! noNativeLocations) {
-            AnnotationVisitor av = cw.visitAnnotation(NATIVE_LOCATION, true);
-            SourceLocation src = tree.location();
-            SourceLocation.Location loc = src.getFileLocation();
-            Path p = loc.path();
-            av.visit("file", p == null ? "<builtin>" : p.toAbsolutePath().toString());
-            av.visit("line", loc.line());
-            av.visit("column", loc.column());
-            av.visitEnd();
-        }
-    }
-
-    private void addClassIfNeeded(String clsName, byte[] bytes) {
-        if (null != types.put(clsName, bytes)) {
-            log.printWarning("warn.class.overwritten", clsName);
-        }
-    }
-
-    private static boolean isBitField(Tree tree) {
-        return tree instanceof FieldTree && ((FieldTree)tree).isBitField();
-    }
-
-    /**
-     *
-     * @param cw ClassWriter for the struct
-     * @param tree The Tree
-     * @param parentType The struct type
-     */
-    private boolean addField(ClassVisitor cw, Tree tree, Type parentType) {
-        String fieldName = tree.name();
-        assert !fieldName.isEmpty();
-        Type type = tree.type();
-        JType jt = headerFile.dictionary().lookup(type);
-        assert (jt != null);
-        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$get",
-                "()" + jt.getDescriptor(), "()" + jt.getSignature(false), null);
-        jt.visitInner(cw);
-
-        if (! noNativeLocations) {
-            AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
-            SourceLocation src = tree.location();
-            SourceLocation.Location loc = src.getFileLocation();
-            Path p = loc.path();
-            av.visit("file", p == null ? "<builtin>" : p.toAbsolutePath().toString());
-            av.visit("line", loc.line());
-            av.visit("column", loc.column());
-            av.visitEnd();
-        }
-
-        AnnotationVisitor av = mv.visitAnnotation(NATIVE_GETTER, true);
-        av.visit("value", fieldName);
-        av.visitEnd();
-
-        mv.visitEnd();
-        mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$set",
-                "(" + jt.getDescriptor() + ")V",
-                "(" + jt.getSignature(true) + ")V", null);
-        jt.visitInner(cw);
-        av = mv.visitAnnotation(NATIVE_SETTER, true);
-        av.visit("value", fieldName);
-        av.visitEnd();
-        mv.visitEnd();
-
-        if (tree instanceof VarTree || !isBitField(tree)) {
-            JType ptrType = JType.GenericType.ofPointer(jt);
-            mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$ptr",
-                    "()" + ptrType.getDescriptor(), "()" + ptrType.getSignature(false), null);
-            ptrType.visitInner(cw);
-            av = mv.visitAnnotation(NATIVE_ADDRESSOF, true);
-            av.visit("value", fieldName);
-            av.visitEnd();
-            mv.visitEnd();
-        }
-
-        return true;
-    }
-
-    @Override
-    public Boolean visitVar(VarTree varTree, JType jt) {
-        global_layouts.add(varTree.layout().withAnnotation(Layout.NAME, varTree.name()));
-        return addField(global_cw, varTree, null);
-    }
-
-    private void addConstant(ClassWriter cw, SourceLocation src, String name, JType type, Object value) {
-        String desc = "()" + type.getDescriptor();
-        String sig = "()" + type.getSignature(false);
-        MethodVisitor mv = global_cw.visitMethod(ACC_ABSTRACT | ACC_PUBLIC, name, desc, sig, null);
-        type.visitInner(cw);
-
-        if (! noNativeLocations) {
-            AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
-            SourceLocation.Location loc = src.getFileLocation();
-            Path p = loc.path();
-            av.visit("file", p == null ? "<builtin>" : p.toAbsolutePath().toString());
-            av.visit("line", loc.line());
-            av.visit("column", loc.column());
-            av.visitEnd();
-        }
-
-        if (value instanceof String) {
-            AnnotationVisitor av = mv.visitAnnotation(NATIVE_STR_CONST, true);
-            av.visit("value", value);
-            av.visitEnd();
-        } else {
-            //numeric (int, long or double)
-            final long longValue;
-            if (value instanceof Integer) {
-                longValue = (Integer)value;
-            } else if (value instanceof Long) {
-                longValue = (Long)value;
-            } else if (value instanceof Double) {
-                longValue = Double.doubleToRawLongBits((Double)value);
-            } else {
-                throw new IllegalStateException("Unexpected constant: " + value);
-            }
-            AnnotationVisitor av = mv.visitAnnotation(NATIVE_NUM_CONST, true);
-            av.visit("value", longValue);
-            av.visitEnd();
-        }
-        mv.visitEnd();
-    }
-
-    @Override
-    public Boolean visitStruct(StructTree structTree, JType jt) {
-        //generate nested structs recursively
-        structTree.nestedTypes().forEach(this::generateDecl);
-
-        if (structTree.isAnonymous()) {
-            //skip anonymous
-            return false;
-        }
-        String nativeName = structTree.name();
-        Type type = structTree.type();
-        log.print(Level.FINE, () -> "Create struct: " + nativeName);
-
-        String intf = Utils.toClassName(nativeName);
-        String name = headerClassName + "$" + intf;
-
-        log.print(Level.FINE, () -> "Define class " + name + " for native type " + nativeName);
-        /* FIXME: Member interface is implicit static, also ASM.CheckClassAdapter is not
-         * taking static as a valid flag, so comment this out during development.
-         */
-        global_cw.visitInnerClass(name, headerClassName, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
-        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
-        cw.visit(V1_8, ACC_PUBLIC /*| ACC_STATIC*/ | ACC_INTERFACE | ACC_ABSTRACT,
-                name, "Ljava/lang/Object;Ljava/foreign/memory/Struct<L" + name + ";>;",
-                "java/lang/Object", new String[] {"java/foreign/memory/Struct"});
-        annotateNativeLocation(cw, structTree);
-
-        AnnotationVisitor av = cw.visitAnnotation(NATIVE_STRUCT, true);
-        Layout structLayout = structTree.layout();
-        av.visit("value", structLayout.toString());
-        av.visitEnd();
-        cw.visitInnerClass(name, headerClassName, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
-
-        // fields
-        structTree.fields().forEach(fieldTree -> addField(cw, fieldTree, type));
-        // Write class
-        cw.visitEnd();
-        addClassIfNeeded(headerClassName + "$" + intf, cw.toByteArray());
-        return true;
-    }
-
-    @Override
-    public Boolean visitEnum(EnumTree enumTree, JType jt) {
-        // define enum constants in global_cw
-        enumTree.constants().forEach(constant -> addConstant(global_cw,
-                constant.location(),
-                constant.name(),
-                headerFile.dictionary().lookup(constant.type()),
-                constant.enumConstant().get()));
-
-        if (enumTree.name().isEmpty()) {
-            // We are done with anonymous enum
-            return true;
-        }
-
-        // generate annotation class for named enum
-        createAnnotationCls(enumTree);
-        return true;
-    }
-
-    private void createAnnotationCls(Tree tree) {
-        String nativeName = tree.name();
-        log.print(Level.FINE, () -> "Create annotation for: " + nativeName);
-
-        String intf = Utils.toClassName(nativeName);
-        String name = headerClassName + "$" + intf;
-
-        log.print(Level.FINE, () -> "Define class " + name + " for native type " + nativeName);
-        global_cw.visitInnerClass(name, headerClassName, intf,
-                ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
-        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
-        String[] superAnno = { "java/lang/annotation/Annotation" };
-        cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION,
-                name, null, "java/lang/Object", superAnno);
-        annotateNativeLocation(cw, tree);
-        AnnotationVisitor av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true);
-        av.visitEnum("value", "Ljava/lang/annotation/ElementType;", "TYPE_USE");
-        av.visitEnd();
-        av = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
-        av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
-        av.visitEnd();
-        cw.visitInnerClass(name, headerClassName, intf,
-                ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION);
-        // Write class
-        cw.visitEnd();
-        addClassIfNeeded(headerClassName + "$" + intf, cw.toByteArray());
-    }
-
-    private void createFunctionalInterface(JType.FunctionalInterfaceType fnif) {
-        JType.Function fn = fnif.getFunction();
-        String intf;
-        String nativeName;
-        String nDesc = fnif.getFunction().getNativeDescriptor();
-        intf = fnif.getSimpleName();
-        nativeName = "anonymous function";
-        log.print(Level.FINE, () -> "Create FunctionalInterface " + intf);
-
-        final String name = headerClassName + "$" + intf;
-
-        log.print(Level.FINE, () -> "Define class " + name + " for native type " + nativeName + nDesc);
-        global_cw.visitInnerClass(name, headerClassName, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
-        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
-        cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
-                name, "Ljava/lang/Object;",
-                "java/lang/Object", new String[0]);
-        AnnotationVisitor av = cw.visitAnnotation(
-                "Ljava/lang/FunctionalInterface;", true);
-        av.visitEnd();
-        av = cw.visitAnnotation(NATIVE_CALLBACK, true);
-        av.visit("value", nDesc);
-        av.visitEnd();
-        cw.visitInnerClass(name, headerClassName, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
-
-        // add the method
-
-        int flags = ACC_PUBLIC | ACC_ABSTRACT;
-        if (fn.isVarArgs) {
-            flags |= ACC_VARARGS;
-        }
-        MethodVisitor mv = cw.visitMethod(flags, "fn",
-                fn.getDescriptor(), fn.getSignature(false), null);
-        fn.visitInner(cw);
-        mv.visitEnd();
-        // Write class
-        cw.visitEnd();
-        addClassIfNeeded(headerClassName + "$" + intf, cw.toByteArray());
-    }
-
-    @Override
-    public Boolean visitTypedef(TypedefTree typedefTree, JType jt) {
-        createAnnotationCls(typedefTree);
-        return true;
-    }
-
-    @Override
-    public Boolean visitTree(Tree tree, JType jt) {
-        log.print(Level.WARNING, () -> "Unsupported declaration tree:");
-        log.print(Level.WARNING, () -> tree.toString());
-        return true;
-    }
-
-    @Override
-    public Boolean visitFunction(FunctionTree funcTree, JType jt) {
-        assert (jt instanceof JType.Function);
-        JType.Function fn = (JType.Function)jt;
-        log.print(Level.FINE, () -> "Add method: " + fn.getSignature(false));
-        int flags = ACC_PUBLIC | ACC_ABSTRACT;
-        if (fn.isVarArgs) {
-            flags |= ACC_VARARGS;
-        }
-        MethodVisitor mv = global_cw.visitMethod(flags,
-                funcTree.name(), fn.getDescriptor(), fn.getSignature(false), null);
-        jt.visitInner(global_cw);
-        final int arg_cnt = funcTree.numParams();
-        for (int i = 0; i < arg_cnt; i++) {
-            String name = funcTree.paramName(i);
-            final int tmp = i;
-            log.print(Level.FINER, () -> "  arg " + tmp + ": " + name);
-            mv.visitParameter(name, 0);
-        }
-
-        if (! noNativeLocations) {
-            AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
-            SourceLocation src = funcTree.location();
-            SourceLocation.Location loc = src.getFileLocation();
-            Path p = loc.path();
-            av.visit("file", p == null ? "<builtin>" : p.toAbsolutePath().toString());
-            av.visit("line", loc.line());
-            av.visit("column", loc.column());
-            av.visitEnd();
-        }
-
-        Type type = funcTree.type();
-        final String descStr = Utils.getFunction(type).toString();
-
-        AnnotationVisitor av = mv.visitAnnotation(NATIVE_FUNCTION, true);
-        av.visit("value", descStr);
-        av.visitEnd();
-
-        mv.visitEnd();
-        return true;
-    }
-
-    private AsmCodeFactory generateDecl(Tree tree) {
-        try {
-            log.print(Level.FINE, () -> "Process tree " + tree.name());
-            tree.accept(this, tree.isPreprocessing() ? null : headerFile.dictionary().lookup(tree.type()));
-        } catch (Exception ex) {
-            handleException(ex);
-            log.print(Level.WARNING, () -> "Tree causing above exception is: " + tree.name());
-            log.print(Level.WARNING, () -> tree.toString());
-        }
-        return this;
-    }
-
-    @Override
-    public Boolean visitMacro(MacroTree macroTree, JType jt) {
-        if (!macroTree.isConstant()) {
-            log.print(Level.FINE, () -> "Skipping unrecognized object-like macro " + macroTree.name());
-            return false;
-        }
-        String name = macroTree.name();
-        MacroParser.Macro macro = macroTree.macro().get();
-        log.print(Level.FINE, () -> "Adding macro " + name);
-
-        addConstant(global_cw, macroTree.location(), Utils.toMacroName(name), macro.type(), macro.value());
-
-        return true;
-    }
-}
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactoryExt.java	Fri Apr 19 15:03:19 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,366 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- *
- * 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 com.sun.tools.jextract;
-
-import java.foreign.Libraries;
-import java.foreign.Scope;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodHandles.Lookup;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-import java.util.logging.Level;
-
-import com.sun.tools.jextract.parser.MacroParser;
-import com.sun.tools.jextract.tree.Tree;
-import jdk.internal.org.objectweb.asm.FieldVisitor;
-import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.MethodVisitor;
-import jdk.internal.org.objectweb.asm.Type;
-import com.sun.tools.jextract.tree.EnumTree;
-import com.sun.tools.jextract.tree.FieldTree;
-import com.sun.tools.jextract.tree.FunctionTree;
-import com.sun.tools.jextract.tree.MacroTree;
-import com.sun.tools.jextract.tree.VarTree;
-
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
-import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS;
-import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
-import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
-import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
-import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
-import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
-import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
-import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
-import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
-import static jdk.internal.org.objectweb.asm.Opcodes.V1_8;
-
-/**
- * This extended factory generates a class with only static methods and fields. A native
- * library interface instance (of the given header file) is kept as a static private field.
- * One static method is generated for every library interface method. Enum and macro constants
- * are mapped to static final fields. By importing the "static forwarder" class, the user code
- * looks more or less like C code. Libraries.bind and header interface usage is hidden.
- */
-final class AsmCodeFactoryExt extends AsmCodeFactory {
-    private final String headerClassNameDesc;
-    private final String forwarderClassName;
-    private final ClassWriter cw;
-    // suffix for static forwarder class name
-    // field name for the header interface instance.
-    private static final String STATICS_LIBRARY_FIELD_NAME = "_theLibrary";
-
-    private final List<Consumer<MethodVisitor>> constantInitializers = new ArrayList<>();
-    private final List<EnumFactory> enumFactories = new ArrayList<>();
-
-    AsmCodeFactoryExt(Context ctx, HeaderFile header) {
-        super(ctx, header);
-        log.print(Level.INFO, () -> "Instantiate StaticForwarderGenerator for " + header.path);
-        this.headerClassNameDesc = "L" + headerClassName + ";";
-        this.forwarderClassName = Utils.toInternalName(header.pkgName, header.staticForwarderClsName);
-        this.cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
-        this.cw.visit(V1_8, ACC_PUBLIC | ACC_FINAL, getClassName(),
-            null, "java/lang/Object", null);
-        scopeAccessor();
-    }
-
-    private class EnumFactory {
-        private final EnumTree enumTree;
-        private final String enumClassName;
-
-        EnumFactory(EnumTree enumTree) {
-            log.print(Level.INFO, () -> "Instantiate EnumFactory for " + enumTree.name());
-            this.enumTree = enumTree;
-            this.enumClassName = AsmCodeFactoryExt.this.getClassName() + "$" + enumTree.name();
-
-        }
-
-        String getEnumName() {
-            return enumTree.name();
-        }
-
-        String getClassName() {
-            return enumClassName;
-        }
-
-        byte[] getClassBytes() {
-            return generate();
-        }
-
-        private byte[] generate() {
-            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
-            cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, enumClassName,
-                null, "java/lang/Object", null);
-            cw.visitInnerClass(enumClassName, AsmCodeFactoryExt.this.getClassName(), enumTree.name(), ACC_PUBLIC | ACC_FINAL);
-            enumTree.constants().forEach(constant -> {
-                String name = constant.name();
-                JType type = headerFile.dictionary().lookup(constant.type());
-                Object constantValue = makeConstantValue(type, constant.enumConstant().get());
-                FieldVisitor fv = cw.visitField(ACC_PUBLIC | ACC_STATIC | ACC_FINAL, name, type.getDescriptor(),
-                        type.getSignature(false), constantValue);
-                fv.visitEnd();
-            });
-
-            cw.visitEnd();
-            return cw.toByteArray();
-        }
-    }
-
-    @Override
-    public Boolean visitVar(VarTree varTree, JType jt) {
-        if (super.visitVar(varTree, jt)) {
-            String fieldName = varTree.name();
-            assert !fieldName.isEmpty();
-
-            emitStaticForwarder(fieldName + "$get",
-                "()" + jt.getDescriptor(), "()" + jt.getSignature(false), false);
-            jt.visitInner(cw);
-
-            emitStaticForwarder(fieldName + "$set",
-                "(" + jt.getDescriptor() + ")V",
-                "(" + jt.getSignature(true) + ")V", false);
-            JType ptrType = JType.GenericType.ofPointer(jt);
-            emitStaticForwarder(fieldName + "$ptr",
-                "()" + ptrType.getDescriptor(), "()" + ptrType.getSignature(false), false);
-            ptrType.visitInner(cw);
-
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public Boolean visitEnum(EnumTree enumTree, JType jt) {
-        if (super.visitEnum(enumTree, jt)) {
-            if (enumTree.name().isEmpty()) {
-                enumTree.constants().forEach(constant -> addConstant(constant.name(),
-                    headerFile.dictionary().lookup(constant.type()),
-                    constant.enumConstant().get()));
-            } else {
-                EnumFactory ef = new EnumFactory(enumTree);
-                enumFactories.add(ef);
-                cw.visitInnerClass(ef.getClassName(), getClassName(), ef.getEnumName(),
-                    ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
-            }
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public Boolean visitFunction(FunctionTree funcTree, JType jt) {
-        if (super.visitFunction(funcTree, jt)) {
-            assert (jt instanceof JType.Function);
-            JType.Function fn = (JType.Function)jt;
-            log.print(Level.FINE, () -> "Add method: " + fn.getSignature(false));
-            emitStaticForwarder(funcTree.name(), fn.getDescriptor(), fn.getSignature(false), fn.isVarArgs);
-            fn.visitInner(cw);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public Boolean visitMacro(MacroTree macroTree, JType jt) {
-        if (super.visitMacro(macroTree, jt)) {
-            String name = macroTree.name();
-            MacroParser.Macro macro = macroTree.macro().get();
-            log.print(Level.FINE, () -> "Adding macro " + name);
-            addConstant(Utils.toMacroName(name), macro.type(), macro.value());
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    private void addConstant(String name, JType type, Object value) {
-        Object constantValue = makeConstantValue(type, value);
-        FieldVisitor fv = cw.visitField(ACC_PUBLIC | ACC_STATIC | ACC_FINAL, name, type.getDescriptor(),
-                type.getSignature(false), constantValue);
-        fv.visitEnd();
-        if (constantValue == null) {
-            constantInitializers.add(mv -> {
-                // load library interface (static) field
-                String desc = type.getDescriptor();
-                mv.visitFieldInsn(GETSTATIC, getClassName(),
-                        STATICS_LIBRARY_FIELD_NAME, headerClassNameDesc);
-                mv.visitMethodInsn(INVOKEINTERFACE, headerClassName, name, "()" + desc, true);
-                mv.visitFieldInsn(PUTSTATIC, getClassName(), name, desc);
-            });
-        }
-    }
-
-    private Object makeConstantValue(JType type, Object value) {
-        switch (type.getDescriptor()) {
-            case "Z":
-                return ((long)value) != 0;
-            case "C":
-                return (char)(long)value;
-            case "B":
-                return (byte)(long)value;
-            case "S":
-                return (short)(long)value;
-            case "I":
-                return (int)(long)value;
-            case "F":
-                return (float)(double)value;
-            case "J": case "D":
-                return value;
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public Map<String, byte[]> generateNativeHeader(List<Tree> decls) {
-        Map<String, byte[]> results = new HashMap<>();
-        results.putAll(super.generateNativeHeader(decls));
-        staticsInitializer();
-        results.put(getClassName(), getClassBytes());
-        for (EnumFactory ef : enumFactories) {
-            results.put(ef.getClassName(), ef.getClassBytes());
-        }
-        return Collections.unmodifiableMap(results);
-    }
-
-    // Internals only below this point
-
-    private String getClassName() {
-        return forwarderClassName;
-    }
-
-    // return the generated static forwarder class bytes
-    private byte[] getClassBytes() {
-        cw.visitEnd();
-        return cw.toByteArray();
-    }
-
-    // emit library interface static field and <clinit> initializer for that field
-    private void staticsInitializer() {
-        // library interface field
-        FieldVisitor fv = cw.visitField(ACC_PRIVATE|ACC_STATIC|ACC_FINAL,
-            STATICS_LIBRARY_FIELD_NAME, headerClassNameDesc, null, null);
-        fv.visitEnd();
-
-        // <clinit> to bind library interface field
-        MethodVisitor mv = cw.visitMethod(ACC_STATIC,
-            "<clinit>", "()V", null, null);
-        mv.visitCode();
-
-        // MethodHandles.lookup()
-        Method lookupMethod = null;
-        try {
-            lookupMethod = MethodHandles.class.getMethod("lookup");
-        } catch (NoSuchMethodException nsme) {
-            throw new RuntimeException(nsme);
-        }
-        mv.visitMethodInsn(INVOKESTATIC,
-            Type.getInternalName(MethodHandles.class), "lookup",
-            Type.getMethodDescriptor(lookupMethod), false);
-
-        // ldc library-interface-class
-        mv.visitLdcInsn(Type.getObjectType(headerClassName));
-
-        // Libraries.bind(lookup, class);
-        Method bindMethod = null;
-        try {
-            bindMethod = Libraries.class.getMethod("bind", Lookup.class, Class.class);
-        } catch (NoSuchMethodException nsme) {
-            throw new RuntimeException(nsme);
-        }
-        mv.visitMethodInsn(INVOKESTATIC,
-            Type.getInternalName(Libraries.class), "bind",
-            Type.getMethodDescriptor(bindMethod), false);
-
-        // store it in library interface field
-        mv.visitTypeInsn(CHECKCAST, headerClassName);
-        mv.visitFieldInsn(PUTSTATIC, getClassName(),
-            STATICS_LIBRARY_FIELD_NAME, headerClassNameDesc);
-
-        constantInitializers.forEach(init -> init.accept(mv));
-
-        mv.visitInsn(RETURN);
-        mv.visitMaxs(0, 0);
-        mv.visitEnd();
-    }
-
-    private void scopeAccessor() {
-        String scopeAccessorDesc = MethodType.methodType(Scope.class).descriptorString();
-        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "scope", scopeAccessorDesc, null, null);
-        mv.visitCode();
-
-        // load library interface (static) field
-        mv.visitFieldInsn(GETSTATIC, getClassName(),
-            STATICS_LIBRARY_FIELD_NAME, headerClassNameDesc);
-
-        String libraryScopeDesc = MethodType.methodType(Scope.class, Object.class).descriptorString();
-        mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(Libraries.class), "libraryScope", libraryScopeDesc, false);
-        mv.visitInsn(ARETURN);
-        mv.visitMaxs(1,1);
-        mv.visitEnd();
-    }
-
-    // emit static forwarder method for a specific library interface method
-    private void emitStaticForwarder(String name, String desc, String signature, boolean isVarArgs) {
-        int accessFlags = ACC_PUBLIC | ACC_STATIC;
-        if (isVarArgs) {
-            accessFlags |= ACC_VARARGS;
-        }
-
-        MethodVisitor mv = cw.visitMethod(accessFlags, name, desc, signature, null);
-        mv.visitCode();
-
-        // load library interface (static) field
-        mv.visitFieldInsn(GETSTATIC, getClassName(),
-            STATICS_LIBRARY_FIELD_NAME, headerClassNameDesc);
-
-        // forward the call to the interface
-        Type[] argTypes = Type.getArgumentTypes(desc);
-        Type retType = Type.getReturnType(desc);
-
-        int loadIdx = 0;
-        for (int i = 0; i < argTypes.length; i++) {
-            mv.visitVarInsn(argTypes[i].getOpcode(ILOAD), loadIdx);
-            loadIdx += argTypes[i].getSize();
-        }
-        mv.visitMethodInsn(INVOKEINTERFACE, headerClassName, name, desc, true);
-        mv.visitInsn(retType.getOpcode(IRETURN));
-
-        mv.visitMaxs(0, 0);
-        mv.visitEnd();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/InMemoryJavaCompiler.java	Fri Apr 26 08:03:40 2019 +0530
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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 com.sun.tools.jextract;
+
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+import java.io.ByteArrayOutputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+
+final class InMemoryJavaCompiler {
+    private InMemoryJavaCompiler() {}
+
+    static Map<String, byte[]> compile(Map<String, ? extends CharSequence> inputMap,
+            String... options) {
+        Collection<JavaFileObject> sourceFiles = new LinkedList<>();
+        for (Entry<String, ? extends CharSequence> entry : inputMap.entrySet()) {
+            sourceFiles.add(new SourceFile(entry.getKey(), entry.getValue()));
+        }
+
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        FileManager fileManager = new FileManager(compiler.getStandardFileManager(null, null, null));
+
+        Writer writer = new StringWriter();
+        Boolean exitCode = compiler.getTask(writer, fileManager, null, Arrays.asList(options), null, sourceFiles).call();
+        if (!exitCode) {
+            throw new RuntimeException("In memory compilation failed: " + writer.toString());
+        }
+        return fileManager.getByteCode();
+    }
+
+    // Wraper for class byte array
+    private static class ClassFile extends SimpleJavaFileObject {
+        private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+        protected ClassFile(String name) {
+            super(URI.create("memo:///" + name.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS);
+        }
+
+        @Override
+        public ByteArrayOutputStream openOutputStream() { return this.baos; }
+
+        byte[] toByteArray() { return baos.toByteArray(); }
+    }
+
+    // File manager which spawns ClassFile instances on demand
+    private static class FileManager extends ForwardingJavaFileManager<JavaFileManager> {
+        private final Map<String, ClassFile> classesMap = new HashMap<>();
+
+        protected FileManager(JavaFileManager fileManager) {
+            super(fileManager);
+        }
+
+        @Override
+        public ClassFile getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject source) {
+            ClassFile classFile = new ClassFile(name);
+            classesMap.put(name, classFile);
+            return classFile;
+        }
+
+        public Map<String, byte[]> getByteCode() {
+            Map<String, byte[]> result = new HashMap<>();
+            for (Entry<String, ClassFile> entry : classesMap.entrySet()) {
+                result.put(entry.getKey(), entry.getValue().toByteArray());
+            }
+            return result;
+        }
+    }
+
+    // Wrapper for source String
+    private static class SourceFile extends SimpleJavaFileObject {
+        private final CharSequence sourceCode;
+
+        public SourceFile(String name, CharSequence sourceCode) {
+            super(URI.create("memo:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
+            this.sourceCode = sourceCode;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignore) {
+            return this.sourceCode;
+        }
+    }
+}
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/JModWriter.java	Fri Apr 19 15:03:19 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/JModWriter.java	Fri Apr 26 08:03:40 2019 +0530
@@ -29,19 +29,16 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 import java.util.logging.Level;
 import java.util.spi.ToolProvider;
 import java.util.logging.Logger;
-import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.ModuleVisitor;
-import jdk.internal.org.objectweb.asm.Opcodes;
 
 // Utility class to generate a .jmod file
 public final class JModWriter {
-    private final Options options;
-    private final Log log;
+    private final Context ctx;
     private final Writer writer;
 
     private static ToolProvider findTool(String name) {
@@ -53,20 +50,20 @@
         return tp.get();
     }
 
+    private static final ToolProvider JAVAC = findTool("javac");
     private static final ToolProvider JMOD = findTool("jmod");
 
     public JModWriter(Context ctx, Writer writer) {
-        this.options = ctx.options;
-        this.log = ctx.log;
+        this.ctx = ctx;
         this.writer = writer;
     }
 
     public void writeJModFile(Path jmodFile, String[] args) throws IOException {
-        if (options.targetPackage == null || options.targetPackage.isEmpty()) {
+        if (ctx.options.targetPackage == null || ctx.options.targetPackage.isEmpty()) {
             throw new IllegalArgumentException("no --target-package specified");
         }
 
-        log.print(Level.INFO, () -> "Collecting jmod file " + jmodFile);
+        ctx.log.print(Level.INFO, () -> "Collecting jmod file " + jmodFile);
 
         String modName = jmodFile.getFileName().toString();
         modName = modName.substring(0, modName.length() - 5 /* ".jmod".length() */);
@@ -75,14 +72,14 @@
         Path jmodRootDir = Files.createTempDirectory("jextract.jmod");
         jmodRootDir.toFile().deleteOnExit();
 
-        log.print(Level.INFO, () -> "Writing .class files");
+        ctx.log.print(Level.INFO, () -> "Writing .class files");
         // write .class files
         Path modClassesDir = jmodRootDir.resolve(modName);
         writer.writeClassFiles(modClassesDir, args);
 
-        log.print(Level.INFO, () -> "Generating module-info.class");
+        ctx.log.print(Level.INFO, () -> "Generating module-info.class");
         // generate module-info.class
-        generateModuleInfoClass(modClassesDir, modName);
+        generateModuleInfoClass(jmodRootDir, modClassesDir, modName);
 
         // copy libraries
         Path libsDir = jmodRootDir.resolve("libs");
@@ -92,40 +89,50 @@
         generateJMod(modClassesDir, libsDir, jmodFile);
     }
 
-    private void generateModuleInfoClass(Path modClassesDir, String modName) throws IOException {
+    private void generateModuleInfoClass(Path jmodRootDir, Path modClassesDir, String modName) throws IOException {
         // collect package names
         final Set<String> packages = new HashSet<>();
         for (String cls : writer.results().keySet()) {
-            int idx = cls.lastIndexOf("/");
+            int idx = cls.lastIndexOf(".");
             packages.add(cls.substring(0, idx));
         }
 
-        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
-        cw.visit(Opcodes.V9, Opcodes.ACC_MODULE, "module-info", null, null, null);
+        // module-info.java source code string
+        StringBuilder modInfoCode = new StringBuilder();
+        modInfoCode.append("module ");
+        modInfoCode.append(modName);
+        modInfoCode.append(" {\n");
+        for (String pkg : packages) {
+            modInfoCode.append("    exports ");
+            modInfoCode.append(pkg);
+            modInfoCode.append(";\n");
+        }
+        modInfoCode.append("}");
 
-        ModuleVisitor mv = cw.visitModule(modName, Opcodes.ACC_MANDATED, null);
-        mv.visitRequire("java.base", Opcodes.ACC_MANDATED, null);
-        for (String pkg : packages) {
-            mv.visitExport(pkg, Opcodes.ACC_MANDATED);
+        // write module-info.java source in module directory
+        Files.write(modClassesDir.resolve("module-info.java"), List.of(modInfoCode.toString()));
+
+        // compile module-info.java
+        int exitCode = JAVAC.run(ctx.log.getOut(), ctx.log.getErr(),
+            "--module-source-path", jmodRootDir.toString(),
+            "-d", jmodRootDir.toString(),
+            modClassesDir.resolve("module-info.java").toString());
+
+        if (exitCode != 0) {
+            throw new RuntimeException("module-info.class generation failed: " + exitCode);
         }
-        mv.visitEnd();
-
-        cw.visitEnd();
-
-        // write module-info.class source in module directory
-        Files.write(modClassesDir.resolve("module-info.class"), cw.toByteArray());
     }
 
     private void copyNativeLibraries(Path libsDir) throws IOException {
         Files.createDirectory(libsDir);
-        if (!options.libraryNames.isEmpty()) {
-            if (options.libraryPaths.isEmpty()) {
-                log.printWarning("warn.no.library.paths.specified");
+        if (!ctx.options.libraryNames.isEmpty()) {
+            if (ctx.options.libraryPaths.isEmpty()) {
+                ctx.log.printWarning("warn.no.library.paths.specified");
                 return;
             }
-            log.print(Level.INFO, () -> "Copying native libraries");
-            Path[] paths = options.libraryPaths.stream().map(Paths::get).toArray(Path[]::new);
-            options.libraryNames.forEach(libName -> {
+            ctx.log.print(Level.INFO, () -> "Copying native libraries");
+            Path[] paths = ctx.options.libraryPaths.stream().map(Paths::get).toArray(Path[]::new);
+            ctx.options.libraryNames.forEach(libName -> {
                 Optional<Path> absPath = Utils.findLibraryPath(paths, libName);
                 if (absPath.isPresent()) {
                     Path libPath = absPath.get();
@@ -135,7 +142,7 @@
                         throw new UncheckedIOException(ioExp);
                     }
                 } else {
-                    log.printWarning("warn.library.not.copied", libName);
+                    ctx.log.printWarning("warn.library.not.copied", libName);
                 }
             });
         }
@@ -143,8 +150,8 @@
 
     private void generateJMod(Path classesDir, Path libsDir, Path jmodFile)
             throws IOException {
-        log.print(Level.INFO, () -> "Generating jmod file: " + jmodFile);
-        int exitCode = JMOD.run(log.getOut(), log.getErr(), "create",
+        ctx.log.print(Level.INFO, () -> "Generating jmod file: " + jmodFile);
+        int exitCode = JMOD.run(ctx.log.getOut(), ctx.log.getErr(), "create",
             "--class-path", classesDir.toString(),
             "--libs", libsDir.toString(),
             jmodFile.toString());
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/JType.java	Fri Apr 19 15:03:19 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/JType.java	Fri Apr 26 08:03:40 2019 +0530
@@ -22,16 +22,10 @@
  */
 package com.sun.tools.jextract;
 
-import jdk.internal.org.objectweb.asm.ClassVisitor;
 import java.foreign.memory.Callback;
 import java.foreign.memory.Pointer;
 import java.util.Objects;
 
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
-import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
-
 /**
  * A Java Type descriptor
  */
@@ -44,10 +38,6 @@
      */
     public abstract String getDescriptor();
 
-    public void visitInner(ClassVisitor cv) {}
-
-    public String getSignature(boolean isArgument) { return getDescriptor(); }
-
     public abstract String getSourceSignature(boolean isArgument);
 
     public final static JType Void = new PrimitiveType("V", of(Void.class), "void");
@@ -183,14 +173,6 @@
                 return clsName;
             }
         }
-
-        @Override
-        public void visitInner(ClassVisitor cv) {
-            if (enclosingName != null) {
-                cv.visitInnerClass(clsName, enclosingName, simpleName,
-                    ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE);
-            }
-        }
     }
 
     public final static class ArrayType extends JType {
@@ -206,23 +188,6 @@
         }
 
         @Override
-        public void visitInner(ClassVisitor cv) {
-            elementType.visitInner(cv);
-        }
-
-        @Override
-        public String getSignature(boolean isArgument) {
-            StringBuilder sb = new StringBuilder();
-            sb.append("L");
-            sb.append(java.foreign.memory.Array.class.getName().replace('.', '/'));
-            sb.append("<");
-            JType pt = elementType;
-            sb.append(pt.box().getSignature(isArgument));
-            sb.append(">;");
-            return sb.toString();
-        }
-
-        @Override
         public String getSourceSignature(boolean isArgument) {
             StringBuilder sb = new StringBuilder();
             sb.append("Array"); // java.foreign.memory.* will be imported
@@ -281,30 +246,6 @@
             throw new UnsupportedOperationException();
         }
 
-        @Override
-        public void visitInner(ClassVisitor cv) {
-            returnType.visitInner(cv);
-            for (JType at : args) {
-                at.visitInner(cv);
-            }
-        }
-
-        @Override
-        public String getSignature(boolean isArgument) {
-            StringBuilder sb = new StringBuilder();
-            sb.append('(');
-            // ensure sequence
-            for (int i = 0; i < args.length; i++) {
-                sb.append(args[i].getSignature(true));
-            }
-            if (isVarArgs) {
-                sb.append("[Ljava/lang/Object;");
-            }
-            sb.append(')');
-            sb.append(returnType.getSignature(false));
-            return sb.toString();
-        }
-
         public String getNativeDescriptor() {
             return layout.toString();
         }
@@ -321,12 +262,6 @@
         Function getFunction() {
             return fn;
         }
-
-        @Override
-        public void visitInner(ClassVisitor cv) {
-            fn.visitInner(cv);
-            super.visitInner(cv);
-        }
     }
 
     public static class GenericType extends ClassType {
@@ -342,24 +277,6 @@
         }
 
         @Override
-        public String getSignature(boolean isArgument) {
-            StringBuilder sb = new StringBuilder();
-            sb.append("L");
-            sb.append(clsName);
-            sb.append("<");
-            if (targ == JType.Void && isArgument) {
-                sb.append("*");
-            } else {
-                if (targ instanceof GenericType && isArgument) {
-                    sb.append("+");
-                }
-                sb.append(targ.box().getSignature(isArgument));
-            }
-            sb.append(">;");
-            return sb.toString();
-        }
-
-        @Override
         public String getSourceSignature(boolean isArgument) {
             StringBuilder sb = new StringBuilder();
             sb.append(super.getSourceSignature(isArgument));
@@ -383,11 +300,5 @@
         public static GenericType ofCallback(JType targ) {
             return new GenericType(JType.binaryName(Callback.class), targ);
         }
-
-        @Override
-        public void visitInner(ClassVisitor cv) {
-            targ.visitInner(cv);
-            super.visitInner(cv);
-        }
     }
 }
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/JarWriter.java	Fri Apr 19 15:03:19 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/JarWriter.java	Fri Apr 26 08:03:40 2019 +0530
@@ -54,7 +54,7 @@
     public void writeJarFile(JarOutputStream jar, String[] args) {
         writer.results().forEach((cls, bytes) -> {
                 try {
-                    String path = cls.replace('.', File.separatorChar) + ".class";
+                    String path = cls.replace('.', '/') + ".class";
                     log.print(Level.FINE, () -> "Add " + path);
                     jar.putNextEntry(new ZipEntry(path));
                     jar.write(bytes);
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/JavaSourceFactory.java	Fri Apr 19 15:03:19 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/JavaSourceFactory.java	Fri Apr 26 08:03:40 2019 +0530
@@ -90,12 +90,13 @@
         this.libraryPaths = ctx.options.recordLibraryPath? ctx.options.libraryPaths : null;
         this.noNativeLocations = ctx.options.noNativeLocations;
         this.global_jsb = new JavaSourceBuilder();
-        this.srcDir = Paths.get(ctx.options.srcDumpDir)
-            .resolve(headerFile.pkgName.replace('.', File.separatorChar));
+        this.srcDir = ctx.options.srcDumpDir != null?
+            Paths.get(ctx.options.srcDumpDir).resolve(headerFile.pkgName.replace('.', File.separatorChar)) :
+            null;
     }
 
     // main entry point that generates & saves .java files for the header file
-    public void generate(List<Tree> decls) {
+    public Map<String, String> generate(List<Tree> decls) {
         global_jsb.addPackagePrefix(headerFile.pkgName);
 
         Map<String, Object> header = new HashMap<>();
@@ -141,13 +142,19 @@
 
         global_jsb.interfaceEnd();
         String src = global_jsb.build();
-        try {
-            Files.createDirectories(srcDir);
-            Path srcPath = srcDir.resolve(clsName + ".java");
-            Files.write(srcPath, List.of(src));
-        } catch (Exception ex) {
-            handleException(ex);
+        if (srcDir != null) {
+            try {
+                Files.createDirectories(srcDir);
+                Path srcPath = srcDir.resolve(clsName + ".java");
+                Files.write(srcPath, List.of(src));
+            } catch (Exception ex) {
+                handleException(ex);
+            }
         }
+
+        Map<String, String> srcMap = new HashMap<>();
+        srcMap.put(headerClassName, src);
+        return srcMap;
     }
 
     protected void handleException(Exception ex) {
@@ -350,7 +357,7 @@
     public Boolean visitFunction(FunctionTree funcTree, JType jt) {
         assert (jt instanceof JType.Function);
         JType.Function fn = (JType.Function)jt;
-        log.print(Level.FINE, () -> "Add method: " + fn.getSignature(false));
+        log.print(Level.FINE, () -> "Add method: " + fn.getSourceSignature(false));
 
         addNativeLocation(global_jsb, funcTree);
         Type type = funcTree.type();
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/JavaSourceFactoryExt.java	Fri Apr 19 15:03:19 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/JavaSourceFactoryExt.java	Fri Apr 26 08:03:40 2019 +0530
@@ -25,7 +25,9 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.logging.Level;
 
@@ -58,7 +60,7 @@
     }
 
     @Override
-    public void generate(List<Tree> decls) {
+    public Map<String, String> generate(List<Tree> decls) {
         header_jsb.addPackagePrefix(headerFile.pkgName);
         String ifaceClsName = headerFile.headerClsName;
         String forwarderName = headerFile.staticForwarderClsName;
@@ -67,17 +69,21 @@
         header_jsb.addLibraryField(ifaceClsName, STATICS_LIBRARY_FIELD_NAME);
         header_jsb.emitScopeAccessor(STATICS_LIBRARY_FIELD_NAME);
 
-        super.generate(decls);
+        Map<String, String> srcMap = super.generate(decls);
         enums.forEach(header_jsb::addNestedType);
 
         header_jsb.classEnd();
         String src = header_jsb.build();
-        try {
-            Path srcPath = srcDir.resolve(forwarderName + ".java");
-            Files.write(srcPath, List.of(src));
-        } catch (Exception ex) {
-            handleException(ex);
+        if (srcDir != null) {
+            try {
+                Path srcPath = srcDir.resolve(forwarderName + ".java");
+                Files.write(srcPath, List.of(src));
+            } catch (Exception ex) {
+                handleException(ex);
+            }
         }
+        srcMap.put(headerFile.pkgName + "." + forwarderName, src);
+        return srcMap;
     }
 
     @Override
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/JextractTool.java	Fri Apr 19 15:03:19 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/JextractTool.java	Fri Apr 26 08:03:40 2019 +0530
@@ -32,6 +32,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -44,7 +45,6 @@
 public class JextractTool {
     private final HeaderResolver headerResolver;
     private final Parser parser;
-    private final Function<HeaderFile, AsmCodeFactory> codeFactory;
     private final Collection<String> clangArgs;
     private final Collection<Path> sources;
     private final Context ctx;
@@ -52,9 +52,6 @@
     public JextractTool(Context ctx) {
         this.headerResolver = new HeaderResolver(ctx);
         this.parser = new Parser(ctx, Options.INCLUDE_MACROS);
-        this.codeFactory = ctx.options.genStaticForwarder ?
-                hf -> new AsmCodeFactoryExt(ctx, hf) :
-                hf -> new AsmCodeFactory(ctx, hf);
         this.clangArgs = ctx.options.clangArgs;
         this.sources = ctx.sources;
         this.ctx = ctx;
@@ -77,21 +74,18 @@
                 .collect(Collectors.groupingBy(this::headerFromDecl));
 
         //generate classes
-        Map<String, byte[]> results = new LinkedHashMap<>();
-        headerMap.forEach((hf, decls) -> generateHeader(hf, decls, results));
-        return new Writer(ctx, results);
+        Map<String, String> srcMap = new HashMap<>();
+        headerMap.forEach((hf, decls) -> generateHeader(hf, decls,srcMap));
+        Map<String, byte[]> classMap = !srcMap.isEmpty()? InMemoryJavaCompiler.compile(srcMap) : Map.of();
+        return new Writer(ctx, classMap);
     }
 
-    private void generateHeader(HeaderFile hf, List<Tree> decls, Map<String, byte[]> results) {
+    private void generateHeader(HeaderFile hf, List<Tree> decls, Map<String, String> srcMap) {
         TypeEnter enter = new TypeEnter(hf.dictionary());
         decls.forEach(t -> t.accept(enter, null));
-        if (ctx.options.srcDumpDir != null) {
-            JavaSourceFactory jsb = ctx.options.genStaticForwarder ?
-                new JavaSourceFactoryExt(ctx, hf) : new JavaSourceFactory(ctx, hf);
-            jsb.generate(decls);
-        }
-        AsmCodeFactory cf = codeFactory.apply(hf);
-        results.putAll(cf.generateNativeHeader(decls));
+        JavaSourceFactory jsb = ctx.options.genStaticForwarder ?
+            new JavaSourceFactoryExt(ctx, hf) : new JavaSourceFactory(ctx, hf);
+        srcMap.putAll(jsb.generate(decls));
     }
 
     private HeaderFile headerFromDecl(Tree tree) {
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/Writer.java	Fri Apr 19 15:03:19 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/Writer.java	Fri Apr 26 08:03:40 2019 +0530
@@ -41,7 +41,7 @@
         this.results = results;
     }
 
-    static final String JEXTRACT_MANIFEST = "META-INF" + File.separatorChar + "jextract.properties";
+    static final String JEXTRACT_MANIFEST = "META-INF/jextract.properties";
 
     public boolean isEmpty() {
         return results.isEmpty();
@@ -76,7 +76,7 @@
                 }
             });
 
-            Path propsPath = destDir.resolve(JEXTRACT_MANIFEST).normalize();
+            Path propsPath = destDir.resolve(JEXTRACT_MANIFEST.replace('/', File.separatorChar)).normalize();
             Files.createDirectories(propsPath.getParent());
             try (OutputStream fos = Files.newOutputStream(propsPath)) {
                 fos.write(getJextractProperties(args));
--- a/src/jdk.jextract/share/classes/module-info.java	Fri Apr 19 15:03:19 2019 +0530
+++ b/src/jdk.jextract/share/classes/module-info.java	Fri Apr 26 08:03:40 2019 +0530
@@ -24,7 +24,7 @@
  */
 
 module jdk.jextract {
-    requires java.compiler;
+    requires jdk.compiler;
     requires java.logging;
     requires jdk.internal.opt;
     requires jdk.internal.clang;
--- a/test/jdk/com/sun/tools/jextract/Runner.java	Fri Apr 19 15:03:19 2019 +0530
+++ b/test/jdk/com/sun/tools/jextract/Runner.java	Fri Apr 26 08:03:40 2019 +0530
@@ -299,14 +299,13 @@
         actualCL = new ClassLoader() {
             @Override
             protected Class<?> findClass(String name) throws ClassNotFoundException {
-                byte[] byteCode = actualClz.get(canonicalize(name));
+                byte[] byteCode = actualClz.get(name);
                 if (byteCode == null) throw new ClassNotFoundException(name);
                 return defineClass(name, byteCode, 0, byteCode.length);
             }
         };
         System.out.println("Done compile, ready for test");
         assertEquals(actualClz.keySet().stream()
-                        .map(Runner::normalize)
                         .collect(Collectors.toSet()),
                 mfm.listClasses());
         System.out.println("Compile result validated.");
@@ -316,10 +315,6 @@
         return classname.replace('/', '.');
     }
 
-    private static String canonicalize(String classname) {
-        return classname.replace('.', '/');
-    }
-
     private static Path[] paths(String testDir, String[] files, boolean platformDependent) {
         boolean isWindows = System.getProperty("os.name").startsWith("Windows");
         return Arrays.stream(files)