1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package com.sun.tools.jextract; 24 25 import java.io.IOException; 26 import java.foreign.layout.Layout; 27 import java.nio.file.Path; 28 import java.nio.file.Paths; 29 import java.util.ArrayList; 30 import java.util.Collections; 31 import java.util.HashMap; 32 import java.util.HashSet; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.Set; 36 import java.util.logging.Logger; 37 import java.util.stream.Stream; 38 import jdk.internal.clang.Cursor; 39 import jdk.internal.clang.CursorKind; 40 import jdk.internal.clang.SourceLocation; 41 import jdk.internal.clang.Type; 42 import jdk.internal.foreign.Util; 43 import jdk.internal.org.objectweb.asm.AnnotationVisitor; 44 import jdk.internal.org.objectweb.asm.ClassVisitor; 45 import jdk.internal.org.objectweb.asm.ClassWriter; 46 import jdk.internal.org.objectweb.asm.MethodVisitor; 47 import jdk.internal.org.objectweb.asm.TypeReference; 48 49 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT; 50 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ANNOTATION; 51 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL; 52 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE; 53 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; 54 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; 55 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS; 56 import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; 57 import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN; 58 import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN; 59 import static jdk.internal.org.objectweb.asm.Opcodes.I2C; 60 import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN; 61 import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN; 62 import static jdk.internal.org.objectweb.asm.Opcodes.V1_8; 63 64 /** 65 * Scan a header file and generate classes for entities defined in that header 66 * file. 67 */ 68 final class AsmCodeFactory { 69 private static final String ANNOTATION_PKG_PREFIX = "Ljava/foreign/annotations/"; 70 private static final String NATIVE_CALLBACK = ANNOTATION_PKG_PREFIX + "NativeCallback;"; 71 private static final String NATIVE_HEADER = ANNOTATION_PKG_PREFIX + "NativeHeader;"; 72 private static final String NATIVE_LOCATION = ANNOTATION_PKG_PREFIX + "NativeLocation;"; 73 private static final String NATIVE_STRUCT = ANNOTATION_PKG_PREFIX + "NativeStruct;"; 74 75 private final Context ctx; 76 private final ClassWriter global_cw; 77 // to avoid duplicate generation of methods, field accessors 78 private final Set<String> global_methods = new HashSet<>(); 79 private final Set<String> global_fields = new HashSet<>(); 80 private final String internal_name; 81 private final HeaderFile owner; 82 private final Map<String, byte[]> types; 83 private final Logger logger = Logger.getLogger(getClass().getPackage().getName()); 84 private final List<String> headerDeclarations = new ArrayList<>(); 85 private transient boolean built = false; 86 87 AsmCodeFactory(Context ctx, HeaderFile header) { 88 this.ctx = ctx; 89 logger.info(() -> "Instantiate AsmCodeFactory for " + header.path); 90 this.owner = header; 91 this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName); 92 this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 93 this.types = new HashMap<>(); 94 global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, 95 internal_name, 96 null, "java/lang/Object", null); 97 } 98 99 private void generateNativeHeader() { 100 generateMacros(); 101 AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true); 102 av.visit("path", owner.path.toAbsolutePath().toString()); 103 if (owner.libraries != null && !owner.libraries.isEmpty()) { 104 AnnotationVisitor libNames = av.visitArray("libraries"); 105 for (String name : owner.libraries) { 106 libNames.visit(null, name); 107 } 108 libNames.visitEnd(); 109 if (owner.libraryPaths != null && !owner.libraryPaths.isEmpty()) { 110 AnnotationVisitor libPaths = av.visitArray("libraryPaths"); 111 for (String path : owner.libraryPaths) { 112 libPaths.visit(null, path); 113 } 114 libPaths.visitEnd(); 115 } 116 } 117 av.visit("declarations", String.join(" ", headerDeclarations)); 118 av.visitEnd(); 119 } 120 121 private void handleException(Exception ex) { 122 ctx.err.println(Main.format("cannot.write.class.file", owner.pkgName + "." + owner.clsName, ex)); 123 if (Main.DEBUG) { 124 ex.printStackTrace(ctx.err); 125 } 126 } 127 128 private void annotateNativeLocation(ClassVisitor cw, Cursor dcl) { 129 AnnotationVisitor av = cw.visitAnnotation(NATIVE_LOCATION, true); 130 SourceLocation src = dcl.getSourceLocation(); 131 SourceLocation.Location loc = src.getFileLocation(); 132 Path p = loc.path(); 133 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString()); 134 av.visit("line", loc.line()); 135 av.visit("column", loc.column()); 136 av.visit("USR", dcl.USR()); 137 av.visitEnd(); 138 } 139 140 private void writeClassFile(final ClassWriter cw, String clsName) 141 throws IOException { 142 cw.visitEnd(); 143 byte[] bytecodes = cw.toByteArray(); 144 if (null != types.put(clsName, bytecodes)) { 145 logger.warning("Class " + clsName + " definition is overwritten"); 146 } 147 } 148 149 /** 150 * 151 * @param cw ClassWriter for the struct 152 * @param c The FieldDecl cursor 153 * @param parentType The struct type 154 */ 155 private void addField(ClassVisitor cw, Cursor c, Type parentType) { 156 String fieldName = c.spelling(); 157 if (fieldName.isEmpty()) { 158 //skip anon fields 159 return; 160 } 161 Type t = c.type(); 162 JType jt = owner.globalLookup(t); 163 assert (jt != null); 164 if (cw == global_cw) { 165 String uniqueName = fieldName + "." + jt.getDescriptor(); 166 if (! global_fields.add(uniqueName)) { 167 return; // added already 168 } 169 } 170 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$get", 171 "()" + jt.getDescriptor(), "()" + jt.getSignature(), null); 172 173 AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true); 174 SourceLocation src = c.getSourceLocation(); 175 SourceLocation.Location loc = src.getFileLocation(); 176 Path p = loc.path(); 177 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString()); 178 av.visit("line", loc.line()); 179 av.visit("column", loc.column()); 180 av.visit("USR", c.USR()); 181 av.visitEnd(); 182 183 mv.visitEnd(); 184 cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$set", 185 "(" + jt.getDescriptor() + ")V", 186 "(" + JType.getPointerVoidAsWildcard(jt) + ")V", null); 187 if (!c.isBitField()) { 188 JType ptrType = new PointerType(jt); 189 cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$ptr", 190 "()" + ptrType.getDescriptor(), "()" + ptrType.getSignature(), null); 191 } 192 } 193 194 private void addVar(ClassVisitor cw, Cursor c, Type parentType) { 195 addField(cw, c, parentType); 196 Layout layout = Utils.getLayout(c.type()); 197 String descStr = decorateAsAccessor(c, layout).toString(); 198 addHeaderDecl(c.spelling(), descStr); 199 } 200 201 private void addHeaderDecl(String symbol, String desc) { 202 headerDeclarations.add(String.format("%s=%s", symbol, desc)); 203 } 204 205 private void addConstant(ClassVisitor cw, Cursor c) { 206 assert (c.kind() == CursorKind.EnumConstantDecl); 207 String name = c.spelling(); 208 String desc = owner.globalLookup(c.type()).getDescriptor(); 209 Object value = null; 210 switch (desc) { 211 case "J": 212 value = c.getEnumConstantValue(); 213 break; 214 case "I": 215 value = (int) c.getEnumConstantValue(); 216 break; 217 } 218 cw.visitField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, name, desc, null, value); 219 } 220 221 private void createStruct(Cursor cursor) { 222 String nativeName = Utils.getIdentifier(cursor); 223 Type t = cursor.type(); 224 logger.fine(() -> "Create struct: " + nativeName); 225 226 String intf = Utils.toClassName(nativeName); 227 String name = internal_name + "$" + intf; 228 229 logger.fine(() -> "Define class " + name + " for native type " + nativeName); 230 /* FIXME: Member interface is implicit static, also ASM.CheckClassAdapter is not 231 * taking static as a valid flag, so comment this out during development. 232 */ 233 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); 234 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 235 cw.visit(V1_8, ACC_PUBLIC /*| ACC_STATIC*/ | ACC_INTERFACE | ACC_ABSTRACT, 236 name, "Ljava/lang/Object;Ljava/foreign/memory/Struct<L" + name + ";>;", 237 "java/lang/Object", new String[] {"java/foreign/memory/Struct"}); 238 annotateNativeLocation(cw, cursor); 239 240 AnnotationVisitor av = cw.visitAnnotation(NATIVE_STRUCT, true); 241 Layout structLayout = Utils.getRecordLayout(t, this::decorateAsAccessor); 242 av.visit("value", structLayout.toString()); 243 av.visitEnd(); 244 cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); 245 246 // fields 247 structFields(cursor).forEach(cx -> addField(cw, cx, cursor.type())); 248 // Write class 249 try { 250 writeClassFile(cw, owner.clsName + "$" + intf); 251 } catch (IOException ex) { 252 handleException(ex); 253 } 254 } 255 256 Layout decorateAsAccessor(Cursor accessorCursor, Layout layout) { 257 String accessorName = accessorCursor.spelling(); 258 layout = layout 259 .withAnnotation("get", accessorName + "$get") 260 .withAnnotation("set", accessorName + "$set"); 261 if (!accessorCursor.isBitField()) { 262 //no pointer accessors for bitfield! 263 layout = layout.withAnnotation("ptr", accessorName + "$ptr"); 264 } 265 return layout; 266 } 267 268 // A stream of fields of a struct (or union). Note that we have to include 269 // fields from nested annoymous unions and structs in the containing struct. 270 private Stream<Cursor> structFields(Cursor cursor) { 271 return cursor.children() 272 .flatMap(c -> c.isAnonymousStruct()? structFields(c) : Stream.of(c)) 273 .filter(c -> c.kind() == CursorKind.FieldDecl); 274 } 275 276 private void createEnum(Cursor cursor) { 277 // define enum constants in global_cw 278 cursor.stream() 279 .filter(cx -> cx.kind() == CursorKind.EnumConstantDecl) 280 .forEachOrdered(cx -> addConstant(global_cw, cx)); 281 282 if (cursor.isAnonymousEnum()) { 283 // We are done with anonymous enum 284 return; 285 } 286 287 // generate annotation class for named enum 288 createAnnotationCls(cursor); 289 } 290 291 private void createAnnotationCls(Cursor dcl) { 292 String nativeName = Utils.getIdentifier(dcl); 293 logger.fine(() -> "Create annotation for: " + nativeName); 294 295 String intf = Utils.toClassName(nativeName); 296 String name = internal_name + "$" + intf; 297 298 logger.fine(() -> "Define class " + name + " for native type " + nativeName); 299 global_cw.visitInnerClass(name, internal_name, intf, 300 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION); 301 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 302 String[] superAnno = { "java/lang/annotation/Annotation" }; 303 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION, 304 name, null, "java/lang/Object", superAnno); 305 annotateNativeLocation(cw, dcl); 306 Type t = dcl.type().canonicalType(); 307 AnnotationVisitor av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true); 308 av.visitEnum("value", "Ljava/lang/annotation/ElementType;", "TYPE_USE"); 309 av.visitEnd(); 310 av = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); 311 av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME"); 312 av.visitEnd(); 313 cw.visitInnerClass(name, internal_name, intf, 314 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION); 315 // Write class 316 try { 317 writeClassFile(cw, owner.clsName + "$" + intf); 318 } catch (IOException ex) { 319 handleException(ex); 320 } 321 } 322 323 private void createFunctionalInterface(Cursor dcl, JType.FnIf fnif) { 324 JType.Function fn = fnif.getFunction(); 325 String intf; 326 String nativeName; 327 String nDesc = fnif.getFunction().getNativeDescriptor(); 328 if (dcl == null) { 329 intf = ((JType.InnerType) fnif.type).getName(); 330 nativeName = "anonymous function"; 331 } else { 332 nativeName = Utils.getIdentifier(dcl); 333 intf = Utils.toClassName(nativeName); 334 } 335 logger.fine(() -> "Create FunctionalInterface " + intf); 336 337 final String name = internal_name + "$" + intf; 338 339 logger.fine(() -> "Define class " + name + " for native type " + nativeName + nDesc); 340 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); 341 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 342 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, 343 name, "Ljava/lang/Object;Ljava/foreign/memory/Callback<L" + name + ";>;", 344 "java/lang/Object", new String[] {"java/foreign/memory/Callback"}); 345 if (dcl != null) { 346 annotateNativeLocation(cw, dcl); 347 } 348 AnnotationVisitor av = cw.visitAnnotation( 349 "Ljava/lang/FunctionalInterface;", true); 350 av.visitEnd(); 351 av = cw.visitAnnotation(NATIVE_CALLBACK, true); 352 av.visit("value", nDesc); 353 av.visitEnd(); 354 cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); 355 356 // add the method 357 358 int flags = ACC_PUBLIC | ACC_ABSTRACT; 359 if (fn.isVarArgs) { 360 flags |= ACC_VARARGS; 361 } 362 MethodVisitor mv = cw.visitMethod(flags, "fn", 363 fn.getDescriptor(), fn.getSignature(), null); 364 mv.visitEnd(); 365 // Write class 366 try { 367 writeClassFile(cw, owner.clsName + "$" + intf); 368 } catch (IOException ex) { 369 handleException(ex); 370 } 371 } 372 373 private void defineType(Cursor dcl, TypeAlias alias) { 374 if (alias.getAnnotationDescriptor() != null) { 375 createAnnotationCls(dcl); 376 } else { 377 JType real = alias.canonicalType(); 378 if (real instanceof JType.FnIf) { 379 createFunctionalInterface(dcl, (JType.FnIf) real); 380 } 381 // Otherwise, type alias is a same named stuct 382 } 383 } 384 385 private void addMethod(Cursor dcl, JType.Function fn) { 386 String uniqueName = dcl.spelling() + "." + fn.getDescriptor(); 387 if (! global_methods.add(uniqueName)) { 388 return; // added already 389 } 390 logger.fine(() -> "Add method: " + fn.getSignature()); 391 int flags = ACC_PUBLIC | ACC_ABSTRACT; 392 if (fn.isVarArgs) { 393 flags |= ACC_VARARGS; 394 } 395 MethodVisitor mv = global_cw.visitMethod(flags, 396 dcl.spelling(), fn.getDescriptor(), fn.getSignature(), null); 397 final int arg_cnt = dcl.numberOfArgs(); 398 for (int i = 0; i < arg_cnt; i++) { 399 String name = dcl.getArgument(i).spelling(); 400 final int tmp = i; 401 logger.finer(() -> " arg " + tmp + ": " + name); 402 mv.visitParameter(name, 0); 403 } 404 AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true); 405 SourceLocation src = dcl.getSourceLocation(); 406 SourceLocation.Location loc = src.getFileLocation(); 407 Path p = loc.path(); 408 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString()); 409 av.visit("line", loc.line()); 410 av.visit("column", loc.column()); 411 av.visit("USR", dcl.USR()); 412 av.visitEnd(); 413 Type t = dcl.type(); 414 final String descStr = Utils.getFunction(t).toString(); 415 addHeaderDecl(dcl.spelling(), descStr); 416 417 int idx = 0; 418 for (JType arg: fn.args) { 419 if (arg instanceof TypeAlias) { 420 TypeAlias alias = (TypeAlias) arg; 421 final int tmp = idx; 422 logger.finest(() -> " arg " + tmp + " is an alias " + alias); 423 if (alias.getAnnotationDescriptor() != null) { 424 mv.visitTypeAnnotation( 425 TypeReference.newFormalParameterReference(idx).getValue(), 426 null, alias.getAnnotationDescriptor(), true) 427 .visitEnd(); 428 } 429 } 430 idx++; 431 } 432 433 if (fn.returnType instanceof TypeAlias) { 434 TypeAlias alias = (TypeAlias) fn.returnType; 435 logger.finest(() -> " return type is an alias " + alias); 436 if (alias.getAnnotationDescriptor() != null) { 437 mv.visitTypeAnnotation( 438 TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(), 439 null, alias.getAnnotationDescriptor(), true) 440 .visitEnd(); 441 } 442 } 443 mv.visitEnd(); 444 } 445 446 protected AsmCodeFactory addType(JType jt, Cursor cursor) { 447 JType2 jt2 = null; 448 if (jt instanceof JType2) { 449 jt2 = (JType2) jt; 450 jt = jt2.getDelegate(); 451 } else { 452 logger.warning(() -> "Should have JType2 in addType"); 453 if (Main.DEBUG) { 454 new Throwable().printStackTrace(ctx.err); 455 } 456 } 457 if (cursor == null) { 458 assert (jt2 != null); 459 if (jt instanceof JType.FnIf) { 460 createFunctionalInterface(null, (JType.FnIf) jt); 461 } 462 return this; 463 } 464 boolean noDef = cursor.isInvalid(); 465 if (noDef) { 466 cursor = jt2.getCursor(); 467 } 468 469 final Cursor c = cursor; 470 471 try { 472 logger.fine(() -> "Process cursor " + c.spelling()); 473 switch (cursor.kind()) { 474 case StructDecl: 475 case UnionDecl: 476 createStruct(cursor); 477 break; 478 case FunctionDecl: 479 assert (jt instanceof JType.Function); 480 addMethod(cursor, (JType.Function) jt); 481 break; 482 case EnumDecl: 483 createEnum(cursor); 484 break; 485 case TypedefDecl: 486 // anonymous typedef struct {} xxx will not get TypeAlias 487 if (jt instanceof TypeAlias) { 488 defineType(cursor, (TypeAlias) jt); 489 } 490 break; 491 case VarDecl: 492 addVar(global_cw, cursor, null); 493 break; 494 default: 495 logger.warning(() -> "Unsupported declaration Cursor:"); 496 logger.warning(() -> Printer.Stringifier(p -> p.dumpCursor(c, true))); 497 break; 498 } 499 } catch (Exception ex) { 500 handleException(ex); 501 logger.warning("Cursor causing above exception is: " + c.spelling()); 502 logger.warning(() -> Printer.Stringifier(p -> p.dumpCursor(c, true))); 503 } 504 return this; 505 } 506 507 AsmCodeFactory generateMacros() { 508 for (MacroParser.Macro macro : ctx.macros(owner)) { 509 if (macro.isConstantMacro()) { 510 logger.fine(() -> "Adding macro " + macro.name()); 511 Object value = macro.value(); 512 Class<?> macroType = (Class<?>) Util.unboxIfNeeded(value.getClass()); 513 514 String sig = jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(jdk.internal.org.objectweb.asm.Type.getType(macroType)); 515 MethodVisitor mv = global_cw.visitMethod(ACC_PUBLIC, macro.name(), sig, sig, null); 516 517 Cursor cursor = macro.cursor(); 518 AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true); 519 SourceLocation src = cursor.getSourceLocation(); 520 SourceLocation.Location loc = src.getFileLocation(); 521 Path p = loc.path(); 522 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString()); 523 av.visit("line", loc.line()); 524 av.visit("column", loc.column()); 525 av.visit("USR", cursor.USR()); 526 av.visitEnd(); 527 528 mv.visitCode(); 529 530 mv.visitLdcInsn(value); 531 if (macroType.equals(char.class)) { 532 mv.visitInsn(I2C); 533 mv.visitInsn(IRETURN); 534 } else if (macroType.equals(int.class)) { 535 mv.visitInsn(IRETURN); 536 } else if (macroType.equals(float.class)) { 537 mv.visitInsn(FRETURN); 538 } else if (macroType.equals(long.class)) { 539 mv.visitInsn(LRETURN); 540 } else if (macroType.equals(double.class)) { 541 mv.visitInsn(DRETURN); 542 } else if (macroType.equals(String.class)) { 543 mv.visitInsn(ARETURN); 544 } 545 mv.visitMaxs(0, 0); 546 mv.visitEnd(); 547 } else { 548 logger.fine(() -> "Skipping unrecognized object-like macro " + macro.name()); 549 } 550 } 551 552 return this; 553 } 554 555 protected synchronized void produce() { 556 if (built) { 557 throw new IllegalStateException("Produce is called multiple times"); 558 } 559 built = true; 560 generateNativeHeader(); 561 try { 562 writeClassFile(global_cw, owner.clsName); 563 } catch (IOException ex) { 564 handleException(ex); 565 } 566 } 567 568 protected Map<String, byte[]> collect() { 569 // Ensure classes are produced 570 if (!built) produce(); 571 HashMap<String, byte[]> rv = new HashMap<>(); 572 // Not copying byte[] for efficiency, perhaps not a safe idea though 573 if (owner.pkgName.isEmpty()) { 574 types.forEach((clsName, bytecodes) -> { 575 rv.put(clsName, bytecodes); 576 }); 577 } else { 578 types.forEach((clsName, bytecodes) -> { 579 rv.put(owner.pkgName + "." + clsName, bytecodes); 580 }); 581 } 582 return Collections.unmodifiableMap(rv); 583 } 584 585 public static void main(String[] args) throws IOException { 586 final Path file = Paths.get(args[1]); 587 final String pkg = args[0]; 588 Context ctx = new Context(); 589 ctx.usePackageForFolder(file, pkg); 590 ctx.usePackageForFolder(Paths.get("/usr/include"), "system"); 591 ctx.addSource(file); 592 ctx.parse(); 593 ctx.collectJarFile(Paths.get(args[2]), args, pkg); 594 } 595 }