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.SourceLocation; 39 import jdk.internal.clang.Type; 40 import jdk.internal.clang.TypeKind; 41 import jdk.internal.org.objectweb.asm.AnnotationVisitor; 42 import jdk.internal.org.objectweb.asm.ClassVisitor; 43 import jdk.internal.org.objectweb.asm.ClassWriter; 44 import jdk.internal.org.objectweb.asm.MethodVisitor; 45 import jdk.internal.org.objectweb.asm.TypeReference; 46 import com.sun.tools.jextract.tree.EnumTree; 47 import com.sun.tools.jextract.tree.FieldTree; 48 import com.sun.tools.jextract.tree.FunctionTree; 49 import com.sun.tools.jextract.tree.MacroTree; 50 import com.sun.tools.jextract.tree.SimpleTreeVisitor; 51 import com.sun.tools.jextract.tree.StructTree; 52 import com.sun.tools.jextract.tree.Tree; 53 import com.sun.tools.jextract.tree.TypedefTree; 54 import com.sun.tools.jextract.tree.VarTree; 55 56 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT; 57 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ANNOTATION; 58 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL; 59 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_INTERFACE; 60 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; 61 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; 62 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS; 63 import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; 64 import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN; 65 import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN; 66 import static jdk.internal.org.objectweb.asm.Opcodes.I2C; 67 import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN; 68 import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN; 69 import static jdk.internal.org.objectweb.asm.Opcodes.V1_8; 70 71 /** 72 * Scan a header file and generate classes for entities defined in that header 73 * file. 74 */ 75 final class AsmCodeFactory extends SimpleTreeVisitor<Void, JType> { 76 private static final String ANNOTATION_PKG_PREFIX = "Ljava/foreign/annotations/"; 77 private static final String NATIVE_CALLBACK = ANNOTATION_PKG_PREFIX + "NativeCallback;"; 78 private static final String NATIVE_HEADER = ANNOTATION_PKG_PREFIX + "NativeHeader;"; 79 private static final String NATIVE_LOCATION = ANNOTATION_PKG_PREFIX + "NativeLocation;"; 80 private static final String NATIVE_STRUCT = ANNOTATION_PKG_PREFIX + "NativeStruct;"; 81 82 private final Context ctx; 83 private final ClassWriter global_cw; 84 // to avoid duplicate generation of methods, field accessors, macros 85 private final Set<String> global_methods = new HashSet<>(); 86 private final Set<String> global_fields = new HashSet<>(); 87 private final Set<String> global_macros = new HashSet<>(); 88 private final String internal_name; 89 private final HeaderFile owner; 90 private final Map<String, byte[]> types; 91 private final Logger logger = Logger.getLogger(getClass().getPackage().getName()); 92 private final List<String> headerDeclarations = new ArrayList<>(); 93 private final StaticForwarderGenerator staticForwardGen; 94 95 private transient boolean built = false; 96 97 AsmCodeFactory(Context ctx, HeaderFile header) { 98 this.ctx = ctx; 99 logger.info(() -> "Instantiate AsmCodeFactory for " + header.path); 100 this.owner = header; 101 this.internal_name = Utils.toInternalName(owner.pkgName, owner.clsName); 102 this.global_cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 103 this.types = new HashMap<>(); 104 global_cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, 105 internal_name, 106 null, "java/lang/Object", null); 107 if (ctx.getGenStaticForwarder()) { 108 this.staticForwardGen = new StaticForwarderGenerator(header); 109 } else { 110 this.staticForwardGen = null; 111 } 112 } 113 114 private void generateNativeHeader() { 115 AnnotationVisitor av = global_cw.visitAnnotation(NATIVE_HEADER, true); 116 av.visit("path", owner.path.toAbsolutePath().toString()); 117 if (owner.libraries != null && !owner.libraries.isEmpty()) { 118 AnnotationVisitor libNames = av.visitArray("libraries"); 119 for (String name : owner.libraries) { 120 libNames.visit(null, name); 121 } 122 libNames.visitEnd(); 123 if (owner.libraryPaths != null && !owner.libraryPaths.isEmpty()) { 124 AnnotationVisitor libPaths = av.visitArray("libraryPaths"); 125 for (String path : owner.libraryPaths) { 126 libPaths.visit(null, path); 127 } 128 libPaths.visitEnd(); 129 } 130 } 131 av.visit("declarations", String.join(" ", headerDeclarations)); 132 av.visitEnd(); 133 } 134 135 private void handleException(Exception ex) { 136 ctx.err.println(Main.format("cannot.write.class.file", owner.pkgName + "." + owner.clsName, ex)); 137 if (Main.DEBUG) { 138 ex.printStackTrace(ctx.err); 139 } 140 } 141 142 private void annotateNativeLocation(ClassVisitor cw, Tree tree) { 143 AnnotationVisitor av = cw.visitAnnotation(NATIVE_LOCATION, true); 144 SourceLocation src = tree.location(); 145 SourceLocation.Location loc = src.getFileLocation(); 146 Path p = loc.path(); 147 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString()); 148 av.visit("line", loc.line()); 149 av.visit("column", loc.column()); 150 av.visit("USR", tree.USR()); 151 av.visitEnd(); 152 } 153 154 private void writeClassFile(final ClassWriter cw, String clsName) 155 throws IOException { 156 cw.visitEnd(); 157 byte[] bytecodes = cw.toByteArray(); 158 if (null != types.put(clsName, bytecodes)) { 159 logger.warning("Class " + clsName + " definition is overwritten"); 160 } 161 } 162 163 private static boolean isBitField(Tree tree) { 164 return tree instanceof FieldTree && ((FieldTree)tree).isBitField(); 165 } 166 167 /** 168 * 169 * @param cw ClassWriter for the struct 170 * @param tree The Tree 171 * @param parentType The struct type 172 */ 173 private void addField(ClassVisitor cw, Tree tree, Type parentType) { 174 String fieldName = tree.name(); 175 assert !fieldName.isEmpty(); 176 Type type = tree.type(); 177 JType jt = owner.globalLookup(type); 178 assert (jt != null); 179 if (cw == global_cw) { 180 String uniqueName = fieldName + "." + jt.getDescriptor(); 181 if (! global_fields.add(uniqueName)) { 182 return; // added already 183 } 184 } 185 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$get", 186 "()" + jt.getDescriptor(), "()" + jt.getSignature(), null); 187 188 AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true); 189 SourceLocation src = tree.location(); 190 SourceLocation.Location loc = src.getFileLocation(); 191 Path p = loc.path(); 192 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString()); 193 av.visit("line", loc.line()); 194 av.visit("column", loc.column()); 195 av.visit("USR", tree.USR()); 196 av.visitEnd(); 197 198 mv.visitEnd(); 199 mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$set", 200 "(" + jt.getDescriptor() + ")V", 201 "(" + JType.getPointerVoidAsWildcard(jt) + ")V", null); 202 mv.visitEnd(); 203 if (tree instanceof VarTree || !isBitField(tree)) { 204 JType ptrType = new PointerType(jt); 205 mv = cw.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fieldName + "$ptr", 206 "()" + ptrType.getDescriptor(), "()" + ptrType.getSignature(), null); 207 mv.visitEnd(); 208 } 209 } 210 211 @Override 212 public Void visitVar(VarTree varTree, JType jt) { 213 addField(global_cw, varTree, null); 214 Layout layout = varTree.layout(); 215 String descStr = decorateAsAccessor(varTree, layout).toString(); 216 addHeaderDecl(varTree.name(), descStr); 217 if (staticForwardGen != null) { 218 staticForwardGen.visitVar(varTree, jt); 219 } 220 return null; 221 } 222 223 private void addHeaderDecl(String symbol, String desc) { 224 headerDeclarations.add(String.format("%s=%s", symbol, desc)); 225 } 226 227 private void addConstant(ClassWriter cw, FieldTree fieldTree) { 228 assert (fieldTree.isEnumConstant()); 229 String name = fieldTree.name(); 230 String desc = owner.globalLookup(fieldTree.type()).getDescriptor(); 231 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, name, "()" + desc, null, null); 232 mv.visitCode(); 233 if (desc.length() != 1) { 234 throw new AssertionError("expected single char descriptor: " + desc); 235 } 236 switch (desc.charAt(0)) { 237 case 'J': 238 long lvalue = fieldTree.enumConstant().get(); 239 mv.visitLdcInsn(lvalue); 240 mv.visitInsn(LRETURN); 241 break; 242 case 'I': 243 int ivalue = fieldTree.enumConstant().get().intValue(); 244 mv.visitLdcInsn(ivalue); 245 mv.visitInsn(IRETURN); 246 break; 247 default: 248 throw new AssertionError("should not reach here"); 249 } 250 mv.visitMaxs(1, 1); 251 mv.visitEnd(); 252 } 253 254 @Override 255 public Void visitStruct(StructTree structTree, JType jt) { 256 String nativeName = structTree.name(); 257 Type type = structTree.type(); 258 logger.fine(() -> "Create struct: " + nativeName); 259 260 String intf = Utils.toClassName(nativeName); 261 String name = internal_name + "$" + intf; 262 263 logger.fine(() -> "Define class " + name + " for native type " + nativeName); 264 /* FIXME: Member interface is implicit static, also ASM.CheckClassAdapter is not 265 * taking static as a valid flag, so comment this out during development. 266 */ 267 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); 268 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 269 cw.visit(V1_8, ACC_PUBLIC /*| ACC_STATIC*/ | ACC_INTERFACE | ACC_ABSTRACT, 270 name, "Ljava/lang/Object;Ljava/foreign/memory/Struct<L" + name + ";>;", 271 "java/lang/Object", new String[] {"java/foreign/memory/Struct"}); 272 annotateNativeLocation(cw, structTree); 273 274 AnnotationVisitor av = cw.visitAnnotation(NATIVE_STRUCT, true); 275 Layout structLayout = structTree.layout(this::decorateAsAccessor); 276 av.visit("value", structLayout.toString()); 277 av.visitEnd(); 278 cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); 279 280 // fields 281 structTree.fields().forEach(fieldTree -> addField(cw, fieldTree, type)); 282 // Write class 283 try { 284 writeClassFile(cw, owner.clsName + "$" + intf); 285 } catch (IOException ex) { 286 handleException(ex); 287 } 288 return null; 289 } 290 291 Layout addGetterSetterName(Layout layout, String accessorName) { 292 return layout 293 .withAnnotation("get", accessorName + "$get") 294 .withAnnotation("set", accessorName + "$set"); 295 } 296 297 Layout decorateAsAccessor(VarTree varTree, Layout layout) { 298 return addGetterSetterName(layout, varTree.name()). 299 withAnnotation("ptr", varTree.name() + "$ptr"); 300 } 301 302 Layout decorateAsAccessor(FieldTree fieldTree, Layout layout) { 303 layout = addGetterSetterName(layout, fieldTree.name()); 304 if (!fieldTree.isBitField()) { 305 //no pointer accessors for bitfield! 306 layout = layout.withAnnotation("ptr", fieldTree.name() + "$ptr"); 307 } 308 return layout; 309 } 310 311 @Override 312 public Void visitEnum(EnumTree enumTree, JType jt) { 313 // define enum constants in global_cw 314 enumTree.constants().forEach(constant -> addConstant(global_cw, constant)); 315 316 if (enumTree.name().isEmpty()) { 317 // We are done with anonymous enum 318 return null; 319 } 320 321 // generate annotation class for named enum 322 createAnnotationCls(enumTree); 323 if (staticForwardGen != null) { 324 staticForwardGen.visitEnum(enumTree, jt); 325 } 326 return null; 327 } 328 329 private void createAnnotationCls(Tree tree) { 330 String nativeName = tree.name(); 331 logger.fine(() -> "Create annotation for: " + nativeName); 332 333 String intf = Utils.toClassName(nativeName); 334 String name = internal_name + "$" + intf; 335 336 logger.fine(() -> "Define class " + name + " for native type " + nativeName); 337 global_cw.visitInnerClass(name, internal_name, intf, 338 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION); 339 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 340 String[] superAnno = { "java/lang/annotation/Annotation" }; 341 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION, 342 name, null, "java/lang/Object", superAnno); 343 annotateNativeLocation(cw, tree); 344 Type type = tree.type().canonicalType(); 345 AnnotationVisitor av = cw.visitAnnotation("Ljava/lang/annotation/Target;", true); 346 av.visitEnum("value", "Ljava/lang/annotation/ElementType;", "TYPE_USE"); 347 av.visitEnd(); 348 av = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true); 349 av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME"); 350 av.visitEnd(); 351 cw.visitInnerClass(name, internal_name, intf, 352 ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_ANNOTATION); 353 // Write class 354 try { 355 writeClassFile(cw, owner.clsName + "$" + intf); 356 } catch (IOException ex) { 357 handleException(ex); 358 } 359 } 360 361 private void createFunctionalInterface(Tree tree, JType.FnIf fnif) { 362 JType.Function fn = fnif.getFunction(); 363 String intf; 364 String nativeName; 365 String nDesc = fnif.getFunction().getNativeDescriptor(); 366 if (tree == null) { 367 intf = ((JType.InnerType) fnif.type).getName(); 368 nativeName = "anonymous function"; 369 } else { 370 nativeName = tree.name(); 371 intf = Utils.toClassName(nativeName); 372 } 373 logger.fine(() -> "Create FunctionalInterface " + intf); 374 375 final String name = internal_name + "$" + intf; 376 377 logger.fine(() -> "Define class " + name + " for native type " + nativeName + nDesc); 378 global_cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); 379 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 380 cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, 381 name, "Ljava/lang/Object;", 382 "java/lang/Object", new String[0]); 383 if (tree != null) { 384 annotateNativeLocation(cw, tree); 385 } 386 AnnotationVisitor av = cw.visitAnnotation( 387 "Ljava/lang/FunctionalInterface;", true); 388 av.visitEnd(); 389 av = cw.visitAnnotation(NATIVE_CALLBACK, true); 390 av.visit("value", nDesc); 391 av.visitEnd(); 392 cw.visitInnerClass(name, internal_name, intf, ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); 393 394 // add the method 395 396 int flags = ACC_PUBLIC | ACC_ABSTRACT; 397 if (fn.isVarArgs) { 398 flags |= ACC_VARARGS; 399 } 400 MethodVisitor mv = cw.visitMethod(flags, "fn", 401 fn.getDescriptor(), fn.getSignature(), null); 402 mv.visitEnd(); 403 // Write class 404 try { 405 writeClassFile(cw, owner.clsName + "$" + intf); 406 } catch (IOException ex) { 407 handleException(ex); 408 } 409 } 410 411 @Override 412 public Void visitTypedef(TypedefTree typedefTree, JType jt) { 413 // anonymous typedef struct {} xxx will not get TypeAlias 414 if (jt instanceof TypeAlias) { 415 TypeAlias alias = (TypeAlias) jt; 416 if (alias.getAnnotationDescriptor() != null) { 417 createAnnotationCls(typedefTree); 418 } else { 419 JType real = alias.canonicalType(); 420 if (real instanceof JType.FnIf) { 421 createFunctionalInterface(typedefTree, (JType.FnIf) real); 422 } 423 // Otherwise, type alias is a same named stuct 424 } 425 } 426 return null; 427 } 428 429 @Override 430 public Void visitTree(Tree tree, JType jt) { 431 logger.warning(() -> "Unsupported declaration tree:"); 432 logger.warning(() -> tree.toString()); 433 return null; 434 } 435 436 @Override 437 public Void visitFunction(FunctionTree funcTree, JType jt) { 438 assert (jt instanceof JType.Function); 439 JType.Function fn = (JType.Function)jt; 440 String uniqueName = funcTree.name() + "." + fn.getDescriptor(); 441 if (! global_methods.add(uniqueName)) { 442 return null; // added already 443 } 444 logger.fine(() -> "Add method: " + fn.getSignature()); 445 int flags = ACC_PUBLIC | ACC_ABSTRACT; 446 if (fn.isVarArgs) { 447 flags |= ACC_VARARGS; 448 } 449 MethodVisitor mv = global_cw.visitMethod(flags, 450 funcTree.name(), fn.getDescriptor(), fn.getSignature(), null); 451 final int arg_cnt = funcTree.numParams(); 452 for (int i = 0; i < arg_cnt; i++) { 453 String name = funcTree.paramName(i); 454 final int tmp = i; 455 logger.finer(() -> " arg " + tmp + ": " + name); 456 mv.visitParameter(name, 0); 457 } 458 AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true); 459 SourceLocation src = funcTree.location(); 460 SourceLocation.Location loc = src.getFileLocation(); 461 Path p = loc.path(); 462 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString()); 463 av.visit("line", loc.line()); 464 av.visit("column", loc.column()); 465 av.visit("USR", funcTree.USR()); 466 av.visitEnd(); 467 Type type = funcTree.type(); 468 final String descStr = Utils.getFunction(type).toString(); 469 addHeaderDecl(funcTree.name(), descStr); 470 471 int idx = 0; 472 for (JType arg: fn.args) { 473 if (arg instanceof TypeAlias) { 474 TypeAlias alias = (TypeAlias) arg; 475 final int tmp = idx; 476 logger.finest(() -> " arg " + tmp + " is an alias " + alias); 477 if (alias.getAnnotationDescriptor() != null) { 478 mv.visitTypeAnnotation( 479 TypeReference.newFormalParameterReference(idx).getValue(), 480 null, alias.getAnnotationDescriptor(), true) 481 .visitEnd(); 482 } 483 } 484 idx++; 485 } 486 487 if (fn.returnType instanceof TypeAlias) { 488 TypeAlias alias = (TypeAlias) fn.returnType; 489 logger.finest(() -> " return type is an alias " + alias); 490 if (alias.getAnnotationDescriptor() != null) { 491 mv.visitTypeAnnotation( 492 TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(), 493 null, alias.getAnnotationDescriptor(), true) 494 .visitEnd(); 495 } 496 } 497 mv.visitEnd(); 498 if (staticForwardGen != null) { 499 staticForwardGen.visitFunction(funcTree, jt); 500 } 501 return null; 502 } 503 504 protected AsmCodeFactory addType(JType jt, Tree tree) { 505 JType2 jt2 = null; 506 if (jt instanceof JType2) { 507 jt2 = (JType2) jt; 508 jt = jt2.getDelegate(); 509 } else { 510 logger.warning(() -> "Should have JType2 in addType"); 511 if (Main.DEBUG) { 512 new Throwable().printStackTrace(ctx.err); 513 } 514 } 515 if (tree == null) { 516 assert (jt2 != null); 517 if (jt instanceof JType.FnIf) { 518 createFunctionalInterface(null, (JType.FnIf) jt); 519 } 520 return this; 521 } 522 /* 523 // FIXME: what is this? 524 boolean noDef = cursor.isInvalid(); 525 if (noDef) { 526 cursor = jt2.getCursor(); 527 } 528 */ 529 530 try { 531 logger.fine(() -> "Process tree " + tree.name()); 532 tree.accept(this, jt); 533 } catch (Exception ex) { 534 handleException(ex); 535 logger.warning("Tree causing above exception is: " + tree.name()); 536 logger.warning(() -> tree.toString()); 537 } 538 return this; 539 } 540 541 @Override 542 public Void visitMacro(MacroTree macroTree, JType jt) { 543 if (!macroTree.isConstant()) { 544 logger.fine(() -> "Skipping unrecognized object-like macro " + macroTree.name()); 545 return null; 546 } 547 String name = macroTree.name(); 548 Object value = macroTree.value().get(); 549 if (! global_macros.add(name)) { 550 return null; // added already 551 } 552 logger.fine(() -> "Adding macro " + name); 553 Class<?> macroType = Utils.unboxIfNeeded(value.getClass()); 554 555 String sig = jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(jdk.internal.org.objectweb.asm.Type.getType(macroType)); 556 MethodVisitor mv = global_cw.visitMethod(ACC_PUBLIC, name, sig, sig, null); 557 558 AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true); 559 SourceLocation src = macroTree.location(); 560 SourceLocation.Location loc = src.getFileLocation(); 561 Path p = loc.path(); 562 av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString()); 563 av.visit("line", loc.line()); 564 av.visit("column", loc.column()); 565 av.visit("USR", macroTree.USR()); 566 av.visitEnd(); 567 568 mv.visitCode(); 569 570 mv.visitLdcInsn(value); 571 if (macroType.equals(char.class)) { 572 mv.visitInsn(I2C); 573 mv.visitInsn(IRETURN); 574 } else if (macroType.equals(int.class)) { 575 mv.visitInsn(IRETURN); 576 } else if (macroType.equals(float.class)) { 577 mv.visitInsn(FRETURN); 578 } else if (macroType.equals(long.class)) { 579 mv.visitInsn(LRETURN); 580 } else if (macroType.equals(double.class)) { 581 mv.visitInsn(DRETURN); 582 } else if (macroType.equals(String.class)) { 583 mv.visitInsn(ARETURN); 584 } 585 mv.visitMaxs(0, 0); 586 mv.visitEnd(); 587 if (staticForwardGen != null) { 588 staticForwardGen.visitMacro(macroTree, jt); 589 } 590 return null; 591 } 592 593 protected synchronized void produce() { 594 if (built) { 595 throw new IllegalStateException("Produce is called multiple times"); 596 } 597 built = true; 598 generateNativeHeader(); 599 try { 600 writeClassFile(global_cw, owner.clsName); 601 } catch (IOException ex) { 602 handleException(ex); 603 } 604 if (staticForwardGen != null) { 605 types.put(staticForwardGen.getSimpleClassName(), staticForwardGen.getClassBytes()); 606 } 607 } 608 609 protected Map<String, byte[]> collect() { 610 // Ensure classes are produced 611 if (!built) produce(); 612 HashMap<String, byte[]> rv = new HashMap<>(); 613 // Not copying byte[] for efficiency, perhaps not a safe idea though 614 if (owner.pkgName.isEmpty()) { 615 types.forEach((clsName, bytecodes) -> { 616 rv.put(clsName, bytecodes); 617 }); 618 } else { 619 types.forEach((clsName, bytecodes) -> { 620 rv.put(owner.pkgName + "." + clsName, bytecodes); 621 }); 622 } 623 return Collections.unmodifiableMap(rv); 624 } 625 } --- EOF ---