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