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