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