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