24
25 import jdk.internal.clang.*;
26 import jdk.internal.clang.Type;
27 import jdk.internal.org.objectweb.asm.*;
28
29 import java.io.IOException;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Map;
36 import java.util.logging.Logger;
37
38 import static jdk.internal.org.objectweb.asm.Opcodes.*;
39
40 /**
41 * Scan a header file and generate classes for entities defined in that header
42 * file.
43 */
44 public class AsmCodeFactory extends CodeFactory {
45 final ClassWriter global_cw;
46 final String internal_name;
47 final HeaderFile owner;
48 final Map<String, byte[]> types;
49 final HashSet<String> handledMacros = new HashSet<>();
50 final Logger logger = Logger.getLogger(getClass().getPackage().getName());
51
52 public AsmCodeFactory(HeaderFile header) {
53 logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
54 owner = header;
55 internal_name = Utils.toInternalName(owner.pkgName, owner.clsName);
56 global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
57 types = new HashMap<>();
58 init();
59 }
60
61 private void init() {
62 global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
63 internal_name,
64 null, "java/lang/Object", null);
65 AnnotationVisitor av = global_cw.visitAnnotation(
66 "Ljava/nicl/metadata/Header;", true);
67 av.visit("path", owner.path.toAbsolutePath().toString());
68 av.visitEnd();
69 if (owner.libraries != null && !owner.libraries.isEmpty()) {
70 AnnotationVisitor deps = global_cw.visitAnnotation(
71 "Ljava/nicl/metadata/LibraryDependencies;", true);
72 AnnotationVisitor libNames = deps.visitArray("names");
73 for (String name : owner.libraries) {
74 libNames.visit(null, name);
75 }
76 libNames.visitEnd();
77 if (owner.libraryPaths != null && !owner.libraryPaths.isEmpty()) {
78 AnnotationVisitor libPaths = deps.visitArray("paths");
79 for (String path : owner.libraryPaths) {
80 libPaths.visit(null, path);
81 }
82 libPaths.visitEnd();
83 }
84 deps.visitEnd();
85 }
86 }
87
88 private void handleException(Exception ex) {
89 Context.getInstance().err.println(Main.format("cannot.write.class.file", owner.pkgName + "." + owner.clsName, ex));
90 if (Main.DEBUG) {
91 ex.printStackTrace(Context.getInstance().err);
92 }
93 }
94
95 private void annotateC(ClassVisitor cw, Cursor dcl) {
96 AnnotationVisitor av = cw.visitAnnotation(
97 "Ljava/nicl/metadata/C;", true);
98 SourceLocation src = dcl.getSourceLocation();
99 SourceLocation.Location loc = src.getFileLocation();
100 Path p = loc.path();
101 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
102 av.visit("line", loc.line());
103 av.visit("column", loc.column());
104 av.visit("USR", dcl.USR());
105 av.visitEnd();
106 }
107
108 private void writeClassFile(final ClassWriter cw, String clsName)
109 throws IOException {
110 cw.visitEnd();
111 byte[] bytecodes = cw.toByteArray();
480 logger.finest(() -> " return type is an alias " + alias);
481 if (alias.getAnnotationDescriptor() != null) {
482 mv.visitTypeAnnotation(
483 TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(),
484 null, alias.getAnnotationDescriptor(), true)
485 .visitEnd();
486 }
487 }
488 mv.visitEnd();
489 }
490
491 @Override
492 protected CodeFactory addType(JType jt, Cursor cursor) {
493 JType2 jt2 = null;
494 if (jt instanceof JType2) {
495 jt2 = (JType2) jt;
496 jt = jt2.getDelegate();
497 } else {
498 logger.warning(() -> "Should have JType2 in addType");
499 if (Main.DEBUG) {
500 new Throwable().printStackTrace(Context.getInstance().err);
501 }
502 }
503 if (cursor == null) {
504 assert (jt2 != null);
505 if (jt instanceof JType.FnIf) {
506 createFunctionalInterface(jt2);
507 }
508 return this;
509 }
510
511 try {
512 logger.fine(() -> "Process cursor " + cursor.spelling());
513 switch (cursor.kind()) {
514 case StructDecl:
515 createStruct(cursor);
516 break;
517 case FunctionDecl:
518 assert (jt instanceof JType.Function);
519 addMethod(cursor, (JType.Function) jt);
520 break;
728 protected Map<String, byte[]> collect() {
729 // Ensure classes are produced
730 produce();
731 HashMap<String, byte[]> rv = new HashMap<>();
732 // Not copying byte[] for efficiency, perhaps not a safe idea though
733 if (owner.pkgName.isEmpty()) {
734 types.forEach((clsName, bytecodes) -> {
735 rv.put(clsName, bytecodes);
736 });
737 } else {
738 types.forEach((clsName, bytecodes) -> {
739 rv.put(owner.pkgName + "." + clsName, bytecodes);
740 });
741 }
742 return Collections.unmodifiableMap(rv);
743 }
744
745 public static void main(String[] args) throws IOException {
746 final Path file = Paths.get(args[1]);
747 final String pkg = args[0];
748 Context ctx = Context.getInstance();
749 ctx.usePackageForFolder(file, pkg);
750 ctx.usePackageForFolder(Paths.get("/usr/include"), "system");
751 ctx.sources.add(file);
752 ctx.parse(AsmCodeFactory::new);
753 ctx.collectJarFile(Paths.get(args[2]), pkg);
754 }
755
756 }
|
24
25 import jdk.internal.clang.*;
26 import jdk.internal.clang.Type;
27 import jdk.internal.org.objectweb.asm.*;
28
29 import java.io.IOException;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Map;
36 import java.util.logging.Logger;
37
38 import static jdk.internal.org.objectweb.asm.Opcodes.*;
39
40 /**
41 * Scan a header file and generate classes for entities defined in that header
42 * file.
43 */
44 final class AsmCodeFactory extends CodeFactory {
45 private final Context ctx;
46 private final ClassWriter global_cw;
47 private final String internal_name;
48 private final HeaderFile owner;
49 private final Map<String, byte[]> types;
50 private final HashSet<String> handledMacros = new HashSet<>();
51 private final Logger logger = Logger.getLogger(getClass().getPackage().getName());
52
53 AsmCodeFactory(Context ctx, HeaderFile header) {
54 this.ctx = ctx;
55 logger.info(() -> "Instantiate AsmCodeFactory for " + header.path);
56 this.owner = header;
57 this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName);
58 this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
59 this.types = new HashMap<>();
60 init();
61 }
62
63 private void init() {
64 global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE,
65 internal_name,
66 null, "java/lang/Object", null);
67 AnnotationVisitor av = global_cw.visitAnnotation(
68 "Ljava/nicl/metadata/Header;", true);
69 av.visit("path", owner.path.toAbsolutePath().toString());
70 av.visitEnd();
71 if (owner.libraries != null && !owner.libraries.isEmpty()) {
72 AnnotationVisitor deps = global_cw.visitAnnotation(
73 "Ljava/nicl/metadata/LibraryDependencies;", true);
74 AnnotationVisitor libNames = deps.visitArray("names");
75 for (String name : owner.libraries) {
76 libNames.visit(null, name);
77 }
78 libNames.visitEnd();
79 if (owner.libraryPaths != null && !owner.libraryPaths.isEmpty()) {
80 AnnotationVisitor libPaths = deps.visitArray("paths");
81 for (String path : owner.libraryPaths) {
82 libPaths.visit(null, path);
83 }
84 libPaths.visitEnd();
85 }
86 deps.visitEnd();
87 }
88 }
89
90 private void handleException(Exception ex) {
91 ctx.err.println(Main.format("cannot.write.class.file", owner.pkgName + "." + owner.clsName, ex));
92 if (Main.DEBUG) {
93 ex.printStackTrace(ctx.err);
94 }
95 }
96
97 private void annotateC(ClassVisitor cw, Cursor dcl) {
98 AnnotationVisitor av = cw.visitAnnotation(
99 "Ljava/nicl/metadata/C;", true);
100 SourceLocation src = dcl.getSourceLocation();
101 SourceLocation.Location loc = src.getFileLocation();
102 Path p = loc.path();
103 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
104 av.visit("line", loc.line());
105 av.visit("column", loc.column());
106 av.visit("USR", dcl.USR());
107 av.visitEnd();
108 }
109
110 private void writeClassFile(final ClassWriter cw, String clsName)
111 throws IOException {
112 cw.visitEnd();
113 byte[] bytecodes = cw.toByteArray();
482 logger.finest(() -> " return type is an alias " + alias);
483 if (alias.getAnnotationDescriptor() != null) {
484 mv.visitTypeAnnotation(
485 TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(),
486 null, alias.getAnnotationDescriptor(), true)
487 .visitEnd();
488 }
489 }
490 mv.visitEnd();
491 }
492
493 @Override
494 protected CodeFactory addType(JType jt, Cursor cursor) {
495 JType2 jt2 = null;
496 if (jt instanceof JType2) {
497 jt2 = (JType2) jt;
498 jt = jt2.getDelegate();
499 } else {
500 logger.warning(() -> "Should have JType2 in addType");
501 if (Main.DEBUG) {
502 new Throwable().printStackTrace(ctx.err);
503 }
504 }
505 if (cursor == null) {
506 assert (jt2 != null);
507 if (jt instanceof JType.FnIf) {
508 createFunctionalInterface(jt2);
509 }
510 return this;
511 }
512
513 try {
514 logger.fine(() -> "Process cursor " + cursor.spelling());
515 switch (cursor.kind()) {
516 case StructDecl:
517 createStruct(cursor);
518 break;
519 case FunctionDecl:
520 assert (jt instanceof JType.Function);
521 addMethod(cursor, (JType.Function) jt);
522 break;
730 protected Map<String, byte[]> collect() {
731 // Ensure classes are produced
732 produce();
733 HashMap<String, byte[]> rv = new HashMap<>();
734 // Not copying byte[] for efficiency, perhaps not a safe idea though
735 if (owner.pkgName.isEmpty()) {
736 types.forEach((clsName, bytecodes) -> {
737 rv.put(clsName, bytecodes);
738 });
739 } else {
740 types.forEach((clsName, bytecodes) -> {
741 rv.put(owner.pkgName + "." + clsName, bytecodes);
742 });
743 }
744 return Collections.unmodifiableMap(rv);
745 }
746
747 public static void main(String[] args) throws IOException {
748 final Path file = Paths.get(args[1]);
749 final String pkg = args[0];
750 Context ctx = new Context();
751 ctx.usePackageForFolder(file, pkg);
752 ctx.usePackageForFolder(Paths.get("/usr/include"), "system");
753 ctx.addSource(file);
754 ctx.parse();
755 ctx.collectJarFile(Paths.get(args[2]), pkg);
756 }
757 }
|