1 /* 2 * Copyright (c) 1999, 2023, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.jvm; 27 28 import java.io.*; 29 import java.util.LinkedHashMap; 30 import java.util.Map; 31 import java.util.Set; 32 import java.util.LinkedHashSet; 33 import java.util.function.ToIntFunction; 34 35 import javax.tools.JavaFileManager; 36 import javax.tools.FileObject; 37 import javax.tools.JavaFileManager.Location; 38 import javax.tools.JavaFileObject; 39 40 import com.sun.tools.javac.code.*; 41 import com.sun.tools.javac.code.Attribute.RetentionPolicy; 42 import com.sun.tools.javac.code.Directive.*; 43 import com.sun.tools.javac.code.Scope.WriteableScope; 44 import com.sun.tools.javac.code.Source.Feature; 45 import com.sun.tools.javac.code.Symbol.*; 46 import com.sun.tools.javac.code.Type.*; 47 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException; 48 import com.sun.tools.javac.comp.Check; 49 import com.sun.tools.javac.file.PathFileObject; 50 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; 51 import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey; 52 import com.sun.tools.javac.resources.CompilerProperties.Errors; 53 import com.sun.tools.javac.resources.CompilerProperties.Fragments; 54 import com.sun.tools.javac.util.*; 55 import com.sun.tools.javac.util.List; 56 57 import static com.sun.tools.javac.code.Flags.*; 58 import static com.sun.tools.javac.code.Kinds.Kind.*; 59 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; 60 import static com.sun.tools.javac.code.TypeTag.*; 61 import static com.sun.tools.javac.main.Option.*; 62 63 import static javax.tools.StandardLocation.CLASS_OUTPUT; 64 65 /** This class provides operations to map an internal symbol table graph 66 * rooted in a ClassSymbol into a classfile. 67 * 68 * <p><b>This is NOT part of any supported API. 69 * If you write code that depends on this, you do so at your own risk. 70 * This code and its internal interfaces are subject to change or 71 * deletion without notice.</b> 72 */ 73 public class ClassWriter extends ClassFile { 74 protected static final Context.Key<ClassWriter> classWriterKey = new Context.Key<>(); 75 76 private final Options options; 77 78 /** Switch: verbose output. 79 */ 80 private boolean verbose; 81 82 /** Switch: emit source file attribute. 83 */ 84 private boolean emitSourceFile; 85 86 /** Switch: generate CharacterRangeTable attribute. 87 */ 88 private boolean genCrt; 89 90 /** Switch: describe the generated stackmap. 91 */ 92 private boolean debugstackmap; 93 94 /** Preview language level. 95 */ 96 private Preview preview; 97 98 /** 99 * Target class version. 100 */ 101 private Target target; 102 103 /** 104 * Source language version. 105 */ 106 private Source source; 107 108 /** Type utilities. */ 109 private Types types; 110 111 private Check check; 112 113 private boolean allowPrimitiveClasses; 114 115 /** 116 * If true, class files will be written in module-specific subdirectories 117 * of the CLASS_OUTPUT location. 118 */ 119 public boolean multiModuleMode; 120 121 private List<ToIntFunction<Symbol>> extraAttributeHooks = List.nil(); 122 123 /** The initial sizes of the data and constant pool buffers. 124 * Sizes are increased when buffers get full. 125 */ 126 static final int DATA_BUF_SIZE = 0x0fff0; 127 static final int CLASS_BUF_SIZE = 0x1fff0; 128 129 /** An output buffer for member info. 130 */ 131 public ByteBuffer databuf = new ByteBuffer(DATA_BUF_SIZE); 132 133 /** An output buffer for the constant pool. 134 */ 135 ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE); 136 137 /** The constant pool writer. 138 */ 139 final PoolWriter poolWriter; 140 141 /** The log to use for verbose output. 142 */ 143 private final Log log; 144 145 /** The name table. */ 146 private final Names names; 147 148 private final Symtab syms; 149 150 /** Access to files. */ 151 private final JavaFileManager fileManager; 152 153 /** The tags and constants used in compressed stackmap. */ 154 static final int SAME_FRAME_SIZE = 64; 155 static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; 156 static final int SAME_FRAME_EXTENDED = 251; 157 static final int FULL_FRAME = 255; 158 static final int MAX_LOCAL_LENGTH_DIFF = 4; 159 160 /** Get the ClassWriter instance for this context. */ 161 public static ClassWriter instance(Context context) { 162 ClassWriter instance = context.get(classWriterKey); 163 if (instance == null) 164 instance = new ClassWriter(context); 165 return instance; 166 } 167 168 /** Construct a class writer, given an options table. 169 */ 170 @SuppressWarnings("this-escape") 171 protected ClassWriter(Context context) { 172 context.put(classWriterKey, this); 173 174 log = Log.instance(context); 175 names = Names.instance(context); 176 options = Options.instance(context); 177 preview = Preview.instance(context); 178 target = Target.instance(context); 179 source = Source.instance(context); 180 types = Types.instance(context); 181 check = Check.instance(context); 182 fileManager = context.get(JavaFileManager.class); 183 poolWriter = Gen.instance(context).poolWriter; 184 syms = Symtab.instance(context); 185 186 verbose = options.isSet(VERBOSE); 187 genCrt = options.isSet(XJCOV); 188 debugstackmap = options.isSet("debug.stackmap"); 189 190 emitSourceFile = options.isUnset(G_CUSTOM) || 191 options.isSet(G_CUSTOM, "source"); 192 193 String modifierFlags = options.get("debug.dumpmodifiers"); 194 if (modifierFlags != null) { 195 dumpClassModifiers = modifierFlags.indexOf('c') != -1; 196 dumpFieldModifiers = modifierFlags.indexOf('f') != -1; 197 dumpInnerClassModifiers = modifierFlags.indexOf('i') != -1; 198 dumpMethodModifiers = modifierFlags.indexOf('m') != -1; 199 } 200 Source source = Source.instance(context); 201 allowPrimitiveClasses = Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses"); 202 } 203 204 public void addExtraAttributes(ToIntFunction<Symbol> addExtraAttributes) { 205 extraAttributeHooks = extraAttributeHooks.prepend(addExtraAttributes); 206 } 207 208 /****************************************************************** 209 * Diagnostics: dump generated class names and modifiers 210 ******************************************************************/ 211 212 /** Value of option 'dumpmodifiers' is a string 213 * indicating which modifiers should be dumped for debugging: 214 * 'c' -- classes 215 * 'f' -- fields 216 * 'i' -- innerclass attributes 217 * 'm' -- methods 218 * For example, to dump everything: 219 * javac -XDdumpmodifiers=cifm MyProg.java 220 */ 221 private boolean dumpClassModifiers; // -XDdumpmodifiers=c 222 private boolean dumpFieldModifiers; // -XDdumpmodifiers=f 223 private boolean dumpInnerClassModifiers; // -XDdumpmodifiers=i 224 private boolean dumpMethodModifiers; // -XDdumpmodifiers=m 225 226 227 /** Return flags as a string, separated by " ". 228 */ 229 public static String flagNames(long flags) { 230 StringBuilder sbuf = new StringBuilder(); 231 int i = 0; 232 long f = flags & StandardFlags; 233 while (f != 0) { 234 if ((f & 1) != 0) { 235 sbuf.append(" "); 236 sbuf.append(flagName[i]); 237 } 238 f = f >> 1; 239 i++; 240 } 241 return sbuf.toString(); 242 } 243 //where 244 private static final String[] flagName = { 245 "PUBLIC", "PRIVATE", "PROTECTED", "STATIC", "FINAL", 246 "IDENTITY", "VOLATILE", "TRANSIENT", "NATIVE", "INTERFACE", 247 "ABSTRACT", "STRICTFP"}; 248 249 /****************************************************************** 250 * Output routines 251 ******************************************************************/ 252 253 /** Write a character into given byte buffer; 254 * byte buffer will not be grown. 255 */ 256 void putChar(ByteBuffer buf, int op, int x) { 257 buf.elems[op ] = (byte)((x >> 8) & 0xFF); 258 buf.elems[op+1] = (byte)((x ) & 0xFF); 259 } 260 261 /** Write an integer into given byte buffer; 262 * byte buffer will not be grown. 263 */ 264 void putInt(ByteBuffer buf, int adr, int x) { 265 buf.elems[adr ] = (byte)((x >> 24) & 0xFF); 266 buf.elems[adr+1] = (byte)((x >> 16) & 0xFF); 267 buf.elems[adr+2] = (byte)((x >> 8) & 0xFF); 268 buf.elems[adr+3] = (byte)((x ) & 0xFF); 269 } 270 271 /****************************************************************** 272 * Writing the Constant Pool 273 ******************************************************************/ 274 275 /** Thrown when the constant pool is over full. 276 */ 277 public static class PoolOverflow extends RuntimeException { 278 private static final long serialVersionUID = 0; 279 public PoolOverflow() {} 280 } 281 public static class StringOverflow extends RuntimeException { 282 private static final long serialVersionUID = 0; 283 public final String value; 284 public StringOverflow(String s) { 285 value = s; 286 } 287 } 288 289 /****************************************************************** 290 * Writing Attributes 291 ******************************************************************/ 292 293 /** Write header for an attribute to data buffer and return 294 * position past attribute length index. 295 */ 296 public int writeAttr(Name attrName) { 297 int index = poolWriter.putName(attrName); 298 databuf.appendChar(index); 299 databuf.appendInt(0); 300 return databuf.length; 301 } 302 303 /** Fill in attribute length. 304 */ 305 public void endAttr(int index) { 306 putInt(databuf, index - 4, databuf.length - index); 307 } 308 309 /** Leave space for attribute count and return index for 310 * number of attributes field. 311 */ 312 int beginAttrs() { 313 databuf.appendChar(0); 314 return databuf.length; 315 } 316 317 /** Fill in number of attributes. 318 */ 319 void endAttrs(int index, int count) { 320 putChar(databuf, index - 2, count); 321 } 322 323 /** Write the EnclosingMethod attribute if needed. 324 * Returns the number of attributes written (0 or 1). 325 */ 326 int writeEnclosingMethodAttribute(ClassSymbol c) { 327 return writeEnclosingMethodAttribute(names.EnclosingMethod, c); 328 } 329 330 /** Write the EnclosingMethod attribute with a specified name. 331 * Returns the number of attributes written (0 or 1). 332 */ 333 protected int writeEnclosingMethodAttribute(Name attributeName, ClassSymbol c) { 334 if (c.owner.kind != MTH && // neither a local class 335 c.name != names.empty) // nor anonymous 336 return 0; 337 338 int alenIdx = writeAttr(attributeName); 339 ClassSymbol enclClass = c.owner.enclClass(); 340 MethodSymbol enclMethod = 341 (c.owner.type == null // local to init block 342 || c.owner.kind != MTH) // or member init 343 ? null 344 : ((MethodSymbol)c.owner).originalEnclosingMethod(); 345 databuf.appendChar(poolWriter.putClass(enclClass)); 346 databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(enclMethod)); 347 endAttr(alenIdx); 348 return 1; 349 } 350 351 /** Write flag attributes; return number of attributes written. 352 */ 353 int writeFlagAttrs(long flags) { 354 int acount = 0; 355 if ((flags & DEPRECATED) != 0) { 356 int alenIdx = writeAttr(names.Deprecated); 357 endAttr(alenIdx); 358 acount++; 359 } 360 return acount; 361 } 362 363 /** Write member (field or method) attributes; 364 * return number of attributes written. 365 */ 366 int writeMemberAttrs(Symbol sym, boolean isRecordComponent) { 367 int acount = 0; 368 if (!isRecordComponent) { 369 acount = writeFlagAttrs(sym.flags()); 370 } 371 long flags = sym.flags(); 372 if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC && 373 (flags & ANONCONSTR) == 0 && 374 (!types.isSameType(sym.type, sym.erasure(types)) || 375 poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()))) { 376 // note that a local class with captured variables 377 // will get a signature attribute 378 int alenIdx = writeAttr(names.Signature); 379 databuf.appendChar(poolWriter.putSignature(sym)); 380 endAttr(alenIdx); 381 acount++; 382 } 383 acount += writeJavaAnnotations(sym.getRawAttributes()); 384 acount += writeTypeAnnotations(sym.getRawTypeAttributes(), false); 385 return acount; 386 } 387 388 /** 389 * Write method parameter names attribute. 390 */ 391 int writeMethodParametersAttr(MethodSymbol m, boolean writeParamNames) { 392 MethodType ty = m.externalType(types).asMethodType(); 393 final int allparams = ty.argtypes.size(); 394 if (m.params != null && allparams != 0) { 395 final int attrIndex = writeAttr(names.MethodParameters); 396 databuf.appendByte(allparams); 397 // Write extra parameters first 398 for (VarSymbol s : m.extraParams) { 399 final int flags = 400 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | 401 ((int) m.flags() & SYNTHETIC); 402 if (writeParamNames) 403 databuf.appendChar(poolWriter.putName(s.name)); 404 else 405 databuf.appendChar(0); 406 databuf.appendChar(flags); 407 } 408 // Now write the real parameters 409 for (VarSymbol s : m.params) { 410 final int flags = 411 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | 412 ((int) m.flags() & SYNTHETIC); 413 if (writeParamNames) 414 databuf.appendChar(poolWriter.putName(s.name)); 415 else 416 databuf.appendChar(0); 417 databuf.appendChar(flags); 418 } 419 // Now write the captured locals 420 for (VarSymbol s : m.capturedLocals) { 421 final int flags = 422 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | 423 ((int) m.flags() & SYNTHETIC); 424 if (writeParamNames) 425 databuf.appendChar(poolWriter.putName(s.name)); 426 else 427 databuf.appendChar(0); 428 databuf.appendChar(flags); 429 } 430 endAttr(attrIndex); 431 return 1; 432 } else 433 return 0; 434 } 435 436 private void writeParamAnnotations(List<VarSymbol> params, 437 RetentionPolicy retention) { 438 databuf.appendByte(params.length()); 439 for (VarSymbol s : params) { 440 ListBuffer<Attribute.Compound> buf = new ListBuffer<>(); 441 for (Attribute.Compound a : s.getRawAttributes()) 442 if (types.getRetention(a) == retention) 443 buf.append(a); 444 databuf.appendChar(buf.length()); 445 for (Attribute.Compound a : buf) 446 writeCompoundAttribute(a); 447 } 448 449 } 450 451 private void writeParamAnnotations(MethodSymbol m, 452 RetentionPolicy retention) { 453 databuf.appendByte(m.params.length()); 454 writeParamAnnotations(m.params, retention); 455 } 456 457 /** Write method parameter annotations; 458 * return number of attributes written. 459 */ 460 int writeParameterAttrs(List<VarSymbol> vars) { 461 boolean hasVisible = false; 462 boolean hasInvisible = false; 463 if (vars != null) { 464 for (VarSymbol s : vars) { 465 for (Attribute.Compound a : s.getRawAttributes()) { 466 switch (types.getRetention(a)) { 467 case SOURCE: break; 468 case CLASS: hasInvisible = true; break; 469 case RUNTIME: hasVisible = true; break; 470 default: // /* fail soft */ throw new AssertionError(vis); 471 } 472 } 473 } 474 } 475 476 int attrCount = 0; 477 if (hasVisible) { 478 int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations); 479 writeParamAnnotations(vars, RetentionPolicy.RUNTIME); 480 endAttr(attrIndex); 481 attrCount++; 482 } 483 if (hasInvisible) { 484 int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations); 485 writeParamAnnotations(vars, RetentionPolicy.CLASS); 486 endAttr(attrIndex); 487 attrCount++; 488 } 489 return attrCount; 490 } 491 492 /********************************************************************** 493 * Writing Java-language annotations (aka metadata, attributes) 494 **********************************************************************/ 495 496 /** Write Java-language annotations; return number of JVM 497 * attributes written (zero or one). 498 */ 499 int writeJavaAnnotations(List<Attribute.Compound> attrs) { 500 if (attrs.isEmpty()) return 0; 501 ListBuffer<Attribute.Compound> visibles = new ListBuffer<>(); 502 ListBuffer<Attribute.Compound> invisibles = new ListBuffer<>(); 503 for (Attribute.Compound a : attrs) { 504 switch (types.getRetention(a)) { 505 case SOURCE: break; 506 case CLASS: invisibles.append(a); break; 507 case RUNTIME: visibles.append(a); break; 508 default: // /* fail soft */ throw new AssertionError(vis); 509 } 510 } 511 512 int attrCount = 0; 513 if (visibles.length() != 0) { 514 int attrIndex = writeAttr(names.RuntimeVisibleAnnotations); 515 databuf.appendChar(visibles.length()); 516 for (Attribute.Compound a : visibles) 517 writeCompoundAttribute(a); 518 endAttr(attrIndex); 519 attrCount++; 520 } 521 if (invisibles.length() != 0) { 522 int attrIndex = writeAttr(names.RuntimeInvisibleAnnotations); 523 databuf.appendChar(invisibles.length()); 524 for (Attribute.Compound a : invisibles) 525 writeCompoundAttribute(a); 526 endAttr(attrIndex); 527 attrCount++; 528 } 529 return attrCount; 530 } 531 532 int writeTypeAnnotations(List<Attribute.TypeCompound> typeAnnos, boolean inCode) { 533 if (typeAnnos.isEmpty()) return 0; 534 535 ListBuffer<Attribute.TypeCompound> visibles = new ListBuffer<>(); 536 ListBuffer<Attribute.TypeCompound> invisibles = new ListBuffer<>(); 537 538 for (Attribute.TypeCompound tc : typeAnnos) { 539 if (tc.hasUnknownPosition()) { 540 boolean fixed = tc.tryFixPosition(); 541 542 // Could we fix it? 543 if (!fixed) { 544 // This happens for nested types like @A Outer. @B Inner. 545 // For method parameters we get the annotation twice! Once with 546 // a valid position, once unknown. 547 // TODO: find a cleaner solution. 548 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 549 pw.println("ClassWriter: Position UNKNOWN in type annotation: " + tc); 550 continue; 551 } 552 } 553 554 if (tc.position.type.isLocal() != inCode) 555 continue; 556 if (!tc.position.emitToClassfile()) 557 continue; 558 switch (types.getRetention(tc)) { 559 case SOURCE: break; 560 case CLASS: invisibles.append(tc); break; 561 case RUNTIME: visibles.append(tc); break; 562 default: // /* fail soft */ throw new AssertionError(vis); 563 } 564 } 565 566 int attrCount = 0; 567 if (visibles.length() != 0) { 568 int attrIndex = writeAttr(names.RuntimeVisibleTypeAnnotations); 569 databuf.appendChar(visibles.length()); 570 for (Attribute.TypeCompound p : visibles) 571 writeTypeAnnotation(p); 572 endAttr(attrIndex); 573 attrCount++; 574 } 575 576 if (invisibles.length() != 0) { 577 int attrIndex = writeAttr(names.RuntimeInvisibleTypeAnnotations); 578 databuf.appendChar(invisibles.length()); 579 for (Attribute.TypeCompound p : invisibles) 580 writeTypeAnnotation(p); 581 endAttr(attrIndex); 582 attrCount++; 583 } 584 585 return attrCount; 586 } 587 588 /** A visitor to write an attribute including its leading 589 * single-character marker. 590 */ 591 class AttributeWriter implements Attribute.Visitor { 592 public void visitConstant(Attribute.Constant _value) { 593 if (_value.type.getTag() == CLASS) { 594 Assert.check(_value.value instanceof String); 595 String s = (String)_value.value; 596 databuf.appendByte('s'); 597 databuf.appendChar(poolWriter.putName(names.fromString(s))); 598 } else { 599 switch (_value.type.getTag()) { 600 case BYTE: 601 databuf.appendByte('B'); 602 break; 603 case CHAR: 604 databuf.appendByte('C'); 605 break; 606 case SHORT: 607 databuf.appendByte('S'); 608 break; 609 case INT: 610 databuf.appendByte('I'); 611 break; 612 case LONG: 613 databuf.appendByte('J'); 614 break; 615 case FLOAT: 616 databuf.appendByte('F'); 617 break; 618 case DOUBLE: 619 databuf.appendByte('D'); 620 break; 621 case BOOLEAN: 622 databuf.appendByte('Z'); 623 break; 624 default: 625 throw new AssertionError(_value.type); 626 } 627 databuf.appendChar(poolWriter.putConstant(_value.value)); 628 } 629 } 630 public void visitEnum(Attribute.Enum e) { 631 databuf.appendByte('e'); 632 databuf.appendChar(poolWriter.putDescriptor(e.value.type)); 633 databuf.appendChar(poolWriter.putName(e.value.name)); 634 } 635 public void visitClass(Attribute.Class clazz) { 636 databuf.appendByte('c'); 637 databuf.appendChar(poolWriter.putDescriptor(clazz.classType)); 638 } 639 public void visitCompound(Attribute.Compound compound) { 640 databuf.appendByte('@'); 641 writeCompoundAttribute(compound); 642 } 643 public void visitError(Attribute.Error x) { 644 throw new AssertionError(x); 645 } 646 public void visitArray(Attribute.Array array) { 647 databuf.appendByte('['); 648 databuf.appendChar(array.values.length); 649 for (Attribute a : array.values) { 650 a.accept(this); 651 } 652 } 653 } 654 AttributeWriter awriter = new AttributeWriter(); 655 656 /** Write a compound attribute excluding the '@' marker. */ 657 void writeCompoundAttribute(Attribute.Compound c) { 658 databuf.appendChar(poolWriter.putDescriptor(c.type)); 659 databuf.appendChar(c.values.length()); 660 for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) { 661 databuf.appendChar(poolWriter.putName(p.fst.name)); 662 p.snd.accept(awriter); 663 } 664 } 665 666 void writeTypeAnnotation(Attribute.TypeCompound c) { 667 writePosition(c.position); 668 writeCompoundAttribute(c); 669 } 670 671 void writePosition(TypeAnnotationPosition p) { 672 databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte 673 switch (p.type) { 674 // instanceof 675 case INSTANCEOF: 676 // new expression 677 case NEW: 678 // constructor/method reference receiver 679 case CONSTRUCTOR_REFERENCE: 680 case METHOD_REFERENCE: 681 databuf.appendChar(p.offset); 682 break; 683 // local variable 684 case LOCAL_VARIABLE: 685 // resource variable 686 case RESOURCE_VARIABLE: 687 databuf.appendChar(p.lvarOffset.length); // for table length 688 for (int i = 0; i < p.lvarOffset.length; ++i) { 689 databuf.appendChar(p.lvarOffset[i]); 690 databuf.appendChar(p.lvarLength[i]); 691 databuf.appendChar(p.lvarIndex[i]); 692 } 693 break; 694 // exception parameter 695 case EXCEPTION_PARAMETER: 696 databuf.appendChar(p.getExceptionIndex()); 697 break; 698 // method receiver 699 case METHOD_RECEIVER: 700 // Do nothing 701 break; 702 // type parameter 703 case CLASS_TYPE_PARAMETER: 704 case METHOD_TYPE_PARAMETER: 705 databuf.appendByte(p.parameter_index); 706 break; 707 // type parameter bound 708 case CLASS_TYPE_PARAMETER_BOUND: 709 case METHOD_TYPE_PARAMETER_BOUND: 710 databuf.appendByte(p.parameter_index); 711 databuf.appendByte(p.bound_index); 712 break; 713 // class extends or implements clause 714 case CLASS_EXTENDS: 715 databuf.appendChar(p.type_index); 716 break; 717 // throws 718 case THROWS: 719 databuf.appendChar(p.type_index); 720 break; 721 // method parameter 722 case METHOD_FORMAL_PARAMETER: 723 databuf.appendByte(p.parameter_index); 724 break; 725 // type cast 726 case CAST: 727 // method/constructor/reference type argument 728 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 729 case METHOD_INVOCATION_TYPE_ARGUMENT: 730 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 731 case METHOD_REFERENCE_TYPE_ARGUMENT: 732 databuf.appendChar(p.offset); 733 databuf.appendByte(p.type_index); 734 break; 735 // We don't need to worry about these 736 case METHOD_RETURN: 737 case FIELD: 738 break; 739 case UNKNOWN: 740 throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!"); 741 default: 742 throw new AssertionError("jvm.ClassWriter: Unknown target type for position: " + p); 743 } 744 745 { // Append location data for generics/arrays. 746 databuf.appendByte(p.location.size()); 747 java.util.List<Integer> loc = TypeAnnotationPosition.getBinaryFromTypePath(p.location); 748 for (int i : loc) 749 databuf.appendByte((byte)i); 750 } 751 } 752 753 /********************************************************************** 754 * Writing module attributes 755 **********************************************************************/ 756 757 /** Write the Module attribute if needed. 758 * Returns the number of attributes written (0 or 1). 759 */ 760 int writeModuleAttribute(ClassSymbol c) { 761 ModuleSymbol m = (ModuleSymbol) c.owner; 762 763 int alenIdx = writeAttr(names.Module); 764 765 databuf.appendChar(poolWriter.putModule(m)); 766 databuf.appendChar(ModuleFlags.value(m.flags)); // module_flags 767 databuf.appendChar(m.version != null ? poolWriter.putName(m.version) : 0); 768 769 ListBuffer<RequiresDirective> requires = new ListBuffer<>(); 770 for (RequiresDirective r: m.requires) { 771 if (!r.flags.contains(RequiresFlag.EXTRA)) 772 requires.add(r); 773 } 774 databuf.appendChar(requires.size()); 775 for (RequiresDirective r: requires) { 776 databuf.appendChar(poolWriter.putModule(r.module)); 777 databuf.appendChar(RequiresFlag.value(r.flags)); 778 databuf.appendChar(r.module.version != null ? poolWriter.putName(r.module.version) : 0); 779 } 780 781 List<ExportsDirective> exports = m.exports; 782 databuf.appendChar(exports.size()); 783 for (ExportsDirective e: exports) { 784 databuf.appendChar(poolWriter.putPackage(e.packge)); 785 databuf.appendChar(ExportsFlag.value(e.flags)); 786 if (e.modules == null) { 787 databuf.appendChar(0); 788 } else { 789 databuf.appendChar(e.modules.size()); 790 for (ModuleSymbol msym: e.modules) { 791 databuf.appendChar(poolWriter.putModule(msym)); 792 } 793 } 794 } 795 796 List<OpensDirective> opens = m.opens; 797 databuf.appendChar(opens.size()); 798 for (OpensDirective o: opens) { 799 databuf.appendChar(poolWriter.putPackage(o.packge)); 800 databuf.appendChar(OpensFlag.value(o.flags)); 801 if (o.modules == null) { 802 databuf.appendChar(0); 803 } else { 804 databuf.appendChar(o.modules.size()); 805 for (ModuleSymbol msym: o.modules) { 806 databuf.appendChar(poolWriter.putModule(msym)); 807 } 808 } 809 } 810 811 List<UsesDirective> uses = m.uses; 812 databuf.appendChar(uses.size()); 813 for (UsesDirective s: uses) { 814 databuf.appendChar(poolWriter.putClass(s.service)); 815 } 816 817 // temporary fix to merge repeated provides clause for same service; 818 // eventually this should be disallowed when analyzing the module, 819 // so that each service type only appears once. 820 Map<ClassSymbol, Set<ClassSymbol>> mergedProvides = new LinkedHashMap<>(); 821 for (ProvidesDirective p : m.provides) { 822 mergedProvides.computeIfAbsent(p.service, s -> new LinkedHashSet<>()).addAll(p.impls); 823 } 824 databuf.appendChar(mergedProvides.size()); 825 mergedProvides.forEach((srvc, impls) -> { 826 databuf.appendChar(poolWriter.putClass(srvc)); 827 databuf.appendChar(impls.size()); 828 impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl))); 829 }); 830 831 endAttr(alenIdx); 832 return 1; 833 } 834 835 /********************************************************************** 836 * Writing Objects 837 **********************************************************************/ 838 839 /** Write "inner classes" attribute. 840 */ 841 void writeInnerClasses() { 842 int alenIdx = writeAttr(names.InnerClasses); 843 databuf.appendChar(poolWriter.innerClasses.size()); 844 for (ClassSymbol inner : poolWriter.innerClasses) { 845 inner.markAbstractIfNeeded(types); 846 int flags = adjustFlags(inner.flags_field); 847 if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT 848 if (dumpInnerClassModifiers) { 849 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 850 pw.println("INNERCLASS " + inner.name); 851 pw.println("---" + flagNames(flags)); 852 } 853 databuf.appendChar(poolWriter.putClass(inner)); 854 databuf.appendChar( 855 inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0); 856 databuf.appendChar( 857 !inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0); 858 databuf.appendChar(flags); 859 } 860 endAttr(alenIdx); 861 } 862 863 /** Write out "Preload" attribute by enumerating the value classes encountered in field/method descriptors during this compilation. 864 */ 865 void writePreloadAttribute() { 866 int alenIdx = writeAttr(names.Preload); 867 databuf.appendChar(poolWriter.preloadClasses.size()); 868 for (ClassSymbol c : poolWriter.preloadClasses) { 869 databuf.appendChar(poolWriter.putClass(c)); 870 } 871 endAttr(alenIdx); 872 } 873 874 int writeRecordAttribute(ClassSymbol csym) { 875 int alenIdx = writeAttr(names.Record); 876 Scope s = csym.members(); 877 databuf.appendChar(csym.getRecordComponents().size()); 878 for (VarSymbol v: csym.getRecordComponents()) { 879 //databuf.appendChar(poolWriter.putMember(v.accessor.head.snd)); 880 databuf.appendChar(poolWriter.putName(v.name)); 881 databuf.appendChar(poolWriter.putDescriptor(v)); 882 int acountIdx = beginAttrs(); 883 int acount = 0; 884 acount += writeMemberAttrs(v, true); 885 endAttrs(acountIdx, acount); 886 } 887 endAttr(alenIdx); 888 return 1; 889 } 890 891 /** 892 * Write NestMembers attribute (if needed) 893 */ 894 int writeNestMembersIfNeeded(ClassSymbol csym) { 895 ListBuffer<ClassSymbol> nested = new ListBuffer<>(); 896 listNested(csym, nested); 897 Set<ClassSymbol> nestedUnique = new LinkedHashSet<>(nested); 898 if (csym.owner.kind == PCK && !nestedUnique.isEmpty()) { 899 int alenIdx = writeAttr(names.NestMembers); 900 databuf.appendChar(nestedUnique.size()); 901 for (ClassSymbol s : nestedUnique) { 902 databuf.appendChar(poolWriter.putClass(s)); 903 } 904 endAttr(alenIdx); 905 return 1; 906 } 907 return 0; 908 } 909 910 /** 911 * Write NestHost attribute (if needed) 912 */ 913 int writeNestHostIfNeeded(ClassSymbol csym) { 914 if (csym.owner.kind != PCK) { 915 int alenIdx = writeAttr(names.NestHost); 916 databuf.appendChar(poolWriter.putClass(csym.outermostClass())); 917 endAttr(alenIdx); 918 return 1; 919 } 920 return 0; 921 } 922 923 private void listNested(Symbol sym, ListBuffer<ClassSymbol> seen) { 924 if (sym.kind != TYP) return; 925 ClassSymbol csym = (ClassSymbol)sym; 926 if (csym.owner.kind != PCK) { 927 seen.add(csym); 928 } 929 if (csym.members() != null) { 930 for (Symbol s : sym.members().getSymbols()) { 931 listNested(s, seen); 932 } 933 } 934 if (csym.trans_local != null) { 935 for (Symbol s : csym.trans_local) { 936 listNested(s, seen); 937 } 938 } 939 } 940 941 /** Write "PermittedSubclasses" attribute. 942 */ 943 int writePermittedSubclassesIfNeeded(ClassSymbol csym) { 944 if (csym.permitted.nonEmpty()) { 945 int alenIdx = writeAttr(names.PermittedSubclasses); 946 databuf.appendChar(csym.permitted.size()); 947 for (Symbol c : csym.permitted) { 948 databuf.appendChar(poolWriter.putClass((ClassSymbol) c)); 949 } 950 endAttr(alenIdx); 951 return 1; 952 } 953 return 0; 954 } 955 956 /** Write "bootstrapMethods" attribute. 957 */ 958 void writeBootstrapMethods() { 959 int alenIdx = writeAttr(names.BootstrapMethods); 960 int lastBootstrapMethods; 961 do { 962 lastBootstrapMethods = poolWriter.bootstrapMethods.size(); 963 for (BsmKey bsmKey : java.util.List.copyOf(poolWriter.bootstrapMethods.keySet())) { 964 for (LoadableConstant arg : bsmKey.staticArgs) { 965 poolWriter.putConstant(arg); 966 } 967 } 968 } while (lastBootstrapMethods < poolWriter.bootstrapMethods.size()); 969 databuf.appendChar(poolWriter.bootstrapMethods.size()); 970 for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) { 971 //write BSM handle 972 databuf.appendChar(poolWriter.putConstant(bsmKey.bsm)); 973 LoadableConstant[] uniqueArgs = bsmKey.staticArgs; 974 //write static args length 975 databuf.appendChar(uniqueArgs.length); 976 //write static args array 977 for (LoadableConstant arg : uniqueArgs) { 978 databuf.appendChar(poolWriter.putConstant(arg)); 979 } 980 } 981 endAttr(alenIdx); 982 } 983 984 /** Write field symbol, entering all references into constant pool. 985 */ 986 void writeField(VarSymbol v) { 987 int flags = adjustFlags(v.flags()); 988 databuf.appendChar(flags); 989 if (dumpFieldModifiers) { 990 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 991 pw.println("FIELD " + v.name); 992 pw.println("---" + flagNames(v.flags())); 993 } 994 databuf.appendChar(poolWriter.putName(v.name)); 995 databuf.appendChar(poolWriter.putDescriptor(v)); 996 Type fldType = v.erasure(types); 997 if (fldType.requiresPreload(v.owner)) { 998 poolWriter.enterPreloadClass((ClassSymbol) fldType.tsym); 999 } 1000 int acountIdx = beginAttrs(); 1001 int acount = 0; 1002 if (v.getConstValue() != null) { 1003 int alenIdx = writeAttr(names.ConstantValue); 1004 databuf.appendChar(poolWriter.putConstant(v.getConstValue())); 1005 endAttr(alenIdx); 1006 acount++; 1007 } 1008 acount += writeMemberAttrs(v, false); 1009 acount += writeExtraAttributes(v); 1010 endAttrs(acountIdx, acount); 1011 } 1012 1013 /** Write method symbol, entering all references into constant pool. 1014 */ 1015 void writeMethod(MethodSymbol m) { 1016 int flags = adjustFlags(m.flags()); 1017 databuf.appendChar(flags); 1018 if (dumpMethodModifiers) { 1019 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 1020 pw.println("METHOD " + m.name); 1021 pw.println("---" + flagNames(m.flags())); 1022 } 1023 databuf.appendChar(poolWriter.putName(m.name)); 1024 databuf.appendChar(poolWriter.putDescriptor(m)); 1025 MethodType mtype = (MethodType) m.externalType(types); 1026 for (Type t : mtype.getParameterTypes()) { 1027 if (t.requiresPreload(m.owner)) { 1028 poolWriter.enterPreloadClass((ClassSymbol) t.tsym); 1029 } 1030 } 1031 Type returnType = mtype.getReturnType(); 1032 if (returnType.requiresPreload(m.owner)) { 1033 poolWriter.enterPreloadClass((ClassSymbol) returnType.tsym); 1034 } 1035 int acountIdx = beginAttrs(); 1036 int acount = 0; 1037 if (m.code != null) { 1038 int alenIdx = writeAttr(names.Code); 1039 writeCode(m.code); 1040 m.code = null; // to conserve space 1041 endAttr(alenIdx); 1042 acount++; 1043 } 1044 List<Type> thrown = m.erasure(types).getThrownTypes(); 1045 if (thrown.nonEmpty()) { 1046 int alenIdx = writeAttr(names.Exceptions); 1047 databuf.appendChar(thrown.length()); 1048 for (List<Type> l = thrown; l.nonEmpty(); l = l.tail) 1049 databuf.appendChar(poolWriter.putClass(l.head)); 1050 endAttr(alenIdx); 1051 acount++; 1052 } 1053 if (m.defaultValue != null) { 1054 int alenIdx = writeAttr(names.AnnotationDefault); 1055 m.defaultValue.accept(awriter); 1056 endAttr(alenIdx); 1057 acount++; 1058 } 1059 if (target.hasMethodParameters()) { 1060 if (!m.isLambdaMethod()) { // Per JDK-8138729, do not emit parameters table for lambda bodies. 1061 boolean requiresParamNames = requiresParamNames(m); 1062 if (requiresParamNames || requiresParamFlags(m)) 1063 acount += writeMethodParametersAttr(m, requiresParamNames); 1064 } 1065 } 1066 acount += writeMemberAttrs(m, false); 1067 if (!m.isLambdaMethod()) 1068 acount += writeParameterAttrs(m.params); 1069 acount += writeExtraAttributes(m); 1070 endAttrs(acountIdx, acount); 1071 } 1072 1073 private boolean requiresParamNames(MethodSymbol m) { 1074 if (options.isSet(PARAMETERS)) 1075 return true; 1076 if ((m.isInitOrVNew() || m.isValueObjectFactory()) && (m.flags_field & RECORD) != 0) 1077 return true; 1078 return false; 1079 } 1080 1081 private boolean requiresParamFlags(MethodSymbol m) { 1082 if (!m.extraParams.isEmpty()) { 1083 return m.extraParams.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0); 1084 } 1085 if (m.params != null) { 1086 // parameter is stored in params for Enum#valueOf(name) 1087 return m.params.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0); 1088 } 1089 return false; 1090 } 1091 1092 /** Write code attribute of method. 1093 */ 1094 void writeCode(Code code) { 1095 databuf.appendChar(code.max_stack); 1096 databuf.appendChar(code.max_locals); 1097 databuf.appendInt(code.cp); 1098 databuf.appendBytes(code.code, 0, code.cp); 1099 databuf.appendChar(code.catchInfo.length()); 1100 for (List<char[]> l = code.catchInfo.toList(); 1101 l.nonEmpty(); 1102 l = l.tail) { 1103 for (int i = 0; i < l.head.length; i++) 1104 databuf.appendChar(l.head[i]); 1105 } 1106 int acountIdx = beginAttrs(); 1107 int acount = 0; 1108 1109 if (code.lineInfo.nonEmpty()) { 1110 int alenIdx = writeAttr(names.LineNumberTable); 1111 databuf.appendChar(code.lineInfo.length()); 1112 for (List<char[]> l = code.lineInfo.reverse(); 1113 l.nonEmpty(); 1114 l = l.tail) 1115 for (int i = 0; i < l.head.length; i++) 1116 databuf.appendChar(l.head[i]); 1117 endAttr(alenIdx); 1118 acount++; 1119 } 1120 1121 if (genCrt && (code.crt != null)) { 1122 CRTable crt = code.crt; 1123 int alenIdx = writeAttr(names.CharacterRangeTable); 1124 int crtIdx = beginAttrs(); 1125 int crtEntries = crt.writeCRT(databuf, code.lineMap, log); 1126 endAttrs(crtIdx, crtEntries); 1127 endAttr(alenIdx); 1128 acount++; 1129 } 1130 1131 // counter for number of generic local variables 1132 if (code.varDebugInfo && code.varBufferSize > 0) { 1133 int nGenericVars = 0; 1134 int alenIdx = writeAttr(names.LocalVariableTable); 1135 databuf.appendChar(code.getLVTSize()); 1136 for (int i=0; i<code.varBufferSize; i++) { 1137 Code.LocalVar var = code.varBuffer[i]; 1138 1139 for (Code.LocalVar.Range r: var.aliveRanges) { 1140 // write variable info 1141 Assert.check(r.start_pc >= 0 1142 && r.start_pc <= code.cp); 1143 databuf.appendChar(r.start_pc); 1144 Assert.check(r.length > 0 1145 && (r.start_pc + r.length) <= code.cp); 1146 databuf.appendChar(r.length); 1147 VarSymbol sym = var.sym; 1148 databuf.appendChar(poolWriter.putName(sym.name)); 1149 databuf.appendChar(poolWriter.putDescriptor(sym)); 1150 databuf.appendChar(var.reg); 1151 if (needsLocalVariableTypeEntry(var.sym.type)) { 1152 nGenericVars++; 1153 } 1154 } 1155 } 1156 endAttr(alenIdx); 1157 acount++; 1158 1159 if (nGenericVars > 0) { 1160 alenIdx = writeAttr(names.LocalVariableTypeTable); 1161 databuf.appendChar(nGenericVars); 1162 int count = 0; 1163 1164 for (int i=0; i<code.varBufferSize; i++) { 1165 Code.LocalVar var = code.varBuffer[i]; 1166 VarSymbol sym = var.sym; 1167 if (!needsLocalVariableTypeEntry(sym.type)) 1168 continue; 1169 for (Code.LocalVar.Range r : var.aliveRanges) { 1170 // write variable info 1171 databuf.appendChar(r.start_pc); 1172 databuf.appendChar(r.length); 1173 databuf.appendChar(poolWriter.putName(sym.name)); 1174 databuf.appendChar(poolWriter.putSignature(sym)); 1175 databuf.appendChar(var.reg); 1176 count++; 1177 } 1178 } 1179 Assert.check(count == nGenericVars); 1180 endAttr(alenIdx); 1181 acount++; 1182 } 1183 } 1184 1185 if (code.stackMapBufferSize > 0) { 1186 if (debugstackmap) System.out.println("Stack map for " + code.meth); 1187 int alenIdx = writeAttr(code.stackMap.getAttributeName(names)); 1188 writeStackMap(code); 1189 endAttr(alenIdx); 1190 acount++; 1191 } 1192 1193 acount += writeTypeAnnotations(code.meth.getRawTypeAttributes(), true); 1194 1195 endAttrs(acountIdx, acount); 1196 } 1197 //where 1198 private boolean needsLocalVariableTypeEntry(Type t) { 1199 //a local variable needs a type-entry if its type T is generic 1200 //(i.e. |T| != T) and if it's not an non-denotable type (non-denotable 1201 // types are not supported in signature attribute grammar!) 1202 return !types.isSameType(t, types.erasure(t)) && 1203 check.checkDenotable(t); 1204 } 1205 1206 void writeStackMap(Code code) { 1207 int nframes = code.stackMapBufferSize; 1208 if (debugstackmap) System.out.println(" nframes = " + nframes); 1209 databuf.appendChar(nframes); 1210 1211 switch (code.stackMap) { 1212 case CLDC: 1213 for (int i=0; i<nframes; i++) { 1214 if (debugstackmap) System.out.print(" " + i + ":"); 1215 Code.StackMapFrame frame = code.stackMapBuffer[i]; 1216 1217 // output PC 1218 if (debugstackmap) System.out.print(" pc=" + frame.pc); 1219 databuf.appendChar(frame.pc); 1220 1221 // output locals 1222 int localCount = 0; 1223 for (int j=0; j<frame.locals.length; 1224 j += Code.width(frame.locals[j])) { 1225 localCount++; 1226 } 1227 if (debugstackmap) System.out.print(" nlocals=" + 1228 localCount); 1229 databuf.appendChar(localCount); 1230 for (int j=0; j<frame.locals.length; 1231 j += Code.width(frame.locals[j])) { 1232 if (debugstackmap) System.out.print(" local[" + j + "]="); 1233 writeStackMapType(frame.locals[j]); 1234 } 1235 1236 // output stack 1237 int stackCount = 0; 1238 for (int j=0; j<frame.stack.length; 1239 j += Code.width(frame.stack[j])) { 1240 stackCount++; 1241 } 1242 if (debugstackmap) System.out.print(" nstack=" + 1243 stackCount); 1244 databuf.appendChar(stackCount); 1245 for (int j=0; j<frame.stack.length; 1246 j += Code.width(frame.stack[j])) { 1247 if (debugstackmap) System.out.print(" stack[" + j + "]="); 1248 writeStackMapType(frame.stack[j]); 1249 } 1250 if (debugstackmap) System.out.println(); 1251 } 1252 break; 1253 case JSR202: { 1254 Assert.checkNull(code.stackMapBuffer); 1255 for (int i=0; i<nframes; i++) { 1256 if (debugstackmap) System.out.print(" " + i + ":"); 1257 StackMapTableFrame frame = code.stackMapTableBuffer[i]; 1258 frame.write(this); 1259 if (debugstackmap) System.out.println(); 1260 } 1261 break; 1262 } 1263 default: 1264 throw new AssertionError("Unexpected stackmap format value"); 1265 } 1266 } 1267 1268 //where 1269 void writeStackMapType(Type t) { 1270 if (t == null) { 1271 if (debugstackmap) System.out.print("empty"); 1272 databuf.appendByte(0); 1273 } 1274 else switch(t.getTag()) { 1275 case BYTE: 1276 case CHAR: 1277 case SHORT: 1278 case INT: 1279 case BOOLEAN: 1280 if (debugstackmap) System.out.print("int"); 1281 databuf.appendByte(1); 1282 break; 1283 case FLOAT: 1284 if (debugstackmap) System.out.print("float"); 1285 databuf.appendByte(2); 1286 break; 1287 case DOUBLE: 1288 if (debugstackmap) System.out.print("double"); 1289 databuf.appendByte(3); 1290 break; 1291 case LONG: 1292 if (debugstackmap) System.out.print("long"); 1293 databuf.appendByte(4); 1294 break; 1295 case BOT: // null 1296 if (debugstackmap) System.out.print("null"); 1297 databuf.appendByte(5); 1298 break; 1299 case CLASS: 1300 case ARRAY: 1301 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")"); 1302 databuf.appendByte(7); 1303 databuf.appendChar(allowPrimitiveClasses && t.isPrimitiveClass() ? poolWriter.putClass(new ConstantPoolQType(types.erasure(t), types)) : poolWriter.putClass(types.erasure(t))); 1304 break; 1305 case TYPEVAR: 1306 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")"); 1307 databuf.appendByte(7); 1308 databuf.appendChar(poolWriter.putClass(types.erasure(t))); 1309 break; 1310 case UNINITIALIZED_THIS: 1311 if (debugstackmap) System.out.print("uninit_this"); 1312 databuf.appendByte(6); 1313 break; 1314 case UNINITIALIZED_OBJECT: 1315 { UninitializedType uninitType = (UninitializedType)t; 1316 databuf.appendByte(8); 1317 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset); 1318 databuf.appendChar(uninitType.offset); 1319 } 1320 break; 1321 default: 1322 throw new AssertionError(); 1323 } 1324 } 1325 1326 /** An entry in the JSR202 StackMapTable */ 1327 abstract static class StackMapTableFrame { 1328 abstract int getFrameType(); 1329 1330 void write(ClassWriter writer) { 1331 int frameType = getFrameType(); 1332 writer.databuf.appendByte(frameType); 1333 if (writer.debugstackmap) System.out.print(" frame_type=" + frameType); 1334 } 1335 1336 static class SameFrame extends StackMapTableFrame { 1337 final int offsetDelta; 1338 SameFrame(int offsetDelta) { 1339 this.offsetDelta = offsetDelta; 1340 } 1341 int getFrameType() { 1342 return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED; 1343 } 1344 @Override 1345 void write(ClassWriter writer) { 1346 super.write(writer); 1347 if (getFrameType() == SAME_FRAME_EXTENDED) { 1348 writer.databuf.appendChar(offsetDelta); 1349 if (writer.debugstackmap){ 1350 System.out.print(" offset_delta=" + offsetDelta); 1351 } 1352 } 1353 } 1354 } 1355 1356 static class SameLocals1StackItemFrame extends StackMapTableFrame { 1357 final int offsetDelta; 1358 final Type stack; 1359 SameLocals1StackItemFrame(int offsetDelta, Type stack) { 1360 this.offsetDelta = offsetDelta; 1361 this.stack = stack; 1362 } 1363 int getFrameType() { 1364 return (offsetDelta < SAME_FRAME_SIZE) ? 1365 (SAME_FRAME_SIZE + offsetDelta) : 1366 SAME_LOCALS_1_STACK_ITEM_EXTENDED; 1367 } 1368 @Override 1369 void write(ClassWriter writer) { 1370 super.write(writer); 1371 if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { 1372 writer.databuf.appendChar(offsetDelta); 1373 if (writer.debugstackmap) { 1374 System.out.print(" offset_delta=" + offsetDelta); 1375 } 1376 } 1377 if (writer.debugstackmap) { 1378 System.out.print(" stack[" + 0 + "]="); 1379 } 1380 writer.writeStackMapType(stack); 1381 } 1382 } 1383 1384 static class ChopFrame extends StackMapTableFrame { 1385 final int frameType; 1386 final int offsetDelta; 1387 ChopFrame(int frameType, int offsetDelta) { 1388 this.frameType = frameType; 1389 this.offsetDelta = offsetDelta; 1390 } 1391 int getFrameType() { return frameType; } 1392 @Override 1393 void write(ClassWriter writer) { 1394 super.write(writer); 1395 writer.databuf.appendChar(offsetDelta); 1396 if (writer.debugstackmap) { 1397 System.out.print(" offset_delta=" + offsetDelta); 1398 } 1399 } 1400 } 1401 1402 static class AppendFrame extends StackMapTableFrame { 1403 final int frameType; 1404 final int offsetDelta; 1405 final Type[] locals; 1406 AppendFrame(int frameType, int offsetDelta, Type[] locals) { 1407 this.frameType = frameType; 1408 this.offsetDelta = offsetDelta; 1409 this.locals = locals; 1410 } 1411 int getFrameType() { return frameType; } 1412 @Override 1413 void write(ClassWriter writer) { 1414 super.write(writer); 1415 writer.databuf.appendChar(offsetDelta); 1416 if (writer.debugstackmap) { 1417 System.out.print(" offset_delta=" + offsetDelta); 1418 } 1419 for (int i=0; i<locals.length; i++) { 1420 if (writer.debugstackmap) System.out.print(" locals[" + i + "]="); 1421 writer.writeStackMapType(locals[i]); 1422 } 1423 } 1424 } 1425 1426 static class FullFrame extends StackMapTableFrame { 1427 final int offsetDelta; 1428 final Type[] locals; 1429 final Type[] stack; 1430 FullFrame(int offsetDelta, Type[] locals, Type[] stack) { 1431 this.offsetDelta = offsetDelta; 1432 this.locals = locals; 1433 this.stack = stack; 1434 } 1435 int getFrameType() { return FULL_FRAME; } 1436 @Override 1437 void write(ClassWriter writer) { 1438 super.write(writer); 1439 writer.databuf.appendChar(offsetDelta); 1440 writer.databuf.appendChar(locals.length); 1441 if (writer.debugstackmap) { 1442 System.out.print(" offset_delta=" + offsetDelta); 1443 System.out.print(" nlocals=" + locals.length); 1444 } 1445 for (int i=0; i<locals.length; i++) { 1446 if (writer.debugstackmap) System.out.print(" locals[" + i + "]="); 1447 writer.writeStackMapType(locals[i]); 1448 } 1449 1450 writer.databuf.appendChar(stack.length); 1451 if (writer.debugstackmap) { System.out.print(" nstack=" + stack.length); } 1452 for (int i=0; i<stack.length; i++) { 1453 if (writer.debugstackmap) System.out.print(" stack[" + i + "]="); 1454 writer.writeStackMapType(stack[i]); 1455 } 1456 } 1457 } 1458 1459 /** Compare this frame with the previous frame and produce 1460 * an entry of compressed stack map frame. */ 1461 static StackMapTableFrame getInstance(Code.StackMapFrame this_frame, 1462 int prev_pc, 1463 Type[] prev_locals, 1464 Types types) { 1465 Type[] locals = this_frame.locals; 1466 Type[] stack = this_frame.stack; 1467 int offset_delta = this_frame.pc - prev_pc - 1; 1468 if (stack.length == 1) { 1469 if (locals.length == prev_locals.length 1470 && compare(prev_locals, locals, types) == 0) { 1471 return new SameLocals1StackItemFrame(offset_delta, stack[0]); 1472 } 1473 } else if (stack.length == 0) { 1474 int diff_length = compare(prev_locals, locals, types); 1475 if (diff_length == 0) { 1476 return new SameFrame(offset_delta); 1477 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) { 1478 // APPEND 1479 Type[] local_diff = new Type[-diff_length]; 1480 for (int i=prev_locals.length, j=0; i<locals.length; i++,j++) { 1481 local_diff[j] = locals[i]; 1482 } 1483 return new AppendFrame(SAME_FRAME_EXTENDED - diff_length, 1484 offset_delta, 1485 local_diff); 1486 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) { 1487 // CHOP 1488 return new ChopFrame(SAME_FRAME_EXTENDED - diff_length, 1489 offset_delta); 1490 } 1491 } 1492 // FULL_FRAME 1493 return new FullFrame(offset_delta, locals, stack); 1494 } 1495 1496 static boolean isInt(Type t) { 1497 return (t.getTag().isStrictSubRangeOf(INT) || t.hasTag(BOOLEAN)); 1498 } 1499 1500 static boolean isSameType(Type t1, Type t2, Types types) { 1501 if (t1 == null) { return t2 == null; } 1502 if (t2 == null) { return false; } 1503 1504 if (isInt(t1) && isInt(t2)) { return true; } 1505 1506 if (t1.hasTag(UNINITIALIZED_THIS)) { 1507 return t2.hasTag(UNINITIALIZED_THIS); 1508 } else if (t1.hasTag(UNINITIALIZED_OBJECT)) { 1509 if (t2.hasTag(UNINITIALIZED_OBJECT)) { 1510 return ((UninitializedType)t1).offset == ((UninitializedType)t2).offset; 1511 } else { 1512 return false; 1513 } 1514 } else if (t2.hasTag(UNINITIALIZED_THIS) || t2.hasTag(UNINITIALIZED_OBJECT)) { 1515 return false; 1516 } 1517 1518 return types.isSameType(t1, t2); 1519 } 1520 1521 static int compare(Type[] arr1, Type[] arr2, Types types) { 1522 int diff_length = arr1.length - arr2.length; 1523 if (diff_length > MAX_LOCAL_LENGTH_DIFF || diff_length < -MAX_LOCAL_LENGTH_DIFF) { 1524 return Integer.MAX_VALUE; 1525 } 1526 int len = (diff_length > 0) ? arr2.length : arr1.length; 1527 for (int i=0; i<len; i++) { 1528 if (!isSameType(arr1[i], arr2[i], types)) { 1529 return Integer.MAX_VALUE; 1530 } 1531 } 1532 return diff_length; 1533 } 1534 } 1535 1536 void writeFields(Scope s) { 1537 // process them in reverse sibling order; 1538 // i.e., process them in declaration order. 1539 List<VarSymbol> vars = List.nil(); 1540 for (Symbol sym : s.getSymbols(NON_RECURSIVE)) { 1541 if (sym.kind == VAR) vars = vars.prepend((VarSymbol)sym); 1542 } 1543 while (vars.nonEmpty()) { 1544 writeField(vars.head); 1545 vars = vars.tail; 1546 } 1547 } 1548 1549 void writeMethods(Scope s) { 1550 List<MethodSymbol> methods = List.nil(); 1551 for (Symbol sym : s.getSymbols(NON_RECURSIVE)) { 1552 if (sym.kind == MTH && (sym.flags() & HYPOTHETICAL) == 0) 1553 methods = methods.prepend((MethodSymbol)sym); 1554 } 1555 while (methods.nonEmpty()) { 1556 writeMethod(methods.head); 1557 methods = methods.tail; 1558 } 1559 } 1560 1561 /** Emit a class file for a given class. 1562 * @param c The class from which a class file is generated. 1563 */ 1564 public JavaFileObject writeClass(ClassSymbol c) 1565 throws IOException, PoolOverflow, StringOverflow 1566 { 1567 String name = (c.owner.kind == MDL ? c.name : c.flatname).toString(); 1568 Location outLocn; 1569 if (multiModuleMode) { 1570 ModuleSymbol msym = c.owner.kind == MDL ? (ModuleSymbol) c.owner : c.packge().modle; 1571 outLocn = fileManager.getLocationForModule(CLASS_OUTPUT, msym.name.toString()); 1572 } else { 1573 outLocn = CLASS_OUTPUT; 1574 } 1575 JavaFileObject outFile 1576 = fileManager.getJavaFileForOutput(outLocn, 1577 name, 1578 JavaFileObject.Kind.CLASS, 1579 c.sourcefile); 1580 OutputStream out = outFile.openOutputStream(); 1581 try { 1582 writeClassFile(out, c); 1583 if (verbose) 1584 log.printVerbose("wrote.file", outFile.getName()); 1585 out.close(); 1586 out = null; 1587 } catch (InvalidSignatureException ex) { 1588 log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type()))); 1589 } finally { 1590 if (out != null) { 1591 // if we are propagating an exception, delete the file 1592 out.close(); 1593 outFile.delete(); 1594 outFile = null; 1595 } 1596 } 1597 return outFile; // may be null if write failed 1598 } 1599 1600 /** Write class `c' to outstream `out'. 1601 */ 1602 public void writeClassFile(OutputStream out, ClassSymbol c) 1603 throws IOException, PoolOverflow, StringOverflow { 1604 Assert.check((c.flags() & COMPOUND) == 0); 1605 databuf.reset(); 1606 poolbuf.reset(); 1607 1608 Type supertype = types.supertype(c.type); 1609 List<Type> interfaces = types.interfaces(c.type); 1610 List<Type> typarams = c.type.getTypeArguments(); 1611 1612 int flags; 1613 if (c.owner.kind == MDL) { 1614 flags = ACC_MODULE; 1615 } else { 1616 flags = adjustFlags(c.flags() & ~(DEFAULT | STRICTFP)); 1617 if ((flags & PROTECTED) != 0) flags |= PUBLIC; 1618 flags = flags & AdjustedClassFlags; 1619 } 1620 1621 if (dumpClassModifiers) { 1622 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 1623 pw.println(); 1624 pw.println("CLASSFILE " + c.getQualifiedName()); 1625 pw.println("---" + flagNames(flags)); 1626 } 1627 databuf.appendChar(flags); 1628 1629 if (c.owner.kind == MDL) { 1630 PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage; 1631 databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed))); 1632 } else { 1633 databuf.appendChar(poolWriter.putClass(c)); 1634 } 1635 databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0); 1636 databuf.appendChar(interfaces.length()); 1637 for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail) 1638 databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym)); 1639 int fieldsCount = 0; 1640 int methodsCount = 0; 1641 for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) { 1642 switch (sym.kind) { 1643 case VAR: fieldsCount++; break; 1644 case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++; 1645 break; 1646 case TYP: poolWriter.enterInnerClass((ClassSymbol)sym); break; 1647 default : Assert.error(); 1648 } 1649 } 1650 1651 if (c.trans_local != null) { 1652 for (ClassSymbol local : c.trans_local) { 1653 poolWriter.enterInnerClass(local); 1654 } 1655 } 1656 1657 databuf.appendChar(fieldsCount); 1658 writeFields(c.members()); 1659 databuf.appendChar(methodsCount); 1660 writeMethods(c.members()); 1661 1662 int acountIdx = beginAttrs(); 1663 int acount = 0; 1664 1665 boolean sigReq = 1666 typarams.length() != 0 || supertype.allparams().length() != 0; 1667 for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail) 1668 sigReq = l.head.allparams().length() != 0; 1669 if (sigReq) { 1670 int alenIdx = writeAttr(names.Signature); 1671 databuf.appendChar(poolWriter.putSignature(c)); 1672 endAttr(alenIdx); 1673 acount++; 1674 } 1675 1676 if (c.sourcefile != null && emitSourceFile) { 1677 int alenIdx = writeAttr(names.SourceFile); 1678 // WHM 6/29/1999: Strip file path prefix. We do it here at 1679 // the last possible moment because the sourcefile may be used 1680 // elsewhere in error diagnostics. Fixes 4241573. 1681 String simpleName = PathFileObject.getSimpleName(c.sourcefile); 1682 databuf.appendChar(poolWriter.putName(names.fromString(simpleName))); 1683 endAttr(alenIdx); 1684 acount++; 1685 } 1686 1687 if (genCrt) { 1688 // Append SourceID attribute 1689 int alenIdx = writeAttr(names.SourceID); 1690 databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(getLastModified(c.sourcefile))))); 1691 endAttr(alenIdx); 1692 acount++; 1693 // Append CompilationID attribute 1694 alenIdx = writeAttr(names.CompilationID); 1695 databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis())))); 1696 endAttr(alenIdx); 1697 acount++; 1698 } 1699 1700 acount += writeFlagAttrs(c.flags()); 1701 acount += writeJavaAnnotations(c.getRawAttributes()); 1702 acount += writeTypeAnnotations(c.getRawTypeAttributes(), false); 1703 acount += writeEnclosingMethodAttribute(c); 1704 if (c.owner.kind == MDL) { 1705 acount += writeModuleAttribute(c); 1706 acount += writeFlagAttrs(c.owner.flags() & ~DEPRECATED); 1707 } 1708 acount += writeExtraClassAttributes(c); 1709 acount += writeExtraAttributes(c); 1710 1711 poolbuf.appendInt(JAVA_MAGIC); 1712 if (preview.isEnabled() && preview.usesPreview(c.sourcefile)) { 1713 poolbuf.appendChar(ClassFile.PREVIEW_MINOR_VERSION); 1714 } else { 1715 poolbuf.appendChar(target.minorVersion); 1716 } 1717 poolbuf.appendChar(target.majorVersion); 1718 1719 if (c.owner.kind != MDL) { 1720 if (target.hasNestmateAccess()) { 1721 acount += writeNestMembersIfNeeded(c); 1722 acount += writeNestHostIfNeeded(c); 1723 } 1724 } 1725 1726 if (c.isRecord()) { 1727 acount += writeRecordAttribute(c); 1728 } 1729 1730 if (target.hasSealedClasses()) { 1731 acount += writePermittedSubclassesIfNeeded(c); 1732 } 1733 1734 if (!poolWriter.bootstrapMethods.isEmpty()) { 1735 writeBootstrapMethods(); 1736 acount++; 1737 } 1738 1739 if (!poolWriter.innerClasses.isEmpty()) { 1740 writeInnerClasses(); 1741 acount++; 1742 } 1743 1744 if (!poolWriter.preloadClasses.isEmpty()) { 1745 writePreloadAttribute(); 1746 acount++; 1747 } 1748 1749 endAttrs(acountIdx, acount); 1750 1751 out.write(poolbuf.elems, 0, poolbuf.length); 1752 1753 poolWriter.writePool(out); 1754 poolWriter.reset(); // to save space 1755 1756 out.write(databuf.elems, 0, databuf.length); 1757 } 1758 1759 /**Allows subclasses to write additional class attributes 1760 * 1761 * @return the number of attributes written 1762 */ 1763 protected int writeExtraClassAttributes(ClassSymbol c) { 1764 return 0; 1765 } 1766 1767 /**Allows friends to write additional attributes 1768 * 1769 * @return the number of attributes written 1770 */ 1771 protected int writeExtraAttributes(Symbol sym) { 1772 int i = 0; 1773 for (ToIntFunction<Symbol> hook : extraAttributeHooks) { 1774 i += hook.applyAsInt(sym); 1775 } 1776 return i; 1777 } 1778 1779 int adjustFlags(final long flags) { 1780 int result = (int)flags; 1781 1782 // Elide strictfp bit in class files 1783 if (target.obsoleteAccStrict()) 1784 result &= ~STRICTFP; 1785 1786 if ((flags & BRIDGE) != 0) 1787 result |= ACC_BRIDGE; 1788 if ((flags & VARARGS) != 0) 1789 result |= ACC_VARARGS; 1790 if ((flags & DEFAULT) != 0) 1791 result &= ~ABSTRACT; 1792 if ((flags & PRIMITIVE_CLASS) != 0) 1793 result |= ACC_PRIMITIVE; 1794 if ((flags & VALUE_CLASS) != 0) 1795 result |= ACC_VALUE; 1796 if ((flags & IDENTITY_TYPE) != 0) 1797 result |= ACC_IDENTITY; 1798 return result; 1799 } 1800 1801 long getLastModified(FileObject filename) { 1802 long mod = 0; 1803 try { 1804 mod = filename.getLastModified(); 1805 } catch (SecurityException e) { 1806 throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage()); 1807 } 1808 return mod; 1809 } 1810 }