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 endAttr(attrIndex); 661 return 1; 662 } else 663 return 0; 664 } 665 666 667 /** Write method parameter annotations; 668 * return number of attributes written. 669 */ 670 int writeParameterAttrs(MethodSymbol m) { 671 boolean hasVisible = false; 672 boolean hasInvisible = false; 673 if (m.params != null) { 674 for (VarSymbol s : m.params) { 675 for (Attribute.Compound a : s.getRawAttributes()) { 676 switch (types.getRetention(a)) { 677 case SOURCE: break; 678 case CLASS: hasInvisible = true; break; 679 case RUNTIME: hasVisible = true; break; 680 default: ;// /* fail soft */ throw new AssertionError(vis); 681 } 682 } 683 } 684 } 685 686 int attrCount = 0; 687 if (hasVisible) { 688 int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations); 689 databuf.appendByte(m.params.length()); 690 for (VarSymbol s : m.params) { 691 ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>(); 692 for (Attribute.Compound a : s.getRawAttributes()) 693 if (types.getRetention(a) == RetentionPolicy.RUNTIME) 694 buf.append(a); 695 databuf.appendChar(buf.length()); 696 for (Attribute.Compound a : buf) 697 writeCompoundAttribute(a); 698 } 699 endAttr(attrIndex); 700 attrCount++; 701 } 702 if (hasInvisible) { 703 int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations); 704 databuf.appendByte(m.params.length()); 705 for (VarSymbol s : m.params) { 706 ListBuffer<Attribute.Compound> buf = new ListBuffer<Attribute.Compound>(); 707 for (Attribute.Compound a : s.getRawAttributes()) 708 if (types.getRetention(a) == RetentionPolicy.CLASS) 709 buf.append(a); 710 databuf.appendChar(buf.length()); 711 for (Attribute.Compound a : buf) 712 writeCompoundAttribute(a); 713 } 714 endAttr(attrIndex); 715 attrCount++; 716 } 717 return attrCount; 718 } 719 720 /********************************************************************** 721 * Writing Java-language annotations (aka metadata, attributes) 722 **********************************************************************/ 723 724 /** Write Java-language annotations; return number of JVM 725 * attributes written (zero or one). 726 */ 727 int writeJavaAnnotations(List<Attribute.Compound> attrs) { 728 if (attrs.isEmpty()) return 0; 729 ListBuffer<Attribute.Compound> visibles = new ListBuffer<Attribute.Compound>(); 730 ListBuffer<Attribute.Compound> invisibles = new ListBuffer<Attribute.Compound>(); 731 for (Attribute.Compound a : attrs) { 732 switch (types.getRetention(a)) { 733 case SOURCE: break; 734 case CLASS: invisibles.append(a); break; 735 case RUNTIME: visibles.append(a); break; 736 default: ;// /* fail soft */ throw new AssertionError(vis); 737 } 738 } 739 740 int attrCount = 0; 741 if (visibles.length() != 0) { 742 int attrIndex = writeAttr(names.RuntimeVisibleAnnotations); 743 databuf.appendChar(visibles.length()); 744 for (Attribute.Compound a : visibles) 745 writeCompoundAttribute(a); 746 endAttr(attrIndex); 747 attrCount++; 748 } 749 if (invisibles.length() != 0) { 750 int attrIndex = writeAttr(names.RuntimeInvisibleAnnotations); 751 databuf.appendChar(invisibles.length()); 752 for (Attribute.Compound a : invisibles) 753 writeCompoundAttribute(a); 754 endAttr(attrIndex); 755 attrCount++; 756 } 757 return attrCount; 758 } 759 760 int writeTypeAnnotations(List<Attribute.TypeCompound> typeAnnos, boolean inCode) { 761 if (typeAnnos.isEmpty()) return 0; 762 763 ListBuffer<Attribute.TypeCompound> visibles = ListBuffer.lb(); 764 ListBuffer<Attribute.TypeCompound> invisibles = ListBuffer.lb(); 765 766 for (Attribute.TypeCompound tc : typeAnnos) { 767 if (tc.hasUnknownPosition()) { 768 boolean fixed = tc.tryFixPosition(); 769 770 // Could we fix it? 771 if (!fixed) { 772 // This happens for nested types like @A Outer. @B Inner. 773 // For method parameters we get the annotation twice! Once with 774 // a valid position, once unknown. 775 // TODO: find a cleaner solution. 776 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 777 pw.println("ClassWriter: Position UNKNOWN in type annotation: " + tc); 778 continue; 779 } 780 } 781 782 if (tc.position.type.isLocal() != inCode) 783 continue; 784 if (!tc.position.emitToClassfile()) 785 continue; 786 switch (types.getRetention(tc)) { 787 case SOURCE: break; 788 case CLASS: invisibles.append(tc); break; 789 case RUNTIME: visibles.append(tc); break; 790 default: ;// /* fail soft */ throw new AssertionError(vis); 791 } 792 } 793 794 int attrCount = 0; 795 if (visibles.length() != 0) { 796 int attrIndex = writeAttr(names.RuntimeVisibleTypeAnnotations); 797 databuf.appendChar(visibles.length()); 798 for (Attribute.TypeCompound p : visibles) 799 writeTypeAnnotation(p); 800 endAttr(attrIndex); 801 attrCount++; 802 } 803 804 if (invisibles.length() != 0) { 805 int attrIndex = writeAttr(names.RuntimeInvisibleTypeAnnotations); 806 databuf.appendChar(invisibles.length()); 807 for (Attribute.TypeCompound p : invisibles) 808 writeTypeAnnotation(p); 809 endAttr(attrIndex); 810 attrCount++; 811 } 812 813 return attrCount; 814 } 815 816 /** A visitor to write an attribute including its leading 817 * single-character marker. 818 */ 819 class AttributeWriter implements Attribute.Visitor { 820 public void visitConstant(Attribute.Constant _value) { 821 Object value = _value.value; 822 switch (_value.type.getTag()) { 823 case BYTE: 824 databuf.appendByte('B'); 825 break; 826 case CHAR: 827 databuf.appendByte('C'); 828 break; 829 case SHORT: 830 databuf.appendByte('S'); 831 break; 832 case INT: 833 databuf.appendByte('I'); 834 break; 835 case LONG: 836 databuf.appendByte('J'); 837 break; 838 case FLOAT: 839 databuf.appendByte('F'); 840 break; 841 case DOUBLE: 842 databuf.appendByte('D'); 843 break; 844 case BOOLEAN: 845 databuf.appendByte('Z'); 846 break; 847 case CLASS: 848 Assert.check(value instanceof String); 849 databuf.appendByte('s'); 850 value = names.fromString(value.toString()); // CONSTANT_Utf8 851 break; 852 default: 853 throw new AssertionError(_value.type); 854 } 855 databuf.appendChar(pool.put(value)); 856 } 857 public void visitEnum(Attribute.Enum e) { 858 databuf.appendByte('e'); 859 databuf.appendChar(pool.put(typeSig(e.value.type))); 860 databuf.appendChar(pool.put(e.value.name)); 861 } 862 public void visitClass(Attribute.Class clazz) { 863 databuf.appendByte('c'); 864 databuf.appendChar(pool.put(typeSig(clazz.classType))); 865 } 866 public void visitCompound(Attribute.Compound compound) { 867 databuf.appendByte('@'); 868 writeCompoundAttribute(compound); 869 } 870 public void visitError(Attribute.Error x) { 871 throw new AssertionError(x); 872 } 873 public void visitArray(Attribute.Array array) { 874 databuf.appendByte('['); 875 databuf.appendChar(array.values.length); 876 for (Attribute a : array.values) { 877 a.accept(this); 878 } 879 } 880 } 881 AttributeWriter awriter = new AttributeWriter(); 882 883 /** Write a compound attribute excluding the '@' marker. */ 884 void writeCompoundAttribute(Attribute.Compound c) { 885 databuf.appendChar(pool.put(typeSig(c.type))); 886 databuf.appendChar(c.values.length()); 887 for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) { 888 databuf.appendChar(pool.put(p.fst.name)); 889 p.snd.accept(awriter); 890 } 891 } 892 893 void writeTypeAnnotation(Attribute.TypeCompound c) { 894 writePosition(c.position); 895 writeCompoundAttribute(c); 896 } 897 898 void writePosition(TypeAnnotationPosition p) { 899 databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte 900 switch (p.type) { 901 // instanceof 902 case INSTANCEOF: 903 // new expression 904 case NEW: 905 // constructor/method reference receiver 906 case CONSTRUCTOR_REFERENCE: 907 case METHOD_REFERENCE: 908 databuf.appendChar(p.offset); 909 break; 910 // local variable 911 case LOCAL_VARIABLE: 912 // resource variable 913 case RESOURCE_VARIABLE: 914 databuf.appendChar(p.lvarOffset.length); // for table length 915 for (int i = 0; i < p.lvarOffset.length; ++i) { 916 databuf.appendChar(p.lvarOffset[i]); 917 databuf.appendChar(p.lvarLength[i]); 918 databuf.appendChar(p.lvarIndex[i]); 919 } 920 break; 921 // exception parameter 922 case EXCEPTION_PARAMETER: 923 databuf.appendChar(p.exception_index); 924 break; 925 // method receiver 926 case METHOD_RECEIVER: 927 // Do nothing 928 break; 929 // type parameter 930 case CLASS_TYPE_PARAMETER: 931 case METHOD_TYPE_PARAMETER: 932 databuf.appendByte(p.parameter_index); 933 break; 934 // type parameter bound 935 case CLASS_TYPE_PARAMETER_BOUND: 936 case METHOD_TYPE_PARAMETER_BOUND: 937 databuf.appendByte(p.parameter_index); 938 databuf.appendByte(p.bound_index); 939 break; 940 // class extends or implements clause 941 case CLASS_EXTENDS: 942 databuf.appendChar(p.type_index); 943 break; 944 // throws 945 case THROWS: 946 databuf.appendChar(p.type_index); 947 break; 948 // method parameter 949 case METHOD_FORMAL_PARAMETER: 950 databuf.appendByte(p.parameter_index); 951 break; 952 // type cast 953 case CAST: 954 // method/constructor/reference type argument 955 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 956 case METHOD_INVOCATION_TYPE_ARGUMENT: 957 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 958 case METHOD_REFERENCE_TYPE_ARGUMENT: 959 databuf.appendChar(p.offset); 960 databuf.appendByte(p.type_index); 961 break; 962 // We don't need to worry about these 963 case METHOD_RETURN: 964 case FIELD: 965 break; 966 case UNKNOWN: 967 throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!"); 968 default: 969 throw new AssertionError("jvm.ClassWriter: Unknown target type for position: " + p); 970 } 971 972 { // Append location data for generics/arrays. 973 databuf.appendByte(p.location.size()); 974 java.util.List<Integer> loc = TypeAnnotationPosition.getBinaryFromTypePath(p.location); 975 for (int i : loc) 976 databuf.appendByte((byte)i); 977 } 978 } 979 980 /********************************************************************** 981 * Writing Objects 982 **********************************************************************/ 983 984 /** Enter an inner class into the `innerClasses' set/queue. 985 */ 986 void enterInner(ClassSymbol c) { 987 if (c.type.isCompound()) { 988 throw new AssertionError("Unexpected intersection type: " + c.type); 989 } 990 try { 991 c.complete(); 992 } catch (CompletionFailure ex) { 993 System.err.println("error: " + c + ": " + ex.getMessage()); 994 throw ex; 995 } 996 if (!c.type.hasTag(CLASS)) return; // arrays 997 if (pool != null && // pool might be null if called from xClassName 998 c.owner.enclClass() != null && 999 (innerClasses == null || !innerClasses.contains(c))) { 1000 // log.errWriter.println("enter inner " + c);//DEBUG 1001 enterInner(c.owner.enclClass()); 1002 pool.put(c); 1003 if (c.name != names.empty) 1004 pool.put(c.name); 1005 if (innerClasses == null) { 1006 innerClasses = new HashSet<ClassSymbol>(); 1007 innerClassesQueue = new ListBuffer<ClassSymbol>(); 1008 pool.put(names.InnerClasses); 1009 } 1010 innerClasses.add(c); 1011 innerClassesQueue.append(c); 1012 } 1013 } 1014 1015 /** Write "inner classes" attribute. 1016 */ 1017 void writeInnerClasses() { 1018 int alenIdx = writeAttr(names.InnerClasses); 1019 databuf.appendChar(innerClassesQueue.length()); 1020 for (List<ClassSymbol> l = innerClassesQueue.toList(); 1021 l.nonEmpty(); 1022 l = l.tail) { 1023 ClassSymbol inner = l.head; 1024 char flags = (char) adjustFlags(inner.flags_field); 1025 if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT 1026 if (inner.name.isEmpty()) flags &= ~FINAL; // Anonymous class: unset FINAL flag 1027 flags &= ~STRICTFP; //inner classes should not have the strictfp flag set. 1028 if (dumpInnerClassModifiers) { 1029 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 1030 pw.println("INNERCLASS " + inner.name); 1031 pw.println("---" + flagNames(flags)); 1032 } 1033 databuf.appendChar(pool.get(inner)); 1034 databuf.appendChar( 1035 inner.owner.kind == TYP ? pool.get(inner.owner) : 0); 1036 databuf.appendChar( 1037 !inner.name.isEmpty() ? pool.get(inner.name) : 0); 1038 databuf.appendChar(flags); 1039 } 1040 endAttr(alenIdx); 1041 } 1042 1043 /** Write "bootstrapMethods" attribute. 1044 */ 1045 void writeBootstrapMethods() { 1046 int alenIdx = writeAttr(names.BootstrapMethods); 1047 databuf.appendChar(bootstrapMethods.size()); 1048 for (Map.Entry<DynamicMethod, MethodHandle> entry : bootstrapMethods.entrySet()) { 1049 DynamicMethod dmeth = entry.getKey(); 1050 DynamicMethodSymbol dsym = (DynamicMethodSymbol)dmeth.baseSymbol(); 1051 //write BSM handle 1052 databuf.appendChar(pool.get(entry.getValue())); 1053 //write static args length 1054 databuf.appendChar(dsym.staticArgs.length); 1055 //write static args array 1056 Object[] uniqueArgs = dmeth.uniqueStaticArgs; 1057 for (Object o : uniqueArgs) { 1058 databuf.appendChar(pool.get(o)); 1059 } 1060 } 1061 endAttr(alenIdx); 1062 } 1063 1064 /** Write field symbol, entering all references into constant pool. 1065 */ 1066 void writeField(VarSymbol v) { 1067 int flags = adjustFlags(v.flags()); 1068 databuf.appendChar(flags); 1069 if (dumpFieldModifiers) { 1070 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 1071 pw.println("FIELD " + fieldName(v)); 1072 pw.println("---" + flagNames(v.flags())); 1073 } 1074 databuf.appendChar(pool.put(fieldName(v))); 1075 databuf.appendChar(pool.put(typeSig(v.erasure(types)))); 1076 int acountIdx = beginAttrs(); 1077 int acount = 0; 1078 if (v.getConstValue() != null) { 1079 int alenIdx = writeAttr(names.ConstantValue); 1080 databuf.appendChar(pool.put(v.getConstValue())); 1081 endAttr(alenIdx); 1082 acount++; 1083 } 1084 acount += writeMemberAttrs(v); 1085 endAttrs(acountIdx, acount); 1086 } 1087 1088 /** Write method symbol, entering all references into constant pool. 1089 */ 1090 void writeMethod(MethodSymbol m) { 1091 int flags = adjustFlags(m.flags()); 1092 databuf.appendChar(flags); 1093 if (dumpMethodModifiers) { 1094 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 1095 pw.println("METHOD " + fieldName(m)); 1096 pw.println("---" + flagNames(m.flags())); 1097 } 1098 databuf.appendChar(pool.put(fieldName(m))); 1099 databuf.appendChar(pool.put(typeSig(m.externalType(types)))); 1100 int acountIdx = beginAttrs(); 1101 int acount = 0; 1102 if (m.code != null) { 1103 int alenIdx = writeAttr(names.Code); 1104 writeCode(m.code); 1105 m.code = null; // to conserve space 1106 endAttr(alenIdx); 1107 acount++; 1108 } 1109 List<Type> thrown = m.erasure(types).getThrownTypes(); 1110 if (thrown.nonEmpty()) { 1111 int alenIdx = writeAttr(names.Exceptions); 1112 databuf.appendChar(thrown.length()); 1113 for (List<Type> l = thrown; l.nonEmpty(); l = l.tail) 1114 databuf.appendChar(pool.put(l.head.tsym)); 1115 endAttr(alenIdx); 1116 acount++; 1117 } 1118 if (m.defaultValue != null) { 1119 int alenIdx = writeAttr(names.AnnotationDefault); 1120 m.defaultValue.accept(awriter); 1121 endAttr(alenIdx); 1122 acount++; 1123 } 1124 if (options.isSet(PARAMETERS)) 1125 acount += writeMethodParametersAttr(m); 1126 acount += writeMemberAttrs(m); 1127 acount += writeParameterAttrs(m); 1128 endAttrs(acountIdx, acount); 1129 } 1130 1131 /** Write code attribute of method. 1132 */ 1133 void writeCode(Code code) { 1134 databuf.appendChar(code.max_stack); 1135 databuf.appendChar(code.max_locals); 1136 databuf.appendInt(code.cp); 1137 databuf.appendBytes(code.code, 0, code.cp); 1138 databuf.appendChar(code.catchInfo.length()); 1139 for (List<char[]> l = code.catchInfo.toList(); 1140 l.nonEmpty(); 1141 l = l.tail) { 1142 for (int i = 0; i < l.head.length; i++) 1143 databuf.appendChar(l.head[i]); 1144 } 1145 int acountIdx = beginAttrs(); 1146 int acount = 0; 1147 1148 if (code.lineInfo.nonEmpty()) { 1149 int alenIdx = writeAttr(names.LineNumberTable); 1150 databuf.appendChar(code.lineInfo.length()); 1151 for (List<char[]> l = code.lineInfo.reverse(); 1152 l.nonEmpty(); 1153 l = l.tail) 1154 for (int i = 0; i < l.head.length; i++) 1155 databuf.appendChar(l.head[i]); 1156 endAttr(alenIdx); 1157 acount++; 1158 } 1159 1160 if (genCrt && (code.crt != null)) { 1161 CRTable crt = code.crt; 1162 int alenIdx = writeAttr(names.CharacterRangeTable); 1163 int crtIdx = beginAttrs(); 1164 int crtEntries = crt.writeCRT(databuf, code.lineMap, log); 1165 endAttrs(crtIdx, crtEntries); 1166 endAttr(alenIdx); 1167 acount++; 1168 } 1169 1170 // counter for number of generic local variables 1171 int nGenericVars = 0; 1172 1173 if (code.varBufferSize > 0) { 1174 int alenIdx = writeAttr(names.LocalVariableTable); 1175 databuf.appendChar(code.varBufferSize); 1176 1177 for (int i=0; i<code.varBufferSize; i++) { 1178 Code.LocalVar var = code.varBuffer[i]; 1179 1180 // write variable info 1181 Assert.check(var.start_pc >= 0 1182 && var.start_pc <= code.cp); 1183 databuf.appendChar(var.start_pc); 1184 Assert.check(var.length >= 0 1185 && (var.start_pc + var.length) <= code.cp); 1186 databuf.appendChar(var.length); 1187 VarSymbol sym = var.sym; 1188 databuf.appendChar(pool.put(sym.name)); 1189 Type vartype = sym.erasure(types); 1190 if (needsLocalVariableTypeEntry(sym.type)) 1191 nGenericVars++; 1192 databuf.appendChar(pool.put(typeSig(vartype))); 1193 databuf.appendChar(var.reg); 1194 } 1195 endAttr(alenIdx); 1196 acount++; 1197 } 1198 1199 if (nGenericVars > 0) { 1200 int alenIdx = writeAttr(names.LocalVariableTypeTable); 1201 databuf.appendChar(nGenericVars); 1202 int count = 0; 1203 1204 for (int i=0; i<code.varBufferSize; i++) { 1205 Code.LocalVar var = code.varBuffer[i]; 1206 VarSymbol sym = var.sym; 1207 if (!needsLocalVariableTypeEntry(sym.type)) 1208 continue; 1209 count++; 1210 // write variable info 1211 databuf.appendChar(var.start_pc); 1212 databuf.appendChar(var.length); 1213 databuf.appendChar(pool.put(sym.name)); 1214 databuf.appendChar(pool.put(typeSig(sym.type))); 1215 databuf.appendChar(var.reg); 1216 } 1217 Assert.check(count == nGenericVars); 1218 endAttr(alenIdx); 1219 acount++; 1220 } 1221 1222 if (code.stackMapBufferSize > 0) { 1223 if (debugstackmap) System.out.println("Stack map for " + code.meth); 1224 int alenIdx = writeAttr(code.stackMap.getAttributeName(names)); 1225 writeStackMap(code); 1226 endAttr(alenIdx); 1227 acount++; 1228 } 1229 1230 acount += writeTypeAnnotations(code.meth.getRawTypeAttributes(), true); 1231 1232 endAttrs(acountIdx, acount); 1233 } 1234 //where 1235 private boolean needsLocalVariableTypeEntry(Type t) { 1236 //a local variable needs a type-entry if its type T is generic 1237 //(i.e. |T| != T) and if it's not an intersection type (not supported 1238 //in signature attribute grammar) 1239 return (!types.isSameType(t, types.erasure(t)) && 1240 !t.isCompound()); 1241 } 1242 1243 void writeStackMap(Code code) { 1244 int nframes = code.stackMapBufferSize; 1245 if (debugstackmap) System.out.println(" nframes = " + nframes); 1246 databuf.appendChar(nframes); 1247 1248 switch (code.stackMap) { 1249 case CLDC: 1250 for (int i=0; i<nframes; i++) { 1251 if (debugstackmap) System.out.print(" " + i + ":"); 1252 Code.StackMapFrame frame = code.stackMapBuffer[i]; 1253 1254 // output PC 1255 if (debugstackmap) System.out.print(" pc=" + frame.pc); 1256 databuf.appendChar(frame.pc); 1257 1258 // output locals 1259 int localCount = 0; 1260 for (int j=0; j<frame.locals.length; 1261 j += (target.generateEmptyAfterBig() ? 1 : Code.width(frame.locals[j]))) { 1262 localCount++; 1263 } 1264 if (debugstackmap) System.out.print(" nlocals=" + 1265 localCount); 1266 databuf.appendChar(localCount); 1267 for (int j=0; j<frame.locals.length; 1268 j += (target.generateEmptyAfterBig() ? 1 : Code.width(frame.locals[j]))) { 1269 if (debugstackmap) System.out.print(" local[" + j + "]="); 1270 writeStackMapType(frame.locals[j]); 1271 } 1272 1273 // output stack 1274 int stackCount = 0; 1275 for (int j=0; j<frame.stack.length; 1276 j += (target.generateEmptyAfterBig() ? 1 : Code.width(frame.stack[j]))) { 1277 stackCount++; 1278 } 1279 if (debugstackmap) System.out.print(" nstack=" + 1280 stackCount); 1281 databuf.appendChar(stackCount); 1282 for (int j=0; j<frame.stack.length; 1283 j += (target.generateEmptyAfterBig() ? 1 : Code.width(frame.stack[j]))) { 1284 if (debugstackmap) System.out.print(" stack[" + j + "]="); 1285 writeStackMapType(frame.stack[j]); 1286 } 1287 if (debugstackmap) System.out.println(); 1288 } 1289 break; 1290 case JSR202: { 1291 Assert.checkNull(code.stackMapBuffer); 1292 for (int i=0; i<nframes; i++) { 1293 if (debugstackmap) System.out.print(" " + i + ":"); 1294 StackMapTableFrame frame = code.stackMapTableBuffer[i]; 1295 frame.write(this); 1296 if (debugstackmap) System.out.println(); 1297 } 1298 break; 1299 } 1300 default: 1301 throw new AssertionError("Unexpected stackmap format value"); 1302 } 1303 } 1304 1305 //where 1306 void writeStackMapType(Type t) { 1307 if (t == null) { 1308 if (debugstackmap) System.out.print("empty"); 1309 databuf.appendByte(0); 1310 } 1311 else switch(t.getTag()) { 1312 case BYTE: 1313 case CHAR: 1314 case SHORT: 1315 case INT: 1316 case BOOLEAN: 1317 if (debugstackmap) System.out.print("int"); 1318 databuf.appendByte(1); 1319 break; 1320 case FLOAT: 1321 if (debugstackmap) System.out.print("float"); 1322 databuf.appendByte(2); 1323 break; 1324 case DOUBLE: 1325 if (debugstackmap) System.out.print("double"); 1326 databuf.appendByte(3); 1327 break; 1328 case LONG: 1329 if (debugstackmap) System.out.print("long"); 1330 databuf.appendByte(4); 1331 break; 1332 case BOT: // null 1333 if (debugstackmap) System.out.print("null"); 1334 databuf.appendByte(5); 1335 break; 1336 case CLASS: 1337 case ARRAY: 1338 if (debugstackmap) System.out.print("object(" + t + ")"); 1339 databuf.appendByte(7); 1340 databuf.appendChar(pool.put(t)); 1341 break; 1342 case TYPEVAR: 1343 if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")"); 1344 databuf.appendByte(7); 1345 databuf.appendChar(pool.put(types.erasure(t).tsym)); 1346 break; 1347 case UNINITIALIZED_THIS: 1348 if (debugstackmap) System.out.print("uninit_this"); 1349 databuf.appendByte(6); 1350 break; 1351 case UNINITIALIZED_OBJECT: 1352 { UninitializedType uninitType = (UninitializedType)t; 1353 databuf.appendByte(8); 1354 if (debugstackmap) System.out.print("uninit_object@" + uninitType.offset); 1355 databuf.appendChar(uninitType.offset); 1356 } 1357 break; 1358 default: 1359 throw new AssertionError(); 1360 } 1361 } 1362 1363 /** An entry in the JSR202 StackMapTable */ 1364 abstract static class StackMapTableFrame { 1365 abstract int getFrameType(); 1366 1367 void write(ClassWriter writer) { 1368 int frameType = getFrameType(); 1369 writer.databuf.appendByte(frameType); 1370 if (writer.debugstackmap) System.out.print(" frame_type=" + frameType); 1371 } 1372 1373 static class SameFrame extends StackMapTableFrame { 1374 final int offsetDelta; 1375 SameFrame(int offsetDelta) { 1376 this.offsetDelta = offsetDelta; 1377 } 1378 int getFrameType() { 1379 return (offsetDelta < SAME_FRAME_SIZE) ? offsetDelta : SAME_FRAME_EXTENDED; 1380 } 1381 @Override 1382 void write(ClassWriter writer) { 1383 super.write(writer); 1384 if (getFrameType() == SAME_FRAME_EXTENDED) { 1385 writer.databuf.appendChar(offsetDelta); 1386 if (writer.debugstackmap){ 1387 System.out.print(" offset_delta=" + offsetDelta); 1388 } 1389 } 1390 } 1391 } 1392 1393 static class SameLocals1StackItemFrame extends StackMapTableFrame { 1394 final int offsetDelta; 1395 final Type stack; 1396 SameLocals1StackItemFrame(int offsetDelta, Type stack) { 1397 this.offsetDelta = offsetDelta; 1398 this.stack = stack; 1399 } 1400 int getFrameType() { 1401 return (offsetDelta < SAME_FRAME_SIZE) ? 1402 (SAME_FRAME_SIZE + offsetDelta) : 1403 SAME_LOCALS_1_STACK_ITEM_EXTENDED; 1404 } 1405 @Override 1406 void write(ClassWriter writer) { 1407 super.write(writer); 1408 if (getFrameType() == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { 1409 writer.databuf.appendChar(offsetDelta); 1410 if (writer.debugstackmap) { 1411 System.out.print(" offset_delta=" + offsetDelta); 1412 } 1413 } 1414 if (writer.debugstackmap) { 1415 System.out.print(" stack[" + 0 + "]="); 1416 } 1417 writer.writeStackMapType(stack); 1418 } 1419 } 1420 1421 static class ChopFrame extends StackMapTableFrame { 1422 final int frameType; 1423 final int offsetDelta; 1424 ChopFrame(int frameType, int offsetDelta) { 1425 this.frameType = frameType; 1426 this.offsetDelta = offsetDelta; 1427 } 1428 int getFrameType() { return frameType; } 1429 @Override 1430 void write(ClassWriter writer) { 1431 super.write(writer); 1432 writer.databuf.appendChar(offsetDelta); 1433 if (writer.debugstackmap) { 1434 System.out.print(" offset_delta=" + offsetDelta); 1435 } 1436 } 1437 } 1438 1439 static class AppendFrame extends StackMapTableFrame { 1440 final int frameType; 1441 final int offsetDelta; 1442 final Type[] locals; 1443 AppendFrame(int frameType, int offsetDelta, Type[] locals) { 1444 this.frameType = frameType; 1445 this.offsetDelta = offsetDelta; 1446 this.locals = locals; 1447 } 1448 int getFrameType() { return frameType; } 1449 @Override 1450 void write(ClassWriter writer) { 1451 super.write(writer); 1452 writer.databuf.appendChar(offsetDelta); 1453 if (writer.debugstackmap) { 1454 System.out.print(" offset_delta=" + offsetDelta); 1455 } 1456 for (int i=0; i<locals.length; i++) { 1457 if (writer.debugstackmap) System.out.print(" locals[" + i + "]="); 1458 writer.writeStackMapType(locals[i]); 1459 } 1460 } 1461 } 1462 1463 static class FullFrame extends StackMapTableFrame { 1464 final int offsetDelta; 1465 final Type[] locals; 1466 final Type[] stack; 1467 FullFrame(int offsetDelta, Type[] locals, Type[] stack) { 1468 this.offsetDelta = offsetDelta; 1469 this.locals = locals; 1470 this.stack = stack; 1471 } 1472 int getFrameType() { return FULL_FRAME; } 1473 @Override 1474 void write(ClassWriter writer) { 1475 super.write(writer); 1476 writer.databuf.appendChar(offsetDelta); 1477 writer.databuf.appendChar(locals.length); 1478 if (writer.debugstackmap) { 1479 System.out.print(" offset_delta=" + offsetDelta); 1480 System.out.print(" nlocals=" + locals.length); 1481 } 1482 for (int i=0; i<locals.length; i++) { 1483 if (writer.debugstackmap) System.out.print(" locals[" + i + "]="); 1484 writer.writeStackMapType(locals[i]); 1485 } 1486 1487 writer.databuf.appendChar(stack.length); 1488 if (writer.debugstackmap) { System.out.print(" nstack=" + stack.length); } 1489 for (int i=0; i<stack.length; i++) { 1490 if (writer.debugstackmap) System.out.print(" stack[" + i + "]="); 1491 writer.writeStackMapType(stack[i]); 1492 } 1493 } 1494 } 1495 1496 /** Compare this frame with the previous frame and produce 1497 * an entry of compressed stack map frame. */ 1498 static StackMapTableFrame getInstance(Code.StackMapFrame this_frame, 1499 int prev_pc, 1500 Type[] prev_locals, 1501 Types types) { 1502 Type[] locals = this_frame.locals; 1503 Type[] stack = this_frame.stack; 1504 int offset_delta = this_frame.pc - prev_pc - 1; 1505 if (stack.length == 1) { 1506 if (locals.length == prev_locals.length 1507 && compare(prev_locals, locals, types) == 0) { 1508 return new SameLocals1StackItemFrame(offset_delta, stack[0]); 1509 } 1510 } else if (stack.length == 0) { 1511 int diff_length = compare(prev_locals, locals, types); 1512 if (diff_length == 0) { 1513 return new SameFrame(offset_delta); 1514 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) { 1515 // APPEND 1516 Type[] local_diff = new Type[-diff_length]; 1517 for (int i=prev_locals.length, j=0; i<locals.length; i++,j++) { 1518 local_diff[j] = locals[i]; 1519 } 1520 return new AppendFrame(SAME_FRAME_EXTENDED - diff_length, 1521 offset_delta, 1522 local_diff); 1523 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) { 1524 // CHOP 1525 return new ChopFrame(SAME_FRAME_EXTENDED - diff_length, 1526 offset_delta); 1527 } 1528 } 1529 // FULL_FRAME 1530 return new FullFrame(offset_delta, locals, stack); 1531 } 1532 1533 static boolean isInt(Type t) { 1534 return (t.getTag().isStrictSubRangeOf(INT) || t.hasTag(BOOLEAN)); 1535 } 1536 1537 static boolean isSameType(Type t1, Type t2, Types types) { 1538 if (t1 == null) { return t2 == null; } 1539 if (t2 == null) { return false; } 1540 1541 if (isInt(t1) && isInt(t2)) { return true; } 1542 1543 if (t1.hasTag(UNINITIALIZED_THIS)) { 1544 return t2.hasTag(UNINITIALIZED_THIS); 1545 } else if (t1.hasTag(UNINITIALIZED_OBJECT)) { 1546 if (t2.hasTag(UNINITIALIZED_OBJECT)) { 1547 return ((UninitializedType)t1).offset == ((UninitializedType)t2).offset; 1548 } else { 1549 return false; 1550 } 1551 } else if (t2.hasTag(UNINITIALIZED_THIS) || t2.hasTag(UNINITIALIZED_OBJECT)) { 1552 return false; 1553 } 1554 1555 return types.isSameType(t1, t2); 1556 } 1557 1558 static int compare(Type[] arr1, Type[] arr2, Types types) { 1559 int diff_length = arr1.length - arr2.length; 1560 if (diff_length > MAX_LOCAL_LENGTH_DIFF || diff_length < -MAX_LOCAL_LENGTH_DIFF) { 1561 return Integer.MAX_VALUE; 1562 } 1563 int len = (diff_length > 0) ? arr2.length : arr1.length; 1564 for (int i=0; i<len; i++) { 1565 if (!isSameType(arr1[i], arr2[i], types)) { 1566 return Integer.MAX_VALUE; 1567 } 1568 } 1569 return diff_length; 1570 } 1571 } 1572 1573 void writeFields(Scope.Entry e) { 1574 // process them in reverse sibling order; 1575 // i.e., process them in declaration order. 1576 List<VarSymbol> vars = List.nil(); 1577 for (Scope.Entry i = e; i != null; i = i.sibling) { 1578 if (i.sym.kind == VAR) vars = vars.prepend((VarSymbol)i.sym); 1579 } 1580 while (vars.nonEmpty()) { 1581 writeField(vars.head); 1582 vars = vars.tail; 1583 } 1584 } 1585 1586 void writeMethods(Scope.Entry e) { 1587 List<MethodSymbol> methods = List.nil(); 1588 for (Scope.Entry i = e; i != null; i = i.sibling) { 1589 if (i.sym.kind == MTH && (i.sym.flags() & HYPOTHETICAL) == 0) 1590 methods = methods.prepend((MethodSymbol)i.sym); 1591 } 1592 while (methods.nonEmpty()) { 1593 writeMethod(methods.head); 1594 methods = methods.tail; 1595 } 1596 } 1597 1598 /** Emit a class file for a given class. 1599 * @param c The class from which a class file is generated. 1600 */ 1601 public JavaFileObject writeClass(ClassSymbol c) 1602 throws IOException, PoolOverflow, StringOverflow 1603 { 1604 JavaFileObject outFile 1605 = fileManager.getJavaFileForOutput(CLASS_OUTPUT, 1606 c.flatname.toString(), 1607 JavaFileObject.Kind.CLASS, 1608 c.sourcefile); 1609 OutputStream out = outFile.openOutputStream(); 1610 try { 1611 writeClassFile(out, c); 1612 if (verbose) 1613 log.printVerbose("wrote.file", outFile); 1614 out.close(); 1615 out = null; 1616 } finally { 1617 if (out != null) { 1618 // if we are propagating an exception, delete the file 1619 out.close(); 1620 outFile.delete(); 1621 outFile = null; 1622 } 1623 } 1624 return outFile; // may be null if write failed 1625 } 1626 1627 /** Write class `c' to outstream `out'. 1628 */ 1629 public void writeClassFile(OutputStream out, ClassSymbol c) 1630 throws IOException, PoolOverflow, StringOverflow { 1631 Assert.check((c.flags() & COMPOUND) == 0); 1632 databuf.reset(); 1633 poolbuf.reset(); 1634 signatureGen.reset(); 1635 pool = c.pool; 1636 innerClasses = null; 1637 innerClassesQueue = null; 1638 bootstrapMethods = new LinkedHashMap<DynamicMethod, MethodHandle>(); 1639 1640 Type supertype = types.supertype(c.type); 1641 List<Type> interfaces = types.interfaces(c.type); 1642 List<Type> typarams = c.type.getTypeArguments(); 1643 1644 int flags = adjustFlags(c.flags() & ~DEFAULT); 1645 if ((flags & PROTECTED) != 0) flags |= PUBLIC; 1646 flags = flags & ClassFlags & ~STRICTFP; 1647 if ((flags & INTERFACE) == 0) flags |= ACC_SUPER; 1648 if (c.isInner() && c.name.isEmpty()) flags &= ~FINAL; 1649 if (dumpClassModifiers) { 1650 PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); 1651 pw.println(); 1652 pw.println("CLASSFILE " + c.getQualifiedName()); 1653 pw.println("---" + flagNames(flags)); 1654 } 1655 databuf.appendChar(flags); 1656 1657 databuf.appendChar(pool.put(c)); 1658 databuf.appendChar(supertype.hasTag(CLASS) ? pool.put(supertype.tsym) : 0); 1659 databuf.appendChar(interfaces.length()); 1660 for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail) 1661 databuf.appendChar(pool.put(l.head.tsym)); 1662 int fieldsCount = 0; 1663 int methodsCount = 0; 1664 for (Scope.Entry e = c.members().elems; e != null; e = e.sibling) { 1665 switch (e.sym.kind) { 1666 case VAR: fieldsCount++; break; 1667 case MTH: if ((e.sym.flags() & HYPOTHETICAL) == 0) methodsCount++; 1668 break; 1669 case TYP: enterInner((ClassSymbol)e.sym); break; 1670 default : Assert.error(); 1671 } 1672 } 1673 1674 if (c.trans_local != null) { 1675 for (ClassSymbol local : c.trans_local) { 1676 enterInner(local); 1677 } 1678 } 1679 1680 databuf.appendChar(fieldsCount); 1681 writeFields(c.members().elems); 1682 databuf.appendChar(methodsCount); 1683 writeMethods(c.members().elems); 1684 1685 int acountIdx = beginAttrs(); 1686 int acount = 0; 1687 1688 boolean sigReq = 1689 typarams.length() != 0 || supertype.allparams().length() != 0; 1690 for (List<Type> l = interfaces; !sigReq && l.nonEmpty(); l = l.tail) 1691 sigReq = l.head.allparams().length() != 0; 1692 if (sigReq) { 1693 Assert.check(source.allowGenerics()); 1694 int alenIdx = writeAttr(names.Signature); 1695 if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams); 1696 signatureGen.assembleSig(supertype); 1697 for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail) 1698 signatureGen.assembleSig(l.head); 1699 databuf.appendChar(pool.put(signatureGen.toName())); 1700 signatureGen.reset(); 1701 endAttr(alenIdx); 1702 acount++; 1703 } 1704 1705 if (c.sourcefile != null && emitSourceFile) { 1706 int alenIdx = writeAttr(names.SourceFile); 1707 // WHM 6/29/1999: Strip file path prefix. We do it here at 1708 // the last possible moment because the sourcefile may be used 1709 // elsewhere in error diagnostics. Fixes 4241573. 1710 //databuf.appendChar(c.pool.put(c.sourcefile)); 1711 String simpleName = BaseFileObject.getSimpleName(c.sourcefile); 1712 databuf.appendChar(c.pool.put(names.fromString(simpleName))); 1713 endAttr(alenIdx); 1714 acount++; 1715 } 1716 1717 if (genCrt) { 1718 // Append SourceID attribute 1719 int alenIdx = writeAttr(names.SourceID); 1720 databuf.appendChar(c.pool.put(names.fromString(Long.toString(getLastModified(c.sourcefile))))); 1721 endAttr(alenIdx); 1722 acount++; 1723 // Append CompilationID attribute 1724 alenIdx = writeAttr(names.CompilationID); 1725 databuf.appendChar(c.pool.put(names.fromString(Long.toString(System.currentTimeMillis())))); 1726 endAttr(alenIdx); 1727 acount++; 1728 } 1729 1730 acount += writeFlagAttrs(c.flags()); 1731 acount += writeJavaAnnotations(c.getRawAttributes()); 1732 acount += writeTypeAnnotations(c.getRawTypeAttributes(), false); 1733 acount += writeEnclosingMethodAttribute(c); 1734 acount += writeExtraClassAttributes(c); 1735 1736 poolbuf.appendInt(JAVA_MAGIC); 1737 poolbuf.appendChar(target.minorVersion); 1738 poolbuf.appendChar(target.majorVersion); 1739 1740 writePool(c.pool); 1741 1742 if (innerClasses != null) { 1743 writeInnerClasses(); 1744 acount++; 1745 } 1746 1747 if (!bootstrapMethods.isEmpty()) { 1748 writeBootstrapMethods(); 1749 acount++; 1750 } 1751 1752 endAttrs(acountIdx, acount); 1753 1754 poolbuf.appendBytes(databuf.elems, 0, databuf.length); 1755 out.write(poolbuf.elems, 0, poolbuf.length); 1756 1757 pool = c.pool = null; // to conserve space 1758 } 1759 1760 /**Allows subclasses to write additional class attributes 1761 * 1762 * @return the number of attributes written 1763 */ 1764 protected int writeExtraClassAttributes(ClassSymbol c) { 1765 return 0; 1766 } 1767 1768 int adjustFlags(final long flags) { 1769 int result = (int)flags; 1770 if ((flags & SYNTHETIC) != 0 && !target.useSyntheticFlag()) 1771 result &= ~SYNTHETIC; 1772 if ((flags & ENUM) != 0 && !target.useEnumFlag()) 1773 result &= ~ENUM; 1774 if ((flags & ANNOTATION) != 0 && !target.useAnnotationFlag()) 1775 result &= ~ANNOTATION; 1776 1777 if ((flags & BRIDGE) != 0 && target.useBridgeFlag()) 1778 result |= ACC_BRIDGE; 1779 if ((flags & VARARGS) != 0 && target.useVarargsFlag()) 1780 result |= ACC_VARARGS; 1781 if ((flags & DEFAULT) != 0) 1782 result &= ~ABSTRACT; 1783 return result; 1784 } 1785 1786 long getLastModified(FileObject filename) { 1787 long mod = 0; 1788 try { 1789 mod = filename.getLastModified(); 1790 } catch (SecurityException e) { 1791 throw new AssertionError("CRT: couldn't get source file modification date: " + e.getMessage()); 1792 } 1793 return mod; 1794 } 1795 }