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 com.sun.tools.javac.code.Kinds.Kind;
29 import com.sun.tools.javac.code.Symbol;
30 import com.sun.tools.javac.code.Symbol.ClassSymbol;
31 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
32 import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
33 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
34 import com.sun.tools.javac.code.Symbol.PackageSymbol;
35 import com.sun.tools.javac.code.Type;
36 import com.sun.tools.javac.code.Types;
37 import com.sun.tools.javac.jvm.ClassWriter.PoolOverflow;
38 import com.sun.tools.javac.jvm.ClassWriter.StringOverflow;
39 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
40 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant;
41 import com.sun.tools.javac.jvm.PoolConstant.Dynamic;
42 import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
43 import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
44 import com.sun.tools.javac.util.ByteBuffer;
45 import com.sun.tools.javac.util.List;
46 import com.sun.tools.javac.util.Name;
47 import com.sun.tools.javac.util.Names;
48
49 import java.io.IOException;
50 import java.io.OutputStream;
51 import java.util.ArrayDeque;
52 import java.util.HashMap;
53 import java.util.LinkedHashMap;
54 import java.util.LinkedHashSet;
55 import java.util.Map;
56
57 import static com.sun.tools.javac.code.Kinds.Kind.TYP;
58 import static com.sun.tools.javac.code.TypeTag.ARRAY;
59 import static com.sun.tools.javac.code.TypeTag.CLASS;
60 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
61 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
62 import static com.sun.tools.javac.jvm.ClassFile.externalize;
63
64 /**
65 * Pool interface towards {@code ClassWriter}. Exposes methods to encode and write javac entities
66 * into the constant pool.
67 *
68 * <p><b>This is NOT part of any supported API.
69 * If you write code that depends on this, you do so at your own risk.
70 * This code and its internal interfaces are subject to change or
71 * deletion without notice.</b>
72 */
73 public class PoolWriter {
74
75 /** Max number of constant pool entries. */
76 public static final int MAX_ENTRIES = 0xFFFF;
77
78 /** Max number of char in a string constant. */
79 public static final int MAX_STRING_LENGTH = 0xFFFF;
80
81 private static final int POOL_BUF_SIZE = 0x7fff;
82
83 private final Types types;
84
85 private final Names names;
86
87 /** Pool helper **/
88 final WriteablePoolHelper pool;
89
90 /** Sole signature generator */
91 final SharedSignatureGenerator signatureGen;
92
93 /** The inner classes to be written, as an ordered set (enclosing first). */
94 LinkedHashSet<ClassSymbol> innerClasses = new LinkedHashSet<>();
95
96 /** The list of entries in the BootstrapMethods attribute. */
97 Map<BsmKey, Integer> bootstrapMethods = new LinkedHashMap<>();
98
99 public PoolWriter(Types types, Names names) {
100 this.types = types;
101 this.names = names;
102 this.signatureGen = new SharedSignatureGenerator(types);
103 this.pool = new WriteablePoolHelper();
104 }
105
106 /**
107 * Puts a class symbol into the pool and return its index.
108 */
109 int putClass(ClassSymbol csym) {
110 return putClass(csym.type);
111 }
112
113 /**
114 * Puts a type into the pool and return its index. The type could be either a class, a type variable
115 * or an array type.
116 */
117 int putClass(Type t) {
118 return pool.writeIfNeeded(types.erasure(t));
119 }
120
121 /**
122 * Puts a member reference into the constant pool. Valid members are either field or method symbols.
123 */
124 int putMember(Symbol s) {
125 return pool.writeIfNeeded(s);
126 }
127
128 /**
129 * Puts a dynamic reference into the constant pool and return its index.
130 */
131 int putDynamic(Dynamic d) {
132 return pool.writeIfNeeded(d);
133 }
134
135 /**
136 * Puts a field or method descriptor into the constant pool and return its index.
137 */
138 int putDescriptor(Type t) {
139 return putName(typeSig(types.erasure(t)));
140 }
203 return pool.writeIfNeeded(new NameAndType(s.name, descriptorType(s)));
204 }
205
206 /**
207 * Puts a package entry into the pool and returns its index.
208 */
209 int putPackage(PackageSymbol pkg) {
210 return pool.writeIfNeeded(pkg);
211 }
212
213 /**
214 * Puts a module entry into the pool and returns its index.
215 */
216 int putModule(ModuleSymbol mod) {
217 return pool.writeIfNeeded(mod);
218 }
219
220 /**
221 * Enter an inner class into the `innerClasses' set.
222 */
223 void enterInner(ClassSymbol c) {
224 if (c.type.isCompound()) {
225 throw new AssertionError("Unexpected intersection type: " + c.type);
226 }
227 c.complete();
228 if (c.owner.enclClass() != null && !innerClasses.contains(c)) {
229 enterInner(c.owner.enclClass());
230 innerClasses.add(c);
231 }
232 }
233
234 /**
235 * Create a new Utf8 entry representing a descriptor for given (member) symbol.
236 */
237 private Type descriptorType(Symbol s) {
238 return s.kind == Kind.MTH ? s.externalType(types) : s.erasure(types);
239 }
240
241 private int makeBootstrapEntry(Dynamic dynamic) {
242 BsmKey bsmKey = dynamic.bsmKey(types);
243
244 // Figure out the index for existing BSM; create a new BSM if no key
245 Integer index = bootstrapMethods.get(bsmKey);
246 if (index == null) {
247 index = bootstrapMethods.size();
248 bootstrapMethods.put(bsmKey, index);
249 }
250
251 return index;
252 }
253
299 }
300 }
301
302 @Override
303 protected void append(char ch) {
304 sigbuf.appendByte(ch);
305 }
306
307 @Override
308 protected void append(byte[] ba) {
309 sigbuf.appendBytes(ba);
310 }
311
312 @Override
313 protected void append(Name name) {
314 sigbuf.appendName(name);
315 }
316
317 @Override
318 protected void classReference(ClassSymbol c) {
319 enterInner(c);
320 }
321
322 protected void reset() {
323 sigbuf.reset();
324 }
325
326 protected Name toName() {
327 return sigbuf.toName(names);
328 }
329 }
330
331 class WriteablePoolHelper {
332
333 /** Pool entries. */
334 private final Map<Object, Integer> keysToPos = new HashMap<>(64);
335
336 final ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
337
338 int currentIndex = 1;
339
345 Object key = p.poolKey(types);
346 Integer index = keysToPos.get(key);
347 if (index == null) {
348 keysToPos.put(key, index = currentIndex++);
349 boolean first = todo.isEmpty();
350 todo.addLast(p);
351 if (first) {
352 while (!todo.isEmpty()) {
353 writeConstant(todo.peekFirst());
354 todo.removeFirst();
355 }
356 }
357 }
358 return index;
359 }
360
361 void writeConstant(PoolConstant c) {
362 int tag = c.poolTag();
363 switch (tag) {
364 case ClassFile.CONSTANT_Class: {
365 Type ct = (Type)c;
366 Name name = ct.hasTag(ARRAY) ?
367 typeSig(ct) :
368 names.fromUtf(externalize(ct.tsym.flatName()));
369 poolbuf.appendByte(tag);
370 poolbuf.appendChar(putName(name));
371 if (ct.hasTag(CLASS)) {
372 enterInner((ClassSymbol)ct.tsym);
373 }
374 break;
375 }
376 case ClassFile.CONSTANT_Utf8: {
377 Name name = (Name)c;
378 poolbuf.appendByte(tag);
379 byte[] bs = name.toUtf();
380 poolbuf.appendChar(bs.length);
381 poolbuf.appendBytes(bs, 0, bs.length);
382 if (overflowString == null && bs.length > MAX_STRING_LENGTH) {
383 //report error only once
384 overflowString = new String(bs);
385 }
386 break;
387 }
388 case ClassFile.CONSTANT_InterfaceMethodref:
389 case ClassFile.CONSTANT_Methodref:
390 case ClassFile.CONSTANT_Fieldref: {
391 Symbol sym = (Symbol)c;
392 poolbuf.appendByte(tag);
485 }
486
487 /**
488 * Return signature of given type
489 */
490 private Name typeSig(Type type) {
491 signatureGen.reset();
492 signatureGen.assembleSig(type);
493 return signatureGen.toName();
494 }
495
496 private Name classSig(Type t) {
497 signatureGen.reset();
498 List<Type> typarams = t.getTypeArguments();
499 if (typarams.nonEmpty()) {
500 signatureGen.assembleParamsSig(typarams);
501 }
502 signatureGen.assembleSig(types.supertype(t));
503 for (Type i : types.interfaces(t))
504 signatureGen.assembleSig(i);
505 return signatureGen.toName();
506 }
507
508 void reset() {
509 innerClasses.clear();
510 bootstrapMethods.clear();
511 pool.reset();
512 }
513 }
|
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 com.sun.tools.javac.code.Kinds.Kind;
29 import com.sun.tools.javac.code.Symbol;
30 import com.sun.tools.javac.code.Symbol.ClassSymbol;
31 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
32 import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
33 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
34 import com.sun.tools.javac.code.Symbol.PackageSymbol;
35 import com.sun.tools.javac.code.Type;
36 import com.sun.tools.javac.code.Type.ConstantPoolQType;
37 import com.sun.tools.javac.code.Types;
38 import com.sun.tools.javac.jvm.ClassWriter.PoolOverflow;
39 import com.sun.tools.javac.jvm.ClassWriter.StringOverflow;
40 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
41 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant;
42 import com.sun.tools.javac.jvm.PoolConstant.Dynamic;
43 import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
44 import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
45 import com.sun.tools.javac.util.ByteBuffer;
46 import com.sun.tools.javac.util.List;
47 import com.sun.tools.javac.util.Name;
48 import com.sun.tools.javac.util.Names;
49
50 import java.io.IOException;
51 import java.io.OutputStream;
52 import java.util.ArrayDeque;
53 import java.util.HashMap;
54 import java.util.HashSet;
55 import java.util.LinkedHashMap;
56 import java.util.LinkedHashSet;
57 import java.util.Map;
58 import java.util.Set;
59
60 import static com.sun.tools.javac.code.Kinds.Kind.TYP;
61 import static com.sun.tools.javac.code.TypeTag.ARRAY;
62 import static com.sun.tools.javac.code.TypeTag.CLASS;
63 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
64 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
65 import static com.sun.tools.javac.jvm.ClassFile.externalize;
66
67 /**
68 * Pool interface towards {@code ClassWriter}. Exposes methods to encode and write javac entities
69 * into the constant pool.
70 *
71 * <p><b>This is NOT part of any supported API.
72 * If you write code that depends on this, you do so at your own risk.
73 * This code and its internal interfaces are subject to change or
74 * deletion without notice.</b>
75 */
76 public class PoolWriter {
77
78 /** Max number of constant pool entries. */
79 public static final int MAX_ENTRIES = 0xFFFF;
80
81 /** Max number of char in a string constant. */
82 public static final int MAX_STRING_LENGTH = 0xFFFF;
83
84 private static final int POOL_BUF_SIZE = 0x7fff;
85
86 private final Types types;
87
88 private final Names names;
89
90 /** Pool helper **/
91 final WriteablePoolHelper pool;
92
93 /** Sole signature generator */
94 final SharedSignatureGenerator signatureGen;
95
96 /** The inner classes to be written, as an ordered set (enclosing first). */
97 LinkedHashSet<ClassSymbol> innerClasses = new LinkedHashSet<>();
98
99 Set<ClassSymbol> preloadClasses = new HashSet<>();
100
101 /** The list of entries in the BootstrapMethods attribute. */
102 Map<BsmKey, Integer> bootstrapMethods = new LinkedHashMap<>();
103
104 public PoolWriter(Types types, Names names) {
105 this.types = types;
106 this.names = names;
107 this.signatureGen = new SharedSignatureGenerator(types);
108 this.pool = new WriteablePoolHelper();
109 }
110
111 /**
112 * Puts a class symbol into the pool and return its index.
113 */
114 int putClass(ClassSymbol csym) {
115 return putClass(csym.type);
116 }
117
118 /**
119 * Puts a type into the pool and return its index. The type could be either a class, a type variable
120 * or an array type.
121 */
122 int putClass(Type t) {
123 /* Their is nothing to be gained by having the pair of class types Foo.ref and Foo.val
124 result in two different CONSTANT_Class_info strucures in the pool. These are
125 indistinguishable at the class file level. Hence we coalesce them here.
126 */
127 if (t.isReferenceProjection())
128 t = t.valueProjection();
129 return pool.writeIfNeeded(types.erasure(t));
130 }
131
132 /**
133 * Puts a type into the pool and return its index. The type could be either a class, a type variable
134 * or an array type.
135 */
136 int putClass(ConstantPoolQType t) {
137 return pool.writeIfNeeded(t);
138 }
139
140 /**
141 * Puts a member reference into the constant pool. Valid members are either field or method symbols.
142 */
143 int putMember(Symbol s) {
144 return pool.writeIfNeeded(s);
145 }
146
147 /**
148 * Puts a dynamic reference into the constant pool and return its index.
149 */
150 int putDynamic(Dynamic d) {
151 return pool.writeIfNeeded(d);
152 }
153
154 /**
155 * Puts a field or method descriptor into the constant pool and return its index.
156 */
157 int putDescriptor(Type t) {
158 return putName(typeSig(types.erasure(t)));
159 }
222 return pool.writeIfNeeded(new NameAndType(s.name, descriptorType(s)));
223 }
224
225 /**
226 * Puts a package entry into the pool and returns its index.
227 */
228 int putPackage(PackageSymbol pkg) {
229 return pool.writeIfNeeded(pkg);
230 }
231
232 /**
233 * Puts a module entry into the pool and returns its index.
234 */
235 int putModule(ModuleSymbol mod) {
236 return pool.writeIfNeeded(mod);
237 }
238
239 /**
240 * Enter an inner class into the `innerClasses' set.
241 */
242 void enterInnerClass(ClassSymbol c) {
243 if (c.type.isCompound()) {
244 throw new AssertionError("Unexpected intersection type: " + c.type);
245 }
246 c.complete();
247 if (c.owner.enclClass() != null && !innerClasses.contains(c)) {
248 enterInnerClass(c.owner.enclClass());
249 innerClasses.add(c);
250 }
251 }
252
253 /** Enter a value class into the `preloadClasses' set.
254 */
255 void enterPreloadClass(ClassSymbol c) {
256 if (c.type.isCompound()) {
257 throw new AssertionError("Unexpected intersection type: " + c.type);
258 }
259 c.complete();
260 preloadClasses.add(c);
261 }
262
263 /**
264 * Create a new Utf8 entry representing a descriptor for given (member) symbol.
265 */
266 private Type descriptorType(Symbol s) {
267 return s.kind == Kind.MTH ? s.externalType(types) : s.erasure(types);
268 }
269
270 private int makeBootstrapEntry(Dynamic dynamic) {
271 BsmKey bsmKey = dynamic.bsmKey(types);
272
273 // Figure out the index for existing BSM; create a new BSM if no key
274 Integer index = bootstrapMethods.get(bsmKey);
275 if (index == null) {
276 index = bootstrapMethods.size();
277 bootstrapMethods.put(bsmKey, index);
278 }
279
280 return index;
281 }
282
328 }
329 }
330
331 @Override
332 protected void append(char ch) {
333 sigbuf.appendByte(ch);
334 }
335
336 @Override
337 protected void append(byte[] ba) {
338 sigbuf.appendBytes(ba);
339 }
340
341 @Override
342 protected void append(Name name) {
343 sigbuf.appendName(name);
344 }
345
346 @Override
347 protected void classReference(ClassSymbol c) {
348 enterInnerClass(c);
349 }
350
351 protected void reset() {
352 sigbuf.reset();
353 }
354
355 protected Name toName() {
356 return sigbuf.toName(names);
357 }
358 }
359
360 class WriteablePoolHelper {
361
362 /** Pool entries. */
363 private final Map<Object, Integer> keysToPos = new HashMap<>(64);
364
365 final ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
366
367 int currentIndex = 1;
368
374 Object key = p.poolKey(types);
375 Integer index = keysToPos.get(key);
376 if (index == null) {
377 keysToPos.put(key, index = currentIndex++);
378 boolean first = todo.isEmpty();
379 todo.addLast(p);
380 if (first) {
381 while (!todo.isEmpty()) {
382 writeConstant(todo.peekFirst());
383 todo.removeFirst();
384 }
385 }
386 }
387 return index;
388 }
389
390 void writeConstant(PoolConstant c) {
391 int tag = c.poolTag();
392 switch (tag) {
393 case ClassFile.CONSTANT_Class: {
394 Type ct = c instanceof ConstantPoolQType ? ((ConstantPoolQType)c).type : (Type)c;
395 Name name = ct.hasTag(ARRAY) ?
396 typeSig(ct) :
397 c instanceof ConstantPoolQType ? names.fromString("Q" + new String(externalize(ct.tsym.flatName())) + ";") : names.fromUtf(externalize(ct.tsym.flatName()));
398 poolbuf.appendByte(tag);
399 poolbuf.appendChar(putName(name));
400 if (ct.hasTag(CLASS)) {
401 enterInnerClass((ClassSymbol)ct.tsym);
402 }
403 break;
404 }
405 case ClassFile.CONSTANT_Utf8: {
406 Name name = (Name)c;
407 poolbuf.appendByte(tag);
408 byte[] bs = name.toUtf();
409 poolbuf.appendChar(bs.length);
410 poolbuf.appendBytes(bs, 0, bs.length);
411 if (overflowString == null && bs.length > MAX_STRING_LENGTH) {
412 //report error only once
413 overflowString = new String(bs);
414 }
415 break;
416 }
417 case ClassFile.CONSTANT_InterfaceMethodref:
418 case ClassFile.CONSTANT_Methodref:
419 case ClassFile.CONSTANT_Fieldref: {
420 Symbol sym = (Symbol)c;
421 poolbuf.appendByte(tag);
514 }
515
516 /**
517 * Return signature of given type
518 */
519 private Name typeSig(Type type) {
520 signatureGen.reset();
521 signatureGen.assembleSig(type);
522 return signatureGen.toName();
523 }
524
525 private Name classSig(Type t) {
526 signatureGen.reset();
527 List<Type> typarams = t.getTypeArguments();
528 if (typarams.nonEmpty()) {
529 signatureGen.assembleParamsSig(typarams);
530 }
531 signatureGen.assembleSig(types.supertype(t));
532 for (Type i : types.interfaces(t))
533 signatureGen.assembleSig(i);
534
535 return signatureGen.toName();
536 }
537
538 void reset() {
539 innerClasses.clear();
540 preloadClasses.clear();
541 bootstrapMethods.clear();
542 pool.reset();
543 }
544 }
|