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