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