1 /* 2 * Copyright (c) 1999, 2024, 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 SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; 150 static final int SAME_FRAME_EXTENDED = 251; 151 static final int FULL_FRAME = 255; 152 static final int MAX_LOCAL_LENGTH_DIFF = 4; 153 154 /** Get the ClassWriter instance for this context. */ 155 public static ClassWriter instance(Context context) { 156 ClassWriter instance = context.get(classWriterKey); 157 if (instance == null) 158 instance = new ClassWriter(context); 159 return instance; 160 } 161 162 /** Construct a class writer, given an options table. 163 */ 164 @SuppressWarnings("this-escape") 165 protected ClassWriter(Context context) { 166 context.put(classWriterKey, this); 167 168 log = Log.instance(context); 169 names = Names.instance(context); 170 options = Options.instance(context); 171 preview = Preview.instance(context); 172 target = Target.instance(context); 173 source = Source.instance(context); 174 types = Types.instance(context); 175 check = Check.instance(context); 176 fileManager = context.get(JavaFileManager.class); 177 poolWriter = Gen.instance(context).poolWriter; 178 179 verbose = options.isSet(VERBOSE); 180 genCrt = options.isSet(XJCOV); 181 debugstackmap = options.isSet("debug.stackmap"); 182 183 emitSourceFile = options.isUnset(G_CUSTOM) || 184 options.isSet(G_CUSTOM, "source"); 185 186 String modifierFlags = options.get("debug.dumpmodifiers"); 187 if (modifierFlags != null) { 188 dumpClassModifiers = modifierFlags.indexOf('c') != -1; 189 dumpFieldModifiers = modifierFlags.indexOf('f') != -1; 190 dumpInnerClassModifiers = modifierFlags.indexOf('i') != -1; 191 dumpMethodModifiers = modifierFlags.indexOf('m') != -1; 192 } 193 } 194 195 public void addExtraAttributes(ToIntFunction<Symbol> addExtraAttributes) { 196 extraAttributeHooks = extraAttributeHooks.prepend(addExtraAttributes); 197 } 198 199 /* **************************************************************** 200 * Diagnostics: dump generated class names and modifiers 201 ******************************************************************/ 202 203 /** Value of option 'dumpmodifiers' is a string 204 * indicating which modifiers should be dumped for debugging: 205 * 'c' -- classes 206 * 'f' -- fields 207 * 'i' -- innerclass attributes 208 * 'm' -- methods 209 * For example, to dump everything: 210 * javac -XDdumpmodifiers=cifm MyProg.java 211 */ 212 private boolean dumpClassModifiers; // -XDdumpmodifiers=c 213 private boolean dumpFieldModifiers; // -XDdumpmodifiers=f 214 private boolean dumpInnerClassModifiers; // -XDdumpmodifiers=i 215 private boolean dumpMethodModifiers; // -XDdumpmodifiers=m 216 217 218 /** Return flags as a string, separated by " ". 219 */ 220 public static String flagNames(long flags) { 221 StringBuilder sbuf = new StringBuilder(); 222 int i = 0; 223 long f = flags & StandardFlags; 224 while (f != 0) { 225 if ((f & 1) != 0 && flagName[i] != "") { 226 sbuf.append(" "); 227 sbuf.append(flagName[i]); 228 } 229 f = f >> 1; 230 i++; 231 } 232 return sbuf.toString(); 233 } 234 //where 235 private static final String[] flagName = { 236 "PUBLIC", "PRIVATE", "PROTECTED", "STATIC", "FINAL", 237 // the empty position should be for synchronized but right now we don't have any test checking it 238 "", "VOLATILE", "TRANSIENT", "NATIVE", "INTERFACE", 239 "ABSTRACT", "STRICTFP"}; 240 241 /* **************************************************************** 242 * Output routines 243 ******************************************************************/ 244 245 /** Write a character into given byte buffer; 246 * byte buffer will not be grown. 247 */ 248 void putChar(ByteBuffer buf, int op, int x) { 249 buf.elems[op ] = (byte)((x >> 8) & 0xFF); 250 buf.elems[op+1] = (byte)((x ) & 0xFF); 251 } 252 253 /** Write an integer into given byte buffer; 254 * byte buffer will not be grown. 255 */ 256 void putInt(ByteBuffer buf, int adr, int x) { 257 buf.elems[adr ] = (byte)((x >> 24) & 0xFF); 258 buf.elems[adr+1] = (byte)((x >> 16) & 0xFF); 259 buf.elems[adr+2] = (byte)((x >> 8) & 0xFF); 260 buf.elems[adr+3] = (byte)((x ) & 0xFF); 261 } 262 263 /* **************************************************************** 264 * Writing the Constant Pool 265 ******************************************************************/ 266 267 /** Thrown when the constant pool is over full. 268 */ 269 public static class PoolOverflow extends RuntimeException { 270 private static final long serialVersionUID = 0; 271 public PoolOverflow() {} 272 } 273 public static class StringOverflow extends RuntimeException { 274 private static final long serialVersionUID = 0; 275 public final String value; 276 public StringOverflow(String s) { 277 value = s; 278 } 279 } 280 281 /* **************************************************************** 282 * Writing Attributes 283 ******************************************************************/ 284 285 /** Write header for an attribute to data buffer and return 286 * position past attribute length index. 287 */ 288 public int writeAttr(Name attrName) { 289 int index = poolWriter.putName(attrName); 290 databuf.appendChar(index); 291 databuf.appendInt(0); 292 return databuf.length; 293 } 294 295 /** Fill in attribute length. 296 */ 297 public void endAttr(int index) { 298 putInt(databuf, index - 4, databuf.length - index); 299 } 300 301 /** Leave space for attribute count and return index for 302 * number of attributes field. 303 */ 304 int beginAttrs() { 305 databuf.appendChar(0); 306 return databuf.length; 307 } 308 309 /** Fill in number of attributes. 310 */ 311 void endAttrs(int index, int count) { 312 putChar(databuf, index - 2, count); 313 } 314 315 /** Write the EnclosingMethod attribute if needed. 316 * Returns the number of attributes written (0 or 1). 317 */ 318 int writeEnclosingMethodAttribute(ClassSymbol c) { 319 return writeEnclosingMethodAttribute(names.EnclosingMethod, c); 320 } 321 322 /** Write the EnclosingMethod attribute with a specified name. 323 * Returns the number of attributes written (0 or 1). 324 */ 325 protected int writeEnclosingMethodAttribute(Name attributeName, ClassSymbol c) { 326 if (c.owner.kind != MTH && // neither a local class 327 c.name != names.empty) // nor anonymous 328 return 0; 329 330 int alenIdx = writeAttr(attributeName); 331 ClassSymbol enclClass = c.owner.enclClass(); 332 MethodSymbol enclMethod = 333 ((c.owner.flags() & BLOCK) != 0 // local to init block 334 || c.owner.kind != MTH) // or member init 335 ? null 336 : ((MethodSymbol)c.owner).originalEnclosingMethod(); 337 databuf.appendChar(poolWriter.putClass(enclClass)); 338 databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(enclMethod)); 339 endAttr(alenIdx); 340 return 1; 341 } 342 343 /** Write flag attributes; return number of attributes written. 344 */ 345 int writeFlagAttrs(long flags) { 346 int acount = 0; 347 if ((flags & DEPRECATED) != 0) { 348 int alenIdx = writeAttr(names.Deprecated); 349 endAttr(alenIdx); 350 acount++; 351 } 352 return acount; 353 } 354 355 /** Write member (field or method) attributes; 356 * return number of attributes written. 357 */ 358 int writeMemberAttrs(Symbol sym, boolean isRecordComponent) { 359 int acount = 0; 360 if (!isRecordComponent) { 361 acount = writeFlagAttrs(sym.flags()); 362 } 363 long flags = sym.flags(); 364 if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC && 365 (flags & ANONCONSTR) == 0 && 366 (!types.isSameType(sym.type, sym.erasure(types)) || 367 poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()))) { 368 // note that a local class with captured variables 369 // will get a signature attribute 370 int alenIdx = writeAttr(names.Signature); 371 databuf.appendChar(poolWriter.putSignature(sym)); 372 endAttr(alenIdx); 373 acount++; 374 } 375 acount += writeJavaAnnotations(sym.getRawAttributes()); 376 acount += writeTypeAnnotations(sym.getRawTypeAttributes(), false); 377 return acount; 378 } 379 380 /** 381 * Write method parameter names attribute. 382 */ 383 int writeMethodParametersAttr(MethodSymbol m, boolean writeParamNames) { 384 MethodType ty = m.externalType(types).asMethodType(); 385 final int allparams = ty.argtypes.size(); 386 if (m.params != null && allparams != 0) { 387 final int attrIndex = writeAttr(names.MethodParameters); 388 databuf.appendByte(allparams); 389 // Write extra parameters first 390 for (VarSymbol s : m.extraParams) { 391 final int flags = 392 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | 393 ((int) m.flags() & SYNTHETIC); 394 if (writeParamNames) 395 databuf.appendChar(poolWriter.putName(s.name)); 396 else 397 databuf.appendChar(0); 398 databuf.appendChar(flags); 399 } 400 // Now write the real parameters 401 for (VarSymbol s : m.params) { 402 final int flags = 403 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | 404 ((int) m.flags() & SYNTHETIC); 405 if (writeParamNames) 406 databuf.appendChar(poolWriter.putName(s.name)); 407 else 408 databuf.appendChar(0); 409 databuf.appendChar(flags); 410 } 411 // Now write the captured locals 412 for (VarSymbol s : m.capturedLocals) { 413 final int flags = 414 ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | 415 ((int) m.flags() & SYNTHETIC); 416 if (writeParamNames) 417 databuf.appendChar(poolWriter.putName(s.name)); 418 else 419 databuf.appendChar(0); 420 databuf.appendChar(flags); 421 } 422 endAttr(attrIndex); 423 return 1; 424 } else 425 return 0; 426 } 427 428 private void writeParamAnnotations(List<VarSymbol> params, 429 RetentionPolicy retention) { 430 databuf.appendByte(params.length()); 431 for (VarSymbol s : params) { 432 ListBuffer<Attribute.Compound> buf = new ListBuffer<>(); 433 for (Attribute.Compound a : s.getRawAttributes()) 434 if (types.getRetention(a) == retention) 435 buf.append(a); 436 databuf.appendChar(buf.length()); 437 for (Attribute.Compound a : buf) 438 writeCompoundAttribute(a); 439 } 440 441 } 442 443 private void writeParamAnnotations(MethodSymbol m, 444 RetentionPolicy retention) { 445 databuf.appendByte(m.params.length()); 446 writeParamAnnotations(m.params, retention); 447 } 448 449 /** Write method parameter annotations; 450 * return number of attributes written. 451 */ 452 int writeParameterAttrs(List<VarSymbol> vars) { 453 boolean hasVisible = false; 454 boolean hasInvisible = false; 455 if (vars != null) { 456 for (VarSymbol s : vars) { 457 for (Attribute.Compound a : s.getRawAttributes()) { 458 switch (types.getRetention(a)) { 459 case SOURCE: break; 460 case CLASS: hasInvisible = true; break; 461 case RUNTIME: hasVisible = true; break; 462 default: // /* fail soft */ throw new AssertionError(vis); 463 } 464 } 465 } 466 } 467 468 int attrCount = 0; 469 if (hasVisible) { 470 int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations); 471 writeParamAnnotations(vars, RetentionPolicy.RUNTIME); 472 endAttr(attrIndex); 473 attrCount++; 474 } 475 if (hasInvisible) { 476 int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations); 477 writeParamAnnotations(vars, RetentionPolicy.CLASS); 478 endAttr(attrIndex); 479 attrCount++; 480 } 481 return attrCount; 482 } 483 484 /* ******************************************************************** 485 * Writing Java-language annotations (aka metadata, attributes) 486 **********************************************************************/ 487 488 /** Write Java-language annotations; return number of JVM 489 * attributes written (zero or one). 490 */ 491 int writeJavaAnnotations(List<Attribute.Compound> attrs) { 492 if (attrs.isEmpty()) return 0; 493 ListBuffer<Attribute.Compound> visibles = new ListBuffer<>(); 494 ListBuffer<Attribute.Compound> invisibles = new ListBuffer<>(); 495 for (Attribute.Compound a : attrs) { 496 switch (types.getRetention(a)) { 497 case SOURCE: break; 498 case CLASS: invisibles.append(a); break; 499 case RUNTIME: visibles.append(a); break; 500 default: // /* fail soft */ throw new AssertionError(vis); 501 } 502 } 503 504 int attrCount = 0; 505 if (visibles.length() != 0) { 506 int attrIndex = writeAttr(names.RuntimeVisibleAnnotations); 507 databuf.appendChar(visibles.length()); 508 for (Attribute.Compound a : visibles) 509 writeCompoundAttribute(a); 510 endAttr(attrIndex); 511 attrCount++; 512 } 513 if (invisibles.length() != 0) { 514 int attrIndex = writeAttr(names.RuntimeInvisibleAnnotations); 515 databuf.appendChar(invisibles.length()); 516 for (Attribute.Compound a : invisibles) 517 writeCompoundAttribute(a); 518 endAttr(attrIndex); 519 attrCount++; 520 } 521 return attrCount; 522 } 523 524 int writeTypeAnnotations(List<Attribute.TypeCompound> typeAnnos, boolean inCode) { 525 if (typeAnnos.isEmpty()) return 0; 526 527 ListBuffer<Attribute.TypeCompound> visibles = new ListBuffer<>(); 528 ListBuffer<Attribute.TypeCompound> invisibles = new ListBuffer<>(); 529 530 for (Attribute.TypeCompound tc : typeAnnos) { 531 if (tc.hasUnknownPosition()) { 532 boolean fixed = tc.tryFixPosition(); 533 534 // Could we fix it? 535 if (!fixed) { 536 // This happens for nested types like @A Outer. @B Inner. 537 // For method parameters we get the annotation twice! Once with 538 // a valid position, once unknown. 539 // TODO: find a cleaner solution. 540 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 541 pw.println("ClassWriter: Position UNKNOWN in type annotation: " + tc); 542 continue; 543 } 544 } 545 546 if (tc.position.type.isLocal() != inCode) 547 continue; 548 if (!tc.position.emitToClassfile()) 549 continue; 550 switch (types.getRetention(tc)) { 551 case SOURCE: break; 552 case CLASS: invisibles.append(tc); break; 553 case RUNTIME: visibles.append(tc); break; 554 default: // /* fail soft */ throw new AssertionError(vis); 555 } 556 } 557 558 int attrCount = 0; 559 if (visibles.length() != 0) { 560 int attrIndex = writeAttr(names.RuntimeVisibleTypeAnnotations); 561 databuf.appendChar(visibles.length()); 562 for (Attribute.TypeCompound p : visibles) 563 writeTypeAnnotation(p); 564 endAttr(attrIndex); 565 attrCount++; 566 } 567 568 if (invisibles.length() != 0) { 569 int attrIndex = writeAttr(names.RuntimeInvisibleTypeAnnotations); 570 databuf.appendChar(invisibles.length()); 571 for (Attribute.TypeCompound p : invisibles) 572 writeTypeAnnotation(p); 573 endAttr(attrIndex); 574 attrCount++; 575 } 576 577 return attrCount; 578 } 579 580 /** A visitor to write an attribute including its leading 581 * single-character marker. 582 */ 583 class AttributeWriter implements Attribute.Visitor { 584 public void visitConstant(Attribute.Constant _value) { 585 if (_value.type.getTag() == CLASS) { 586 Assert.check(_value.value instanceof String); 587 String s = (String)_value.value; 588 databuf.appendByte('s'); 589 databuf.appendChar(poolWriter.putName(names.fromString(s))); 590 } else { 591 switch (_value.type.getTag()) { 592 case BYTE: 593 databuf.appendByte('B'); 594 break; 595 case CHAR: 596 databuf.appendByte('C'); 597 break; 598 case SHORT: 599 databuf.appendByte('S'); 600 break; 601 case INT: 602 databuf.appendByte('I'); 603 break; 604 case LONG: 605 databuf.appendByte('J'); 606 break; 607 case FLOAT: 608 databuf.appendByte('F'); 609 break; 610 case DOUBLE: 611 databuf.appendByte('D'); 612 break; 613 case BOOLEAN: 614 databuf.appendByte('Z'); 615 break; 616 default: 617 throw new AssertionError(_value.type); 618 } 619 databuf.appendChar(poolWriter.putConstant(_value.value)); 620 } 621 } 622 public void visitEnum(Attribute.Enum e) { 623 databuf.appendByte('e'); 624 databuf.appendChar(poolWriter.putDescriptor(e.value.type)); 625 databuf.appendChar(poolWriter.putName(e.value.name)); 626 } 627 public void visitClass(Attribute.Class clazz) { 628 databuf.appendByte('c'); 629 databuf.appendChar(poolWriter.putDescriptor(clazz.classType)); 630 } 631 public void visitCompound(Attribute.Compound compound) { 632 databuf.appendByte('@'); 633 writeCompoundAttribute(compound); 634 } 635 public void visitError(Attribute.Error x) { 636 throw new AssertionError(x); 637 } 638 public void visitArray(Attribute.Array array) { 639 databuf.appendByte('['); 640 databuf.appendChar(array.values.length); 641 for (Attribute a : array.values) { 642 a.accept(this); 643 } 644 } 645 } 646 AttributeWriter awriter = new AttributeWriter(); 647 648 /** Write a compound attribute excluding the '@' marker. */ 649 void writeCompoundAttribute(Attribute.Compound c) { 650 databuf.appendChar(poolWriter.putDescriptor(c.type)); 651 databuf.appendChar(c.values.length()); 652 for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) { 653 checkAnnotationArraySizeInternal(p); 654 databuf.appendChar(poolWriter.putName(p.fst.name)); 655 p.snd.accept(awriter); 656 } 657 } 658 659 private void checkAnnotationArraySizeInternal(Pair<Symbol.MethodSymbol, Attribute> p) { 660 if (p.snd instanceof Attribute.Array arrAttr && 661 arrAttr.values.length > ClassFile.MAX_ANNOTATIONS) { 662 log.error(Errors.AnnotationArrayTooLarge(p.fst.owner)); 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, 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 "LoadableDescriptors" attribute by enumerating the value classes encountered in field/method descriptors during this compilation. 864 */ 865 void writeLoadableDescriptorsAttribute() { 866 int alenIdx = writeAttr(names.LoadableDescriptors); 867 databuf.appendChar(poolWriter.loadableDescriptors.size()); 868 for (Symbol c : poolWriter.loadableDescriptors) { 869 databuf.appendChar(poolWriter.putDescriptor(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.getPermittedSubclasses().nonEmpty()) { 945 int alenIdx = writeAttr(names.PermittedSubclasses); 946 databuf.appendChar(csym.getPermittedSubclasses().size()); 947 for (Type t : csym.getPermittedSubclasses()) { 948 databuf.appendChar(poolWriter.putClass((ClassSymbol) t.tsym)); 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, 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.requiresLoadableDescriptors(v.owner)) { 998 poolWriter.enterLoadableDescriptorsClass(fldType.tsym); 999 if (preview.isPreview(Source.Feature.VALUE_CLASSES)) { 1000 preview.markUsesPreview(null); 1001 } 1002 } 1003 int acountIdx = beginAttrs(); 1004 int acount = 0; 1005 if (v.getConstValue() != null) { 1006 int alenIdx = writeAttr(names.ConstantValue); 1007 databuf.appendChar(poolWriter.putConstant(v.getConstValue())); 1008 endAttr(alenIdx); 1009 acount++; 1010 } 1011 acount += writeMemberAttrs(v, false); 1012 acount += writeExtraAttributes(v); 1013 endAttrs(acountIdx, acount); 1014 } 1015 1016 /** Write method symbol, entering all references into constant pool. 1017 */ 1018 void writeMethod(MethodSymbol m) { 1019 int flags = adjustFlags(m, m.flags()); 1020 databuf.appendChar(flags); 1021 if (dumpMethodModifiers) { 1022 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 1023 pw.println("METHOD " + m.name); 1024 pw.println("---" + flagNames(m.flags())); 1025 } 1026 databuf.appendChar(poolWriter.putName(m.name)); 1027 databuf.appendChar(poolWriter.putDescriptor(m)); 1028 MethodType mtype = (MethodType) m.externalType(types); 1029 for (Type t : mtype.getParameterTypes()) { 1030 if (t.requiresLoadableDescriptors(m.owner)) { 1031 poolWriter.enterLoadableDescriptorsClass(t.tsym); 1032 if (preview.isPreview(Source.Feature.VALUE_CLASSES)) { 1033 preview.markUsesPreview(null); 1034 } 1035 } 1036 } 1037 Type returnType = mtype.getReturnType(); 1038 if (returnType.requiresLoadableDescriptors(m.owner)) { 1039 poolWriter.enterLoadableDescriptorsClass(returnType.tsym); 1040 if (preview.isPreview(Source.Feature.VALUE_CLASSES)) { 1041 preview.markUsesPreview(null); 1042 } 1043 } 1044 int acountIdx = beginAttrs(); 1045 int acount = 0; 1046 if (m.code != null) { 1047 int alenIdx = writeAttr(names.Code); 1048 writeCode(m.code); 1049 m.code = null; // to conserve space 1050 endAttr(alenIdx); 1051 acount++; 1052 } 1053 List<Type> thrown = m.erasure(types).getThrownTypes(); 1054 if (thrown.nonEmpty()) { 1055 int alenIdx = writeAttr(names.Exceptions); 1056 databuf.appendChar(thrown.length()); 1057 for (List<Type> l = thrown; l.nonEmpty(); l = l.tail) 1058 databuf.appendChar(poolWriter.putClass(l.head)); 1059 endAttr(alenIdx); 1060 acount++; 1061 } 1062 if (m.defaultValue != null) { 1063 int alenIdx = writeAttr(names.AnnotationDefault); 1064 m.defaultValue.accept(awriter); 1065 endAttr(alenIdx); 1066 acount++; 1067 } 1068 if (target.hasMethodParameters()) { 1069 if (!m.isLambdaMethod()) { // Per JDK-8138729, do not emit parameters table for lambda bodies. 1070 boolean requiresParamNames = requiresParamNames(m); 1071 if (requiresParamNames || requiresParamFlags(m)) 1072 acount += writeMethodParametersAttr(m, requiresParamNames); 1073 } 1074 } 1075 acount += writeMemberAttrs(m, false); 1076 if (!m.isLambdaMethod()) 1077 acount += writeParameterAttrs(m.params); 1078 acount += writeExtraAttributes(m); 1079 endAttrs(acountIdx, acount); 1080 } 1081 1082 private boolean requiresParamNames(MethodSymbol m) { 1083 if (options.isSet(PARAMETERS)) 1084 return true; 1085 if (m.isConstructor() && (m.flags_field & RECORD) != 0) 1086 return true; 1087 return false; 1088 } 1089 1090 private boolean requiresParamFlags(MethodSymbol m) { 1091 if (!m.extraParams.isEmpty()) { 1092 return m.extraParams.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0); 1093 } 1094 if (m.params != null) { 1095 // parameter is stored in params for Enum#valueOf(name) 1096 return m.params.stream().anyMatch(p -> (p.flags_field & (SYNTHETIC | MANDATED)) != 0); 1097 } 1098 return false; 1099 } 1100 1101 /** Write code attribute of method. 1102 */ 1103 void writeCode(Code code) { 1104 databuf.appendChar(code.max_stack); 1105 databuf.appendChar(code.max_locals); 1106 databuf.appendInt(code.cp); 1107 databuf.appendBytes(code.code, 0, code.cp); 1108 databuf.appendChar(code.catchInfo.length()); 1109 for (List<char[]> l = code.catchInfo.toList(); 1110 l.nonEmpty(); 1111 l = l.tail) { 1112 for (int i = 0; i < l.head.length; i++) 1113 databuf.appendChar(l.head[i]); 1114 } 1115 int acountIdx = beginAttrs(); 1116 int acount = 0; 1117 1118 if (code.lineInfo.nonEmpty()) { 1119 int alenIdx = writeAttr(names.LineNumberTable); 1120 databuf.appendChar(code.lineInfo.length()); 1121 for (List<char[]> l = code.lineInfo.reverse(); 1122 l.nonEmpty(); 1123 l = l.tail) 1124 for (int i = 0; i < l.head.length; i++) 1125 databuf.appendChar(l.head[i]); 1126 endAttr(alenIdx); 1127 acount++; 1128 } 1129 1130 if (genCrt && (code.crt != null)) { 1131 CRTable crt = code.crt; 1132 int alenIdx = writeAttr(names.CharacterRangeTable); 1133 int crtIdx = beginAttrs(); 1134 int crtEntries = crt.writeCRT(databuf, code.lineMap, log); 1135 endAttrs(crtIdx, crtEntries); 1136 endAttr(alenIdx); 1137 acount++; 1138 } 1139 1140 // counter for number of generic local variables 1141 if (code.varDebugInfo && code.varBufferSize > 0) { 1142 int nGenericVars = 0; 1143 int alenIdx = writeAttr(names.LocalVariableTable); 1144 databuf.appendChar(code.getLVTSize()); 1145 for (int i=0; i<code.varBufferSize; i++) { 1146 Code.LocalVar var = code.varBuffer[i]; 1147 1148 for (Code.LocalVar.Range r: var.aliveRanges) { 1149 // write variable info 1150 Assert.check(r.start_pc >= 0 1151 && r.start_pc <= code.cp); 1152 databuf.appendChar(r.start_pc); 1153 Assert.check(r.length > 0 1154 && (r.start_pc + r.length) <= code.cp); 1155 databuf.appendChar(r.length); 1156 VarSymbol sym = var.sym; 1157 databuf.appendChar(poolWriter.putName(sym.name)); 1158 databuf.appendChar(poolWriter.putDescriptor(sym)); 1159 databuf.appendChar(var.reg); 1160 if (needsLocalVariableTypeEntry(var.sym.type)) { 1161 nGenericVars++; 1162 } 1163 } 1164 } 1165 endAttr(alenIdx); 1166 acount++; 1167 1168 if (nGenericVars > 0) { 1169 alenIdx = writeAttr(names.LocalVariableTypeTable); 1170 databuf.appendChar(nGenericVars); 1171 int count = 0; 1172 1173 for (int i=0; i<code.varBufferSize; i++) { 1174 Code.LocalVar var = code.varBuffer[i]; 1175 VarSymbol sym = var.sym; 1176 if (!needsLocalVariableTypeEntry(sym.type)) 1177 continue; 1178 for (Code.LocalVar.Range r : var.aliveRanges) { 1179 // write variable info 1180 databuf.appendChar(r.start_pc); 1181 databuf.appendChar(r.length); 1182 databuf.appendChar(poolWriter.putName(sym.name)); 1183 databuf.appendChar(poolWriter.putSignature(sym)); 1184 databuf.appendChar(var.reg); 1185 count++; 1186 } 1187 } 1188 Assert.check(count == nGenericVars); 1189 endAttr(alenIdx); 1190 acount++; 1191 } 1192 } 1193 1194 if (code.stackMapBufferSize > 0) { 1195 if (debugstackmap) System.out.println("Stack map for " + code.meth); 1196 int alenIdx = writeAttr(code.stackMap.getAttributeName(names)); 1197 writeStackMap(code); 1198 endAttr(alenIdx); 1199 acount++; 1200 } 1201 1202 acount += writeTypeAnnotations(code.meth.getRawTypeAttributes(), true); 1203 1204 endAttrs(acountIdx, acount); 1205 } 1206 //where 1207 private boolean needsLocalVariableTypeEntry(Type t) { 1208 //a local variable needs a type-entry if its type T is generic 1209 //(i.e. |T| != T) and if it's not an non-denotable type (non-denotable 1210 // types are not supported in signature attribute grammar!) 1211 return !types.isSameType(t, types.erasure(t)) && 1212 check.checkDenotable(t); 1213 } 1214 1215 void writeStackMap(Code code) { 1216 int nframes = code.stackMapBufferSize; 1217 if (debugstackmap) System.out.println(" nframes = " + nframes); 1218 databuf.appendChar(nframes); 1219 1220 switch (code.stackMap) { 1221 case CLDC: 1222 for (int i=0; i<nframes; i++) { 1223 if (debugstackmap) System.out.print(" " + i + ":"); 1224 Code.StackMapFrame frame = code.stackMapBuffer[i]; 1225 1226 // output PC 1227 if (debugstackmap) System.out.print(" pc=" + frame.pc); 1228 databuf.appendChar(frame.pc); 1229 1230 // output locals 1231 int localCount = 0; 1232 for (int j=0; j<frame.locals.length; 1233 j += Code.width(frame.locals[j])) { 1234 localCount++; 1235 } 1236 if (debugstackmap) System.out.print(" nlocals=" + 1237 localCount); 1238 databuf.appendChar(localCount); 1239 for (int j=0; j<frame.locals.length; 1240 j += Code.width(frame.locals[j])) { 1241 if (debugstackmap) System.out.print(" local[" + j + "]="); 1242 writeStackMapType(frame.locals[j]); 1243 } 1244 1245 // output stack 1246 int stackCount = 0; 1247 for (int j=0; j<frame.stack.length; 1248 j += Code.width(frame.stack[j])) { 1249 stackCount++; 1250 } 1251 if (debugstackmap) System.out.print(" nstack=" + 1252 stackCount); 1253 databuf.appendChar(stackCount); 1254 for (int j=0; j<frame.stack.length; 1255 j += Code.width(frame.stack[j])) { 1256 if (debugstackmap) System.out.print(" stack[" + j + "]="); 1257 writeStackMapType(frame.stack[j]); 1258 } 1259 if (debugstackmap) System.out.println(); 1260 } 1261 break; 1262 case JSR202: { 1263 Assert.checkNull(code.stackMapBuffer); 1264 for (int i=0; i<nframes; i++) { 1265 if (debugstackmap) System.out.print(" " + i + ":"); 1266 StackMapTableFrame frame = code.stackMapTableBuffer[i]; 1267 frame.write(this); 1268 if (debugstackmap) System.out.println(); 1269 } 1270 break; 1271 } 1272 default: 1273 throw new AssertionError("Unexpected stackmap format value"); 1274 } 1275 } 1276 1277 //where 1278 void writeStackMapType(Type t) { 1279 if (t == null) { 1280 if (debugstackmap) System.out.print("empty"); 1281 databuf.appendByte(0); 1282 } 1283 else switch(t.getTag()) { 1284 case BYTE: 1285 case CHAR: 1286 case SHORT: 1287 case INT: 1288 case BOOLEAN: 1289 if (debugstackmap) System.out.print("int"); 1290 databuf.appendByte(1); 1291 break; 1292 case FLOAT: 1293 if (debugstackmap) System.out.print("float"); 1294 databuf.appendByte(2); 1295 break; 1296 case DOUBLE: 1297 if (debugstackmap) System.out.print("double"); 1298 databuf.appendByte(3); 1299 break; 1300 case LONG: 1301 if (debugstackmap) System.out.print("long"); 1302 databuf.appendByte(4); 1303 break; 1304 case BOT: // null 1305 if (debugstackmap) System.out.print("null"); 1306 databuf.appendByte(5); 1307 break; 1308 case CLASS: 1309 case ARRAY: 1310 case TYPEVAR: 1311 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")"); 1312 databuf.appendByte(7); 1313 databuf.appendChar(poolWriter.putClass(types.erasure(t))); 1314 break; 1315 case UNINITIALIZED_THIS: 1316 if (debugstackmap) System.out.print("uninit_this"); 1317 databuf.appendByte(6); 1318 break; 1319 case UNINITIALIZED_OBJECT: 1320 { UninitializedType uninitType = (UninitializedType)t; 1321 databuf.appendByte(8); 1322 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset); 1323 databuf.appendChar(uninitType.offset); 1324 } 1325 break; 1326 default: 1327 throw new AssertionError(); 1328 } 1329 } 1330 1331 /** An entry in the JSR202 StackMapTable */ 1332 abstract static class StackMapTableFrame { 1333 abstract int getFrameType(); 1334 1335 void write(ClassWriter writer) { 1336 int frameType = getFrameType(); 1337 writer.databuf.appendByte(frameType); 1338 if (writer.debugstackmap) System.out.print(" frame_type=" + frameType); 1339 } 1340 1341 static class SameFrame extends StackMapTableFrame { 1342 final int offsetDelta; 1343 SameFrame(int offsetDelta) { 1344 this.offsetDelta = offsetDelta; 1345 } 1346 int getFrameType() { 1347 return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED; 1348 } 1349 @Override 1350 void write(ClassWriter writer) { 1351 super.write(writer); 1352 if (getFrameType() == SAME_FRAME_EXTENDED) { 1353 writer.databuf.appendChar(offsetDelta); 1354 if (writer.debugstackmap){ 1355 System.out.print(" offset_delta=" + offsetDelta); 1356 } 1357 } 1358 } 1359 } 1360 1361 static class SameLocals1StackItemFrame extends StackMapTableFrame { 1362 final int offsetDelta; 1363 final Type stack; 1364 SameLocals1StackItemFrame(int offsetDelta, Type stack) { 1365 this.offsetDelta = offsetDelta; 1366 this.stack = stack; 1367 } 1368 int getFrameType() { 1369 return (offsetDelta < SAME_FRAME_SIZE) ? 1370 (SAME_FRAME_SIZE + offsetDelta) : 1371 SAME_LOCALS_1_STACK_ITEM_EXTENDED; 1372 } 1373 @Override 1374 void write(ClassWriter writer) { 1375 super.write(writer); 1376 if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { 1377 writer.databuf.appendChar(offsetDelta); 1378 if (writer.debugstackmap) { 1379 System.out.print(" offset_delta=" + offsetDelta); 1380 } 1381 } 1382 if (writer.debugstackmap) { 1383 System.out.print(" stack[" + 0 + "]="); 1384 } 1385 writer.writeStackMapType(stack); 1386 } 1387 } 1388 1389 static class ChopFrame extends StackMapTableFrame { 1390 final int frameType; 1391 final int offsetDelta; 1392 ChopFrame(int frameType, int offsetDelta) { 1393 this.frameType = frameType; 1394 this.offsetDelta = offsetDelta; 1395 } 1396 int getFrameType() { return frameType; } 1397 @Override 1398 void write(ClassWriter writer) { 1399 super.write(writer); 1400 writer.databuf.appendChar(offsetDelta); 1401 if (writer.debugstackmap) { 1402 System.out.print(" offset_delta=" + offsetDelta); 1403 } 1404 } 1405 } 1406 1407 static class AppendFrame extends StackMapTableFrame { 1408 final int frameType; 1409 final int offsetDelta; 1410 final Type[] locals; 1411 AppendFrame(int frameType, int offsetDelta, Type[] locals) { 1412 this.frameType = frameType; 1413 this.offsetDelta = offsetDelta; 1414 this.locals = locals; 1415 } 1416 int getFrameType() { return frameType; } 1417 @Override 1418 void write(ClassWriter writer) { 1419 super.write(writer); 1420 writer.databuf.appendChar(offsetDelta); 1421 if (writer.debugstackmap) { 1422 System.out.print(" offset_delta=" + offsetDelta); 1423 } 1424 for (int i=0; i<locals.length; i++) { 1425 if (writer.debugstackmap) System.out.print(" locals[" + i + "]="); 1426 writer.writeStackMapType(locals[i]); 1427 } 1428 } 1429 } 1430 1431 static class FullFrame extends StackMapTableFrame { 1432 final int offsetDelta; 1433 final Type[] locals; 1434 final Type[] stack; 1435 FullFrame(int offsetDelta, Type[] locals, Type[] stack) { 1436 this.offsetDelta = offsetDelta; 1437 this.locals = locals; 1438 this.stack = stack; 1439 } 1440 int getFrameType() { return FULL_FRAME; } 1441 @Override 1442 void write(ClassWriter writer) { 1443 super.write(writer); 1444 writer.databuf.appendChar(offsetDelta); 1445 writer.databuf.appendChar(locals.length); 1446 if (writer.debugstackmap) { 1447 System.out.print(" offset_delta=" + offsetDelta); 1448 System.out.print(" nlocals=" + locals.length); 1449 } 1450 for (int i=0; i<locals.length; i++) { 1451 if (writer.debugstackmap) System.out.print(" locals[" + i + "]="); 1452 writer.writeStackMapType(locals[i]); 1453 } 1454 1455 writer.databuf.appendChar(stack.length); 1456 if (writer.debugstackmap) { System.out.print(" nstack=" + stack.length); } 1457 for (int i=0; i<stack.length; i++) { 1458 if (writer.debugstackmap) System.out.print(" stack[" + i + "]="); 1459 writer.writeStackMapType(stack[i]); 1460 } 1461 } 1462 } 1463 1464 /** Compare this frame with the previous frame and produce 1465 * an entry of compressed stack map frame. */ 1466 static StackMapTableFrame getInstance(Code.StackMapFrame this_frame, 1467 int prev_pc, 1468 Type[] prev_locals, 1469 Types types) { 1470 Type[] locals = this_frame.locals; 1471 Type[] stack = this_frame.stack; 1472 int offset_delta = this_frame.pc - prev_pc - 1; 1473 if (stack.length == 1) { 1474 if (locals.length == prev_locals.length 1475 && compare(prev_locals, locals, types) == 0) { 1476 return new SameLocals1StackItemFrame(offset_delta, stack[0]); 1477 } 1478 } else if (stack.length == 0) { 1479 int diff_length = compare(prev_locals, locals, types); 1480 if (diff_length == 0) { 1481 return new SameFrame(offset_delta); 1482 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) { 1483 // APPEND 1484 Type[] local_diff = new Type[-diff_length]; 1485 for (int i=prev_locals.length, j=0; i<locals.length; i++,j++) { 1486 local_diff[j] = locals[i]; 1487 } 1488 return new AppendFrame(SAME_FRAME_EXTENDED - diff_length, 1489 offset_delta, 1490 local_diff); 1491 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) { 1492 // CHOP 1493 return new ChopFrame(SAME_FRAME_EXTENDED - diff_length, 1494 offset_delta); 1495 } 1496 } 1497 // FULL_FRAME 1498 return new FullFrame(offset_delta, locals, stack); 1499 } 1500 1501 static boolean isInt(Type t) { 1502 return (t.getTag().isStrictSubRangeOf(INT) || t.hasTag(BOOLEAN)); 1503 } 1504 1505 static boolean isSameType(Type t1, Type t2, Types types) { 1506 if (t1 == null) { return t2 == null; } 1507 if (t2 == null) { return false; } 1508 1509 if (isInt(t1) && isInt(t2)) { return true; } 1510 1511 if (t1.hasTag(UNINITIALIZED_THIS)) { 1512 return t2.hasTag(UNINITIALIZED_THIS); 1513 } else if (t1.hasTag(UNINITIALIZED_OBJECT)) { 1514 if (t2.hasTag(UNINITIALIZED_OBJECT)) { 1515 return ((UninitializedType)t1).offset == ((UninitializedType)t2).offset; 1516 } else { 1517 return false; 1518 } 1519 } else if (t2.hasTag(UNINITIALIZED_THIS) || t2.hasTag(UNINITIALIZED_OBJECT)) { 1520 return false; 1521 } 1522 1523 return types.isSameType(t1, t2); 1524 } 1525 1526 static int compare(Type[] arr1, Type[] arr2, Types types) { 1527 int diff_length = arr1.length - arr2.length; 1528 if (diff_length > MAX_LOCAL_LENGTH_DIFF || diff_length < -MAX_LOCAL_LENGTH_DIFF) { 1529 return Integer.MAX_VALUE; 1530 } 1531 int len = (diff_length > 0) ? arr2.length : arr1.length; 1532 for (int i=0; i<len; i++) { 1533 if (!isSameType(arr1[i], arr2[i], types)) { 1534 return Integer.MAX_VALUE; 1535 } 1536 } 1537 return diff_length; 1538 } 1539 } 1540 1541 void writeFields(Scope s) { 1542 // process them in reverse sibling order; 1543 // i.e., process them in declaration order. 1544 List<VarSymbol> vars = List.nil(); 1545 for (Symbol sym : s.getSymbols(NON_RECURSIVE)) { 1546 if (sym.kind == VAR) vars = vars.prepend((VarSymbol)sym); 1547 } 1548 while (vars.nonEmpty()) { 1549 writeField(vars.head); 1550 vars = vars.tail; 1551 } 1552 } 1553 1554 void writeMethods(Scope s) { 1555 List<MethodSymbol> methods = List.nil(); 1556 for (Symbol sym : s.getSymbols(NON_RECURSIVE)) { 1557 if (sym.kind == MTH && (sym.flags() & HYPOTHETICAL) == 0) 1558 methods = methods.prepend((MethodSymbol)sym); 1559 } 1560 while (methods.nonEmpty()) { 1561 writeMethod(methods.head); 1562 methods = methods.tail; 1563 } 1564 } 1565 1566 /** Emit a class file for a given class. 1567 * @param c The class from which a class file is generated. 1568 */ 1569 public JavaFileObject writeClass(ClassSymbol c) 1570 throws IOException, PoolOverflow, StringOverflow 1571 { 1572 String name = (c.owner.kind == MDL ? c.name : c.flatname).toString(); 1573 Location outLocn; 1574 if (multiModuleMode) { 1575 ModuleSymbol msym = c.owner.kind == MDL ? (ModuleSymbol) c.owner : c.packge().modle; 1576 outLocn = fileManager.getLocationForModule(CLASS_OUTPUT, msym.name.toString()); 1577 } else { 1578 outLocn = CLASS_OUTPUT; 1579 } 1580 JavaFileObject outFile 1581 = fileManager.getJavaFileForOutput(outLocn, 1582 name, 1583 JavaFileObject.Kind.CLASS, 1584 c.sourcefile); 1585 OutputStream out = outFile.openOutputStream(); 1586 try { 1587 writeClassFile(out, c); 1588 if (verbose) 1589 log.printVerbose("wrote.file", outFile.getName()); 1590 out.close(); 1591 out = null; 1592 } catch (InvalidSignatureException ex) { 1593 log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type()))); 1594 } finally { 1595 if (out != null) { 1596 // if we are propagating an exception, delete the file 1597 out.close(); 1598 outFile.delete(); 1599 outFile = null; 1600 } 1601 } 1602 return outFile; // may be null if write failed 1603 } 1604 1605 /** Write class `c' to outstream `out'. 1606 */ 1607 public void writeClassFile(OutputStream out, ClassSymbol c) 1608 throws IOException, PoolOverflow, StringOverflow { 1609 Assert.check((c.flags() & COMPOUND) == 0); 1610 databuf.reset(); 1611 poolbuf.reset(); 1612 1613 Type supertype = types.supertype(c.type); 1614 List<Type> interfaces = types.interfaces(c.type); 1615 List<Type> typarams = c.type.getTypeArguments(); 1616 1617 int flags; 1618 if (c.owner.kind == MDL) { 1619 flags = ACC_MODULE; 1620 } else { 1621 long originalFlags = c.flags(); 1622 flags = adjustFlags(c, c.flags() & ~(DEFAULT | STRICTFP)); 1623 if ((flags & PROTECTED) != 0) flags |= PUBLIC; 1624 flags = flags & ClassFlags; 1625 flags |= (originalFlags & IDENTITY_TYPE) != 0 ? ACC_IDENTITY : flags; 1626 } 1627 1628 if (dumpClassModifiers) { 1629 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 1630 pw.println(); 1631 pw.println("CLASSFILE " + c.getQualifiedName()); 1632 pw.println("---" + flagNames(flags)); 1633 } 1634 databuf.appendChar(flags); 1635 1636 if (c.owner.kind == MDL) { 1637 PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage; 1638 databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed))); 1639 } else { 1640 databuf.appendChar(poolWriter.putClass(c)); 1641 } 1642 databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0); 1643 databuf.appendChar(interfaces.length()); 1644 for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail) 1645 databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym)); 1646 int fieldsCount = 0; 1647 int methodsCount = 0; 1648 for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) { 1649 switch (sym.kind) { 1650 case VAR: fieldsCount++; break; 1651 case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++; 1652 break; 1653 case TYP: poolWriter.enterInner((ClassSymbol)sym); break; 1654 default : Assert.error(); 1655 } 1656 } 1657 1658 if (c.trans_local != null) { 1659 for (ClassSymbol local : c.trans_local) { 1660 poolWriter.enterInner(local); 1661 } 1662 } 1663 1664 databuf.appendChar(fieldsCount); 1665 writeFields(c.members()); 1666 databuf.appendChar(methodsCount); 1667 writeMethods(c.members()); 1668 1669 int acountIdx = beginAttrs(); 1670 int acount = 0; 1671 1672 boolean sigReq = 1673 typarams.length() != 0 || supertype.allparams().length() != 0; 1674 for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail) 1675 sigReq = l.head.allparams().length() != 0; 1676 if (sigReq) { 1677 int alenIdx = writeAttr(names.Signature); 1678 databuf.appendChar(poolWriter.putSignature(c)); 1679 endAttr(alenIdx); 1680 acount++; 1681 } 1682 1683 if (c.sourcefile != null && emitSourceFile) { 1684 int alenIdx = writeAttr(names.SourceFile); 1685 // WHM 6/29/1999: Strip file path prefix. We do it here at 1686 // the last possible moment because the sourcefile may be used 1687 // elsewhere in error diagnostics. Fixes 4241573. 1688 String simpleName = PathFileObject.getSimpleName(c.sourcefile); 1689 databuf.appendChar(poolWriter.putName(names.fromString(simpleName))); 1690 endAttr(alenIdx); 1691 acount++; 1692 } 1693 1694 if (genCrt) { 1695 // Append SourceID attribute 1696 int alenIdx = writeAttr(names.SourceID); 1697 databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(getLastModified(c.sourcefile))))); 1698 endAttr(alenIdx); 1699 acount++; 1700 // Append CompilationID attribute 1701 alenIdx = writeAttr(names.CompilationID); 1702 databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis())))); 1703 endAttr(alenIdx); 1704 acount++; 1705 } 1706 1707 acount += writeFlagAttrs(c.flags()); 1708 acount += writeJavaAnnotations(c.getRawAttributes()); 1709 acount += writeTypeAnnotations(c.getRawTypeAttributes(), false); 1710 acount += writeEnclosingMethodAttribute(c); 1711 if (c.owner.kind == MDL) { 1712 acount += writeModuleAttribute(c); 1713 acount += writeFlagAttrs(c.owner.flags() & ~DEPRECATED); 1714 } 1715 acount += writeExtraClassAttributes(c); 1716 acount += writeExtraAttributes(c); 1717 1718 poolbuf.appendInt(JAVA_MAGIC); 1719 if (preview.isEnabled() && preview.usesPreview(c.sourcefile)) { 1720 poolbuf.appendChar(ClassFile.PREVIEW_MINOR_VERSION); 1721 } else { 1722 poolbuf.appendChar(target.minorVersion); 1723 } 1724 poolbuf.appendChar(target.majorVersion); 1725 1726 if (c.owner.kind != MDL) { 1727 if (target.hasNestmateAccess()) { 1728 acount += writeNestMembersIfNeeded(c); 1729 acount += writeNestHostIfNeeded(c); 1730 } 1731 } 1732 1733 if (c.isRecord()) { 1734 acount += writeRecordAttribute(c); 1735 } 1736 1737 if (target.hasSealedClasses()) { 1738 acount += writePermittedSubclassesIfNeeded(c); 1739 } 1740 1741 if (!poolWriter.bootstrapMethods.isEmpty()) { 1742 writeBootstrapMethods(); 1743 acount++; 1744 } 1745 1746 if (!poolWriter.innerClasses.isEmpty()) { 1747 writeInnerClasses(); 1748 acount++; 1749 } 1750 1751 if (!poolWriter.loadableDescriptors.isEmpty()) { 1752 writeLoadableDescriptorsAttribute(); 1753 acount++; 1754 } 1755 1756 endAttrs(acountIdx, acount); 1757 1758 out.write(poolbuf.elems, 0, poolbuf.length); 1759 1760 poolWriter.writePool(out); 1761 poolWriter.reset(); // to save space 1762 1763 out.write(databuf.elems, 0, databuf.length); 1764 } 1765 1766 /**Allows subclasses to write additional class attributes 1767 * 1768 * @return the number of attributes written 1769 */ 1770 protected int writeExtraClassAttributes(ClassSymbol c) { 1771 return 0; 1772 } 1773 1774 /**Allows friends to write additional attributes 1775 * 1776 * @return the number of attributes written 1777 */ 1778 protected int writeExtraAttributes(Symbol sym) { 1779 int i = 0; 1780 for (ToIntFunction<Symbol> hook : extraAttributeHooks) { 1781 i += hook.applyAsInt(sym); 1782 } 1783 return i; 1784 } 1785 1786 int adjustFlags(Symbol sym, final long flags) { 1787 int result = (int)flags; 1788 1789 // Elide strictfp bit in class files 1790 if (target.obsoleteAccStrict()) 1791 result &= ~STRICTFP; 1792 1793 if ((flags & BRIDGE) != 0) 1794 result |= ACC_BRIDGE; 1795 if ((flags & VARARGS) != 0) 1796 result |= ACC_VARARGS; 1797 if ((flags & DEFAULT) != 0) 1798 result &= ~ABSTRACT; 1799 if ((flags & IDENTITY_TYPE) != 0) { 1800 result |= ACC_IDENTITY; 1801 } 1802 if (sym.kind == VAR) { 1803 if ((flags & STRICT) != 0) { 1804 result |= ACC_STRICT; 1805 } 1806 } 1807 return result; 1808 } 1809 1810 long getLastModified(FileObject filename) { 1811 return filename.getLastModified(); 1812 } 1813 }