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