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