8222289: Overhaul logic for reading/writing constant pool entries

Rewrite of Pool,ClassReader,ClassWriter to use shared pool helper components

Reviewed-by: vromero
This commit is contained in:
Maurizio Cimadamore 2019-04-17 15:37:20 +01:00
parent dce0c5c4ae
commit 7b7f9a6fd3
31 changed files with 1802 additions and 1630 deletions

@ -55,6 +55,7 @@ import com.sun.tools.javac.comp.Attr;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.jvm.*;
import com.sun.tools.javac.jvm.PoolConstant;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.Tag;
@ -91,7 +92,7 @@ import com.sun.tools.javac.util.Name;
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public abstract class Symbol extends AnnoConstruct implements Element {
public abstract class Symbol extends AnnoConstruct implements PoolConstant, Element {
/** The kind of this symbol.
* @see Kinds
@ -286,6 +287,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
this.name = name;
}
@Override
public int poolTag() {
throw new AssertionError("Invalid pool entry");
}
/** Clone this symbol with new owner.
* Legal only for fields and methods.
*/
@ -971,6 +977,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
this.type = new ModuleType(this);
}
@Override
public int poolTag() {
return ClassFile.CONSTANT_Module;
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public Name getSimpleName() {
return Convert.shortName(name);
@ -1137,6 +1148,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
return members_field;
}
@Override
public int poolTag() {
return ClassFile.CONSTANT_Package;
}
public long flags() {
complete();
return flags_field;
@ -1237,10 +1253,6 @@ public abstract class Symbol extends AnnoConstruct implements Element {
*/
public List<ClassSymbol> trans_local;
/** the constant pool of the class
*/
public Pool pool;
/** the annotation metadata attached to this class */
private AnnotationTypeMetadata annotationTypeMetadata;
@ -1251,7 +1263,6 @@ public abstract class Symbol extends AnnoConstruct implements Element {
this.flatname = formFlatName(name, owner);
this.sourcefile = null;
this.classfile = null;
this.pool = null;
this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
}
@ -1543,6 +1554,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
super(VAR, flags, name, type, owner);
}
@Override
public int poolTag() {
return ClassFile.CONSTANT_Fieldref;
}
/** Clone this symbol with new owner.
*/
public VarSymbol clone(Symbol newOwner) {
@ -1551,6 +1567,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
public Symbol baseSymbol() {
return VarSymbol.this;
}
@Override
public Object poolKey(Types types) {
return new Pair<>(newOwner, baseSymbol());
}
};
v.pos = pos;
v.adr = adr;
@ -1711,6 +1732,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
public Symbol baseSymbol() {
return MethodSymbol.this;
}
@Override
public Object poolKey(Types types) {
return new Pair<>(newOwner, baseSymbol());
}
};
m.code = code;
return m;
@ -1740,10 +1766,25 @@ public abstract class Symbol extends AnnoConstruct implements Element {
}
}
@Override
public int poolTag() {
return owner.isInterface() ?
ClassFile.CONSTANT_InterfaceMethodref : ClassFile.CONSTANT_Methodref;
}
public boolean isDynamic() {
return false;
}
public boolean isHandle() {
return false;
}
public MethodHandleSymbol asHandle() {
return new MethodHandleSymbol(this);
}
/** find a symbol that this (proxy method) symbol implements.
* @param c The class whose members are searched for
* implementations
@ -2027,16 +2068,14 @@ public abstract class Symbol extends AnnoConstruct implements Element {
/** A class for invokedynamic method calls.
*/
public static class DynamicMethodSymbol extends MethodSymbol {
public static class DynamicMethodSymbol extends MethodSymbol implements Dynamic {
public Object[] staticArgs;
public Symbol bsm;
public int bsmKind;
public LoadableConstant[] staticArgs;
public MethodHandleSymbol bsm;
public DynamicMethodSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) {
public DynamicMethodSymbol(Name name, Symbol owner, MethodHandleSymbol bsm, Type type, LoadableConstant[] staticArgs) {
super(0, name, type, owner);
this.bsm = bsm;
this.bsmKind = bsmKind;
this.staticArgs = staticArgs;
}
@ -2044,6 +2083,83 @@ public abstract class Symbol extends AnnoConstruct implements Element {
public boolean isDynamic() {
return true;
}
@Override
public LoadableConstant[] staticArgs() {
return staticArgs;
}
@Override
public MethodHandleSymbol bootstrapMethod() {
return bsm;
}
@Override
public int poolTag() {
return ClassFile.CONSTANT_InvokeDynamic;
}
@Override
public Type dynamicType() {
return type;
}
}
/** A class for method handles.
*/
public static class MethodHandleSymbol extends MethodSymbol implements LoadableConstant {
private Symbol refSym;
public MethodHandleSymbol(Symbol msym) {
super(msym.flags_field, msym.name, msym.type, msym.owner);
this.refSym = msym;
}
/**
* Returns the kind associated with this method handle.
*/
public int referenceKind() {
if (refSym.isConstructor()) {
return ClassFile.REF_newInvokeSpecial;
} else {
if (refSym.isStatic()) {
return ClassFile.REF_invokeStatic;
} else if ((refSym.flags() & PRIVATE) != 0) {
return ClassFile.REF_invokeSpecial;
} else if (refSym.enclClass().isInterface()) {
return ClassFile.REF_invokeInterface;
} else {
return ClassFile.REF_invokeVirtual;
}
}
}
@Override
public int poolTag() {
return ClassFile.CONSTANT_MethodHandle;
}
@Override
public Object poolKey(Types types) {
return new Pair<>(baseSymbol(), referenceKind());
}
@Override
public MethodHandleSymbol asHandle() {
return this;
}
@Override
public Symbol baseSymbol() {
return refSym;
}
@Override
public boolean isHandle() {
return true;
}
}
/** A class for predefined operators.

@ -36,7 +36,10 @@ import javax.lang.model.type.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.TypeMetadata.Entry;
import com.sun.tools.javac.code.Types.TypeMapping;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.comp.Infer.IncorporationAction;
import com.sun.tools.javac.jvm.ClassFile;
import com.sun.tools.javac.jvm.PoolConstant;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.DefinedBy.Api;
@ -73,7 +76,7 @@ import static com.sun.tools.javac.code.TypeTag.*;
*
* @see TypeTag
*/
public abstract class Type extends AnnoConstruct implements TypeMirror {
public abstract class Type extends AnnoConstruct implements TypeMirror, PoolConstant {
/**
* Type metadata, Should be {@code null} for the default value.
@ -125,6 +128,16 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
*/
public TypeSymbol tsym;
@Override
public int poolTag() {
throw new AssertionError("Invalid pool entry");
}
@Override
public Object poolKey(Types types) {
return new UniqueType(this, types);
}
/**
* Checks if the current type tag is equal to the given tag.
* @return true if tag is equal to the current type tag.
@ -930,7 +943,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
}
public static class ClassType extends Type implements DeclaredType,
public static class ClassType extends Type implements DeclaredType, LoadableConstant,
javax.lang.model.type.ErrorType {
/** The enclosing type of this type. If this is the type of an inner
@ -975,6 +988,10 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
this.interfaces_field = null;
}
public int poolTag() {
return ClassFile.CONSTANT_Class;
}
@Override
public ClassType cloneWithMetadata(TypeMetadata md) {
return new ClassType(outer_field, typarams_field, tsym, md) {
@ -1277,7 +1294,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
public static class ArrayType extends Type
implements javax.lang.model.type.ArrayType {
implements LoadableConstant, javax.lang.model.type.ArrayType {
public Type elemtype;
@ -1297,6 +1314,10 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
this(that.elemtype, that.tsym, that.getMetadata());
}
public int poolTag() {
return ClassFile.CONSTANT_Class;
}
@Override
public ArrayType cloneWithMetadata(TypeMetadata md) {
return new ArrayType(elemtype, tsym, md) {
@ -1412,7 +1433,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
}
public static class MethodType extends Type implements ExecutableType {
public static class MethodType extends Type implements ExecutableType, LoadableConstant {
public List<Type> argtypes;
public Type restype;
@ -1479,6 +1500,11 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
restype != null && restype.isErroneous();
}
@Override
public int poolTag() {
return ClassFile.CONSTANT_MethodType;
}
public boolean contains(Type elem) {
return elem.equalsIgnoreMetadata(this) || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem);
}

@ -48,6 +48,8 @@ import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Check;
import com.sun.tools.javac.comp.Enter;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.comp.LambdaToMethod;
import com.sun.tools.javac.jvm.ClassFile;
import com.sun.tools.javac.util.*;
import static com.sun.tools.javac.code.BoundKind.*;
@ -5181,6 +5183,29 @@ public class Types {
}
}
}
public Type constantType(LoadableConstant c) {
switch (c.poolTag()) {
case ClassFile.CONSTANT_Class:
return syms.classType;
case ClassFile.CONSTANT_String:
return syms.stringType;
case ClassFile.CONSTANT_Integer:
return syms.intType;
case ClassFile.CONSTANT_Float:
return syms.floatType;
case ClassFile.CONSTANT_Long:
return syms.longType;
case ClassFile.CONSTANT_Double:
return syms.doubleType;
case ClassFile.CONSTANT_MethodHandle:
return syms.methodHandleType;
case ClassFile.CONSTANT_MethodType:
return syms.methodTypeType;
default:
throw new AssertionError("Not a loadable constant: " + c.poolTag());
}
}
// </editor-fold>
public void newRound() {

@ -25,7 +25,9 @@
package com.sun.tools.javac.comp;
import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
import com.sun.tools.javac.tree.*;
@ -59,7 +61,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
@ -70,13 +71,10 @@ import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Kinds.Kind.*;
import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
import static com.sun.tools.javac.jvm.Pool.DynamicMethod;
import javax.lang.model.element.ElementKind;
import javax.lang.model.type.TypeKind;
import com.sun.tools.javac.code.Type.IntersectionClassType;
import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
import com.sun.tools.javac.main.Option;
/**
@ -214,7 +212,7 @@ public class LambdaToMethod extends TreeTranslator {
private Map<DedupedLambda, DedupedLambda> dedupedLambdas;
private Map<DynamicMethod, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
private Map<Object, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
/**
* list of deserialization cases
@ -439,11 +437,8 @@ public class LambdaToMethod extends TreeTranslator {
//then, determine the arguments to the indy call
List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
//build a sam instance using an indy call to the meta-factory
int refKind = referenceKind(sym);
//convert to an invokedynamic call
result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args);
}
// where
@ -488,7 +483,7 @@ public class LambdaToMethod extends TreeTranslator {
//first determine the method symbol to be used to generate the sam instance
//this is either the method reference symbol, or the bridged reference symbol
Symbol refSym = tree.sym;
MethodSymbol refSym = (MethodSymbol)tree.sym;
//the qualifying expression is treated as a special captured arg
JCExpression init;
@ -522,7 +517,7 @@ public class LambdaToMethod extends TreeTranslator {
//build a sam instance using an indy call to the meta-factory
result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args);
}
/**
@ -765,8 +760,8 @@ public class LambdaToMethod extends TreeTranslator {
rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
}
private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym,
DiagnosticPosition pos, List<LoadableConstant> staticArgs, MethodType indyType) {
String functionalInterfaceClass = classSig(targetType);
String functionalInterfaceMethodName = samSym.getSimpleName().toString();
String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
@ -774,7 +769,8 @@ public class LambdaToMethod extends TreeTranslator {
String implMethodName = refSym.getQualifiedName().toString();
String implMethodSignature = typeSig(types.erasure(refSym.type));
JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType),
make.Literal(refSym.referenceKind()));
ListBuffer<JCExpression> serArgs = new ListBuffer<>();
int i = 0;
for (Type t : indyType.getParameterTypes()) {
@ -1106,13 +1102,13 @@ public class LambdaToMethod extends TreeTranslator {
* Generate an indy method call to the meta factory
*/
private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
int refKind, Symbol refSym, List<JCExpression> indy_args) {
MethodHandleSymbol refSym, List<JCExpression> indy_args) {
JCFunctionalExpression tree = context.tree;
//determine the static bsm args
MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
List<Object> staticArgs = List.of(
List<LoadableConstant> staticArgs = List.of(
typeToMethodType(samSym.type),
new Pool.MethodHandle(refKind, refSym, types),
((MethodSymbol)refSym).asHandle(),
typeToMethodType(tree.getDescriptorType(types)));
//computed indy arg types
@ -1131,7 +1127,7 @@ public class LambdaToMethod extends TreeTranslator {
names.altMetafactory : names.metafactory;
if (context.needsAltMetafactory()) {
ListBuffer<Object> markers = new ListBuffer<>();
ListBuffer<Type> markers = new ListBuffer<>();
List<Type> targets = tree.target.isIntersection() ?
types.directSupertypes(tree.target) :
List.nil();
@ -1140,7 +1136,7 @@ public class LambdaToMethod extends TreeTranslator {
if (t.tsym != syms.serializableType.tsym &&
t.tsym != tree.type.tsym &&
t.tsym != syms.objectType.tsym) {
markers.append(t.tsym);
markers.append(t);
}
}
int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
@ -1152,17 +1148,17 @@ public class LambdaToMethod extends TreeTranslator {
if (hasBridges) {
flags |= FLAG_BRIDGES;
}
staticArgs = staticArgs.append(flags);
staticArgs = staticArgs.append(LoadableConstant.Int(flags));
if (hasMarkers) {
staticArgs = staticArgs.append(markers.length());
staticArgs = staticArgs.appendList(markers.toList());
staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
}
if (hasBridges) {
staticArgs = staticArgs.append(context.bridges.length() - 1);
staticArgs = staticArgs.append(LoadableConstant.Int(context.bridges.length() - 1));
for (Symbol s : context.bridges) {
Type s_erasure = s.erasure(types);
if (!types.isSameType(s_erasure, samSym.erasure(types))) {
staticArgs = staticArgs.append(s.erasure(types));
staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
}
}
}
@ -1170,7 +1166,7 @@ public class LambdaToMethod extends TreeTranslator {
int prevPos = make.pos;
try {
make.at(kInfo.clazz);
addDeserializationCase(refKind, refSym, tree.type, samSym,
addDeserializationCase(refSym, tree.type, samSym,
tree, staticArgs, indyType);
} finally {
make.at(prevPos);
@ -1186,14 +1182,14 @@ public class LambdaToMethod extends TreeTranslator {
* arguments types
*/
private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
Name methName) {
List<LoadableConstant> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
Name methName) {
int prevPos = make.pos;
try {
make.at(pos);
List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
syms.stringType,
syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
syms.stringType,
syms.methodTypeType).appendList(staticArgs.map(types::constantType));
Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
bsmName, bsm_staticArgs, List.nil());
@ -1201,15 +1197,12 @@ public class LambdaToMethod extends TreeTranslator {
DynamicMethodSymbol dynSym =
new DynamicMethodSymbol(methName,
syms.noSymbol,
bsm.isStatic() ?
ClassFile.REF_invokeStatic :
ClassFile.REF_invokeVirtual,
(MethodSymbol)bsm,
((MethodSymbol)bsm).asHandle(),
indyType,
staticArgs.toArray());
staticArgs.toArray(new LoadableConstant[staticArgs.length()]));
JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
new DynamicMethod(dynSym, types), dynSym);
dynSym.poolKey(types), dynSym);
qualifier.sym = existing != null ? existing : dynSym;
qualifier.type = indyType.getReturnType();
@ -1220,57 +1213,6 @@ public class LambdaToMethod extends TreeTranslator {
make.at(prevPos);
}
}
//where
private List<Type> bsmStaticArgToTypes(List<Object> args) {
ListBuffer<Type> argtypes = new ListBuffer<>();
for (Object arg : args) {
argtypes.append(bsmStaticArgToType(arg));
}
return argtypes.toList();
}
private Type bsmStaticArgToType(Object arg) {
Assert.checkNonNull(arg);
if (arg instanceof ClassSymbol) {
return syms.classType;
} else if (arg instanceof Integer) {
return syms.intType;
} else if (arg instanceof Long) {
return syms.longType;
} else if (arg instanceof Float) {
return syms.floatType;
} else if (arg instanceof Double) {
return syms.doubleType;
} else if (arg instanceof String) {
return syms.stringType;
} else if (arg instanceof Pool.MethodHandle) {
return syms.methodHandleType;
} else if (arg instanceof MethodType) {
return syms.methodTypeType;
} else {
Assert.error("bad static arg " + arg.getClass());
return null;
}
}
/**
* Get the opcode associated with this method reference
*/
private int referenceKind(Symbol refSym) {
if (refSym.isConstructor()) {
return ClassFile.REF_newInvokeSpecial;
} else {
if (refSym.isStatic()) {
return ClassFile.REF_invokeStatic;
} else if ((refSym.flags() & PRIVATE) != 0) {
return ClassFile.REF_invokeSpecial;
} else if (refSym.enclClass().isInterface()) {
return ClassFile.REF_invokeInterface;
} else {
return ClassFile.REF_invokeVirtual;
}
}
}
// <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
/**
@ -2312,13 +2254,6 @@ public class LambdaToMethod extends TreeTranslator {
this.isSuper = tree.hasKind(ReferenceKind.SUPER);
}
/**
* Get the opcode associated with this method reference
*/
int referenceKind() {
return LambdaToMethod.this.referenceKind(tree.sym);
}
boolean needsVarArgsConversion() {
return tree.varargsElement != null;
}

@ -93,7 +93,6 @@ public class Lower extends TreeTranslator {
private final Attr attr;
private TreeMaker make;
private DiagnosticPosition make_pos;
private final ClassWriter writer;
private final ConstFold cfolder;
private final Target target;
private final Source source;
@ -116,7 +115,6 @@ public class Lower extends TreeTranslator {
chk = Check.instance(context);
attr = Attr.instance(context);
make = TreeMaker.instance(context);
writer = ClassWriter.instance(context);
cfolder = ConstFold.instance(context);
target = Target.instance(context);
source = Source.instance(context);
@ -475,7 +473,7 @@ public class Lower extends TreeTranslator {
.fromString(target.syntheticNameChar() +
"SwitchMap" +
target.syntheticNameChar() +
writer.xClassName(forEnum.type).toString()
names.fromUtf(ClassWriter.externalize(forEnum.type.tsym.flatName())).toString()
.replace('/', '.')
.replace('.', target.syntheticNameChar()));
ClassSymbol outerCacheClass = outerCacheClass();

@ -25,9 +25,6 @@
package com.sun.tools.javac.jvm;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.util.Name;
@ -189,38 +186,4 @@ public class ClassFile {
public static byte[] externalize(Name name) {
return externalize(name.getByteArray(), name.getByteOffset(), name.getByteLength());
}
/************************************************************************
* Name-and-type
***********************************************************************/
/** A class for the name-and-type signature of a method or field.
*/
public static class NameAndType {
Name name;
UniqueType uniqueType;
Types types;
NameAndType(Name name, Type type, Types types) {
this.name = name;
this.uniqueType = new UniqueType(type, types);
this.types = types;
}
void setType(Type type) {
this.uniqueType = new UniqueType(type, types);
}
@Override
public boolean equals(Object other) {
return (other instanceof NameAndType &&
name == ((NameAndType) other).name &&
uniqueType.equals(((NameAndType) other).uniqueType));
}
@Override
public int hashCode() {
return name.hashCode() * uniqueType.hashCode();
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,6 +36,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.IntFunction;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
@ -55,8 +56,8 @@ import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
import com.sun.tools.javac.file.BaseFileManager;
import com.sun.tools.javac.file.PathFileObject;
import com.sun.tools.javac.jvm.ClassFile.NameAndType;
import com.sun.tools.javac.jvm.ClassFile.Version;
import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
import com.sun.tools.javac.resources.CompilerProperties.Warnings;
@ -100,11 +101,6 @@ public class ClassReader {
*/
boolean verbose;
/** Switch: read constant pool and code sections. This switch is initially
* set to false but can be turned on from outside.
*/
public boolean readAllOfClassFile = false;
/** Switch: allow modules.
*/
boolean allowModules;
@ -170,20 +166,15 @@ public class ClassReader {
/** The buffer containing the currently read class file.
*/
byte[] buf = new byte[INITIAL_BUFFER_SIZE];
ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE);
/** The current input pointer.
*/
protected int bp;
/** The objects of the constant pool.
/** The pool reader.
*/
Object[] poolObj;
/** For every constant pool entry, an index into buf where the
* defining section of the entry is found.
*/
int[] poolIdx;
PoolReader poolReader;
/** The major version number of the class file being read. */
int majorVersion;
@ -323,294 +314,29 @@ public class ClassReader {
/** Read a character.
*/
char nextChar() {
return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
char res = buf.getChar(bp);
bp += 2;
return res;
}
/** Read a byte.
*/
int nextByte() {
return buf[bp++] & 0xFF;
return buf.getByte(bp++) & 0xFF;
}
/** Read an integer.
*/
int nextInt() {
return
((buf[bp++] & 0xFF) << 24) +
((buf[bp++] & 0xFF) << 16) +
((buf[bp++] & 0xFF) << 8) +
(buf[bp++] & 0xFF);
}
/** Extract a character at position bp from buf.
*/
char getChar(int bp) {
return
(char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
}
/** Extract an integer at position bp from buf.
*/
int getInt(int bp) {
return
((buf[bp] & 0xFF) << 24) +
((buf[bp+1] & 0xFF) << 16) +
((buf[bp+2] & 0xFF) << 8) +
(buf[bp+3] & 0xFF);
}
/** Extract a long integer at position bp from buf.
*/
long getLong(int bp) {
DataInputStream bufin =
new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
try {
return bufin.readLong();
} catch (IOException e) {
throw new AssertionError(e);
}
}
/** Extract a float at position bp from buf.
*/
float getFloat(int bp) {
DataInputStream bufin =
new DataInputStream(new ByteArrayInputStream(buf, bp, 4));
try {
return bufin.readFloat();
} catch (IOException e) {
throw new AssertionError(e);
}
}
/** Extract a double at position bp from buf.
*/
double getDouble(int bp) {
DataInputStream bufin =
new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
try {
return bufin.readDouble();
} catch (IOException e) {
throw new AssertionError(e);
}
int res = buf.getInt(bp);
bp += 4;
return res;
}
/************************************************************************
* Constant Pool Access
***********************************************************************/
/** Index all constant pool entries, writing their start addresses into
* poolIdx.
*/
void indexPool() {
poolIdx = new int[nextChar()];
poolObj = new Object[poolIdx.length];
int i = 1;
while (i < poolIdx.length) {
poolIdx[i++] = bp;
byte tag = buf[bp++];
switch (tag) {
case CONSTANT_Utf8: case CONSTANT_Unicode: {
int len = nextChar();
bp = bp + len;
break;
}
case CONSTANT_Class:
case CONSTANT_String:
case CONSTANT_MethodType:
case CONSTANT_Module:
case CONSTANT_Package:
bp = bp + 2;
break;
case CONSTANT_MethodHandle:
bp = bp + 3;
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_NameandType:
case CONSTANT_Integer:
case CONSTANT_Float:
case CONSTANT_Dynamic:
case CONSTANT_InvokeDynamic:
bp = bp + 4;
break;
case CONSTANT_Long:
case CONSTANT_Double:
bp = bp + 8;
i++;
break;
default:
throw badClassFile("bad.const.pool.tag.at",
Byte.toString(tag),
Integer.toString(bp -1));
}
}
}
/** Read constant pool entry at start address i, use pool as a cache.
*/
Object readPool(int i) {
Object result = poolObj[i];
if (result != null) return result;
int index = poolIdx[i];
if (index == 0) return null;
byte tag = buf[index];
switch (tag) {
case CONSTANT_Utf8:
poolObj[i] = names.fromUtf(buf, index + 3, getChar(index + 1));
break;
case CONSTANT_Unicode:
throw badClassFile("unicode.str.not.supported");
case CONSTANT_Class:
poolObj[i] = readClassOrType(getChar(index + 1));
break;
case CONSTANT_String:
// FIXME: (footprint) do not use toString here
poolObj[i] = readName(getChar(index + 1)).toString();
break;
case CONSTANT_Fieldref: {
ClassSymbol owner = readClassSymbol(getChar(index + 1));
NameAndType nt = readNameAndType(getChar(index + 3));
poolObj[i] = new VarSymbol(0, nt.name, nt.uniqueType.type, owner);
break;
}
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref: {
ClassSymbol owner = readClassSymbol(getChar(index + 1));
NameAndType nt = readNameAndType(getChar(index + 3));
poolObj[i] = new MethodSymbol(0, nt.name, nt.uniqueType.type, owner);
break;
}
case CONSTANT_NameandType:
poolObj[i] = new NameAndType(
readName(getChar(index + 1)),
readType(getChar(index + 3)), types);
break;
case CONSTANT_Integer:
poolObj[i] = getInt(index + 1);
break;
case CONSTANT_Float:
poolObj[i] = Float.valueOf(getFloat(index + 1));
break;
case CONSTANT_Long:
poolObj[i] = Long.valueOf(getLong(index + 1));
break;
case CONSTANT_Double:
poolObj[i] = Double.valueOf(getDouble(index + 1));
break;
case CONSTANT_MethodHandle:
skipBytes(4);
break;
case CONSTANT_MethodType:
skipBytes(3);
break;
case CONSTANT_Dynamic:
case CONSTANT_InvokeDynamic:
skipBytes(5);
break;
case CONSTANT_Module:
case CONSTANT_Package:
// this is temporary for now: treat as a simple reference to the underlying Utf8.
poolObj[i] = readName(getChar(index + 1));
break;
default:
throw badClassFile("bad.const.pool.tag", Byte.toString(tag));
}
return poolObj[i];
}
/** Read signature and convert to type.
*/
Type readType(int i) {
int index = poolIdx[i];
return sigToType(buf, index + 3, getChar(index + 1));
}
/** If name is an array type or class signature, return the
* corresponding type; otherwise return a ClassSymbol with given name.
*/
Object readClassOrType(int i) {
int index = poolIdx[i];
int len = getChar(index + 1);
int start = index + 3;
Assert.check(buf[start] == '[' || buf[start + len - 1] != ';');
// by the above assertion, the following test can be
// simplified to (buf[start] == '[')
return (buf[start] == '[' || buf[start + len - 1] == ';')
? (Object)sigToType(buf, start, len)
: (Object)enterClass(names.fromUtf(internalize(buf, start,
len)));
}
/** Read signature and convert to type parameters.
*/
List<Type> readTypeParams(int i) {
int index = poolIdx[i];
return sigToTypeParams(buf, index + 3, getChar(index + 1));
}
/** Read class entry.
*/
ClassSymbol readClassSymbol(int i) {
Object obj = readPool(i);
if (obj != null && !(obj instanceof ClassSymbol))
throw badClassFile("bad.const.pool.entry",
currentClassFile.toString(),
"CONSTANT_Class_info", i);
return (ClassSymbol)obj;
}
Name readClassName(int i) {
int index = poolIdx[i];
if (index == 0) return null;
byte tag = buf[index];
if (tag != CONSTANT_Class) {
throw badClassFile("bad.const.pool.entry",
currentClassFile.toString(),
"CONSTANT_Class_info", i);
}
int nameIndex = poolIdx[getChar(index + 1)];
int len = getChar(nameIndex + 1);
int start = nameIndex + 3;
if (buf[start] == '[' || buf[start + len - 1] == ';')
throw badClassFile("wrong class name"); //TODO: proper diagnostics
return names.fromUtf(internalize(buf, start, len));
}
/** Read name.
*/
Name readName(int i) {
Object obj = readPool(i);
if (obj != null && !(obj instanceof Name))
throw badClassFile("bad.const.pool.entry",
currentClassFile.toString(),
"CONSTANT_Utf8_info or CONSTANT_String_info", i);
return (Name)obj;
}
/** Read name and type.
*/
NameAndType readNameAndType(int i) {
Object obj = readPool(i);
if (obj != null && !(obj instanceof NameAndType))
throw badClassFile("bad.const.pool.entry",
currentClassFile.toString(),
"CONSTANT_NameAndType_info", i);
return (NameAndType)obj;
}
/** Read the name of a module.
* The name is stored in a CONSTANT_Module entry, in
* JVMS 4.2 binary form (using ".", not "/")
*/
Name readModuleName(int i) {
return readName(i);
}
/** Read module_flags.
*/
Set<ModuleFlags> readModuleFlags(int flags) {
@ -762,7 +488,7 @@ public class ClassReader {
List<Type> argtypes = sigToTypes(')');
Type restype = sigToType();
List<Type> thrown = List.nil();
while (signature[sigp] == '^') {
while (sigp < siglimit && signature[sigp] == '^') {
sigp++;
thrown = thrown.prepend(sigToType());
}
@ -855,7 +581,7 @@ public class ClassReader {
};
switch (signature[sigp++]) {
case ';':
if (sigp < signature.length && signature[sigp] == '.') {
if (sigp < siglimit && signature[sigp] == '.') {
// support old-style GJC signatures
// The signature produced was
// Lfoo/Outer<Lfoo/X;>;.Lfoo/Outer$Inner<Lfoo/Y;>;
@ -1049,7 +775,7 @@ public class ClassReader {
new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
protected void read(Symbol sym, int attrLen) {
if (readAllOfClassFile || saveParameterNames)
if (saveParameterNames)
((MethodSymbol)sym).code = readCode(sym);
else
bp = bp + attrLen;
@ -1058,7 +784,7 @@ public class ClassReader {
new AttributeReader(names.ConstantValue, V45_3, MEMBER_ATTRIBUTE) {
protected void read(Symbol sym, int attrLen) {
Object v = readPool(nextChar());
Object v = poolReader.getConstant(nextChar());
// Ignore ConstantValue attribute if field not final.
if ((sym.flags() & FINAL) == 0) {
return;
@ -1115,7 +841,7 @@ public class ClassReader {
int nexceptions = nextChar();
List<Type> thrown = List.nil();
for (int j = 0; j < nexceptions; j++)
thrown = thrown.prepend(readClassSymbol(nextChar()).type);
thrown = thrown.prepend(poolReader.getClass(nextChar()).type);
if (sym.type.getThrownTypes().isEmpty())
sym.type.asMethodType().thrown = thrown.reverse();
}
@ -1173,7 +899,7 @@ public class ClassReader {
new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) {
protected void read(Symbol sym, int attrLen) {
ClassSymbol c = (ClassSymbol) sym;
Name n = readName(nextChar());
Name n = poolReader.getName(nextChar());
c.sourcefile = new SourceFileObject(n);
// If the class is a toplevel class, originating from a Java source file,
// but the class name does not match the file name, then it is
@ -1211,7 +937,8 @@ public class ClassReader {
try {
ClassType ct1 = (ClassType)c.type;
Assert.check(c == currentOwner);
ct1.typarams_field = readTypeParams(nextChar());
ct1.typarams_field = poolReader.getName(nextChar())
.map(ClassReader.this::sigToTypeParams);
ct1.supertype_field = sigToType();
ListBuffer<Type> is = new ListBuffer<>();
while (sigp != siglimit) is.append(sigToType());
@ -1221,7 +948,7 @@ public class ClassReader {
}
} else {
List<Type> thrown = sym.type.getThrownTypes();
sym.type = readType(nextChar());
sym.type = poolReader.getType(nextChar());
//- System.err.println(" # " + sym.type);
if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
sym.type.asMethodType().thrown = thrown;
@ -1342,19 +1069,19 @@ public class ClassReader {
ModuleSymbol msym = (ModuleSymbol) sym.owner;
ListBuffer<Directive> directives = new ListBuffer<>();
Name moduleName = readModuleName(nextChar());
Name moduleName = poolReader.peekModuleName(nextChar(), names::fromUtf);
if (currentModule.name != moduleName) {
throw badClassFile("module.name.mismatch", moduleName, currentModule.name);
}
Set<ModuleFlags> moduleFlags = readModuleFlags(nextChar());
msym.flags.addAll(moduleFlags);
msym.version = readName(nextChar());
msym.version = optPoolEntry(nextChar(), poolReader::getName, null);
ListBuffer<RequiresDirective> requires = new ListBuffer<>();
int nrequires = nextChar();
for (int i = 0; i < nrequires; i++) {
ModuleSymbol rsym = syms.enterModule(readModuleName(nextChar()));
ModuleSymbol rsym = poolReader.getModule(nextChar());
Set<RequiresFlag> flags = readRequiresFlags(nextChar());
if (rsym == syms.java_base && majorVersion >= V54.major) {
if (flags.contains(RequiresFlag.TRANSITIVE)) {
@ -1373,8 +1100,7 @@ public class ClassReader {
ListBuffer<ExportsDirective> exports = new ListBuffer<>();
int nexports = nextChar();
for (int i = 0; i < nexports; i++) {
Name n = readName(nextChar());
PackageSymbol p = syms.enterPackage(currentModule, names.fromUtf(internalize(n)));
PackageSymbol p = poolReader.getPackage(nextChar());
Set<ExportsFlag> flags = readExportsFlags(nextChar());
int nto = nextChar();
List<ModuleSymbol> to;
@ -1383,7 +1109,7 @@ public class ClassReader {
} else {
ListBuffer<ModuleSymbol> lb = new ListBuffer<>();
for (int t = 0; t < nto; t++)
lb.append(syms.enterModule(readModuleName(nextChar())));
lb.append(poolReader.getModule(nextChar()));
to = lb.toList();
}
exports.add(new ExportsDirective(p, to, flags));
@ -1396,8 +1122,7 @@ public class ClassReader {
throw badClassFile("module.non.zero.opens", currentModule.name);
}
for (int i = 0; i < nopens; i++) {
Name n = readName(nextChar());
PackageSymbol p = syms.enterPackage(currentModule, names.fromUtf(internalize(n)));
PackageSymbol p = poolReader.getPackage(nextChar());
Set<OpensFlag> flags = readOpensFlags(nextChar());
int nto = nextChar();
List<ModuleSymbol> to;
@ -1406,7 +1131,7 @@ public class ClassReader {
} else {
ListBuffer<ModuleSymbol> lb = new ListBuffer<>();
for (int t = 0; t < nto; t++)
lb.append(syms.enterModule(readModuleName(nextChar())));
lb.append(poolReader.getModule(nextChar()));
to = lb.toList();
}
opens.add(new OpensDirective(p, to, flags));
@ -1419,7 +1144,7 @@ public class ClassReader {
ListBuffer<InterimUsesDirective> uses = new ListBuffer<>();
int nuses = nextChar();
for (int i = 0; i < nuses; i++) {
Name srvc = readClassName(nextChar());
Name srvc = poolReader.peekClassName(nextChar(), this::classNameMapper);
uses.add(new InterimUsesDirective(srvc));
}
interimUses = uses.toList();
@ -1427,17 +1152,21 @@ public class ClassReader {
ListBuffer<InterimProvidesDirective> provides = new ListBuffer<>();
int nprovides = nextChar();
for (int p = 0; p < nprovides; p++) {
Name srvc = readClassName(nextChar());
Name srvc = poolReader.peekClassName(nextChar(), this::classNameMapper);
int nimpls = nextChar();
ListBuffer<Name> impls = new ListBuffer<>();
for (int i = 0; i < nimpls; i++) {
impls.append(readClassName(nextChar()));
impls.append(poolReader.peekClassName(nextChar(), this::classNameMapper));
provides.add(new InterimProvidesDirective(srvc, impls.toList()));
}
}
interimProvides = provides.toList();
}
}
private Name classNameMapper(byte[] arr, int offset, int length) {
return names.fromUtf(ClassFile.internalize(arr, offset, length));
}
},
new AttributeReader(names.ModuleResolution, V53, CLASS_ATTRIBUTE) {
@ -1464,8 +1193,8 @@ public class ClassReader {
// the scope specified by the attribute
sym.owner.members().remove(sym);
ClassSymbol self = (ClassSymbol)sym;
ClassSymbol c = readClassSymbol(nextChar());
NameAndType nt = readNameAndType(nextChar());
ClassSymbol c = poolReader.getClass(nextChar());
NameAndType nt = optPoolEntry(nextChar(), poolReader::getNameAndType, null);
if (c.members_field == null || c.kind != TYP)
throw badClassFile("bad.enclosing.class", self, c);
@ -1520,7 +1249,7 @@ public class ClassReader {
if (nt == null)
return null;
MethodType type = nt.uniqueType.type.asMethodType();
MethodType type = nt.type.asMethodType();
for (Symbol sym : scope.getSymbolsByName(nt.name)) {
if (sym.kind == MTH && isSameBinaryType(sym.type.asMethodType(), type))
@ -1533,15 +1262,15 @@ public class ClassReader {
if ((flags & INTERFACE) != 0)
// no enclosing instance
return null;
if (nt.uniqueType.type.getParameterTypes().isEmpty())
if (nt.type.getParameterTypes().isEmpty())
// no parameters
return null;
// A constructor of an inner class.
// Remove the first argument (the enclosing instance)
nt.setType(new MethodType(nt.uniqueType.type.getParameterTypes().tail,
nt.uniqueType.type.getReturnType(),
nt.uniqueType.type.getThrownTypes(),
nt = new NameAndType(nt.name, new MethodType(nt.type.getParameterTypes().tail,
nt.type.getReturnType(),
nt.type.getThrownTypes(),
syms.methodClass));
// Try searching again
return findMethod(nt, scope, flags);
@ -1578,7 +1307,7 @@ public class ClassReader {
void readAttrs(Symbol sym, AttributeKind kind) {
char ac = nextChar();
for (int i = 0; i < ac; i++) {
Name attrName = readName(nextChar());
Name attrName = poolReader.getName(nextChar());
int attrLen = nextInt();
AttributeReader r = attributeReaders.get(attrName);
if (r != null && r.accepts(kind))
@ -1681,7 +1410,7 @@ public class ClassReader {
/** Read parameter annotations.
*/
void readParameterAnnotations(Symbol meth) {
int numParameters = buf[bp++] & 0xFF;
int numParameters = buf.getByte(bp++) & 0xFF;
if (parameterAnnotations == null) {
parameterAnnotations = new ParameterAnnotations[numParameters];
} else if (parameterAnnotations.length != numParameters) {
@ -1725,39 +1454,30 @@ public class ClassReader {
Type readTypeOrClassSymbol(int i) {
// support preliminary jsr175-format class files
if (buf[poolIdx[i]] == CONSTANT_Class)
return readClassSymbol(i).type;
return readTypeToProxy(i);
}
Type readEnumType(int i) {
// support preliminary jsr175-format class files
int index = poolIdx[i];
int length = getChar(index + 1);
if (buf[index + length + 2] != ';')
return enterClass(readName(i)).type;
if (poolReader.hasTag(i, CONSTANT_Class))
return poolReader.getClass(i).type;
return readTypeToProxy(i);
}
Type readTypeToProxy(int i) {
if (currentModule.module_info == currentOwner) {
int index = poolIdx[i];
return new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1)));
return new ProxyType(i);
} else {
return readType(i);
return poolReader.getType(i);
}
}
CompoundAnnotationProxy readCompoundAnnotation() {
Type t;
if (currentModule.module_info == currentOwner) {
int index = poolIdx[nextChar()];
t = new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1)));
int cpIndex = nextChar();
t = new ProxyType(cpIndex);
} else {
t = readTypeOrClassSymbol(nextChar());
}
int numFields = nextChar();
ListBuffer<Pair<Name,Attribute>> pairs = new ListBuffer<>();
for (int i=0; i<numFields; i++) {
Name name = readName(nextChar());
Name name = poolReader.getName(nextChar());
Attribute value = readAttributeValue();
pairs.append(new Pair<>(name, value));
}
@ -1970,29 +1690,40 @@ public class ClassReader {
}
/**
* Helper function to read an optional pool entry (with given function); this is used while parsing
* InnerClasses and EnclosingMethod attributes, as well as when parsing supertype descriptor,
* as per JVMS.
*/
<Z> Z optPoolEntry(int index, IntFunction<Z> poolFunc, Z defaultValue) {
return (index == 0) ?
defaultValue :
poolFunc.apply(index);
}
Attribute readAttributeValue() {
char c = (char) buf[bp++];
char c = (char) buf.getByte(bp++);
switch (c) {
case 'B':
return new Attribute.Constant(syms.byteType, readPool(nextChar()));
return new Attribute.Constant(syms.byteType, poolReader.getConstant(nextChar()));
case 'C':
return new Attribute.Constant(syms.charType, readPool(nextChar()));
return new Attribute.Constant(syms.charType, poolReader.getConstant(nextChar()));
case 'D':
return new Attribute.Constant(syms.doubleType, readPool(nextChar()));
return new Attribute.Constant(syms.doubleType, poolReader.getConstant(nextChar()));
case 'F':
return new Attribute.Constant(syms.floatType, readPool(nextChar()));
return new Attribute.Constant(syms.floatType, poolReader.getConstant(nextChar()));
case 'I':
return new Attribute.Constant(syms.intType, readPool(nextChar()));
return new Attribute.Constant(syms.intType, poolReader.getConstant(nextChar()));
case 'J':
return new Attribute.Constant(syms.longType, readPool(nextChar()));
return new Attribute.Constant(syms.longType, poolReader.getConstant(nextChar()));
case 'S':
return new Attribute.Constant(syms.shortType, readPool(nextChar()));
return new Attribute.Constant(syms.shortType, poolReader.getConstant(nextChar()));
case 'Z':
return new Attribute.Constant(syms.booleanType, readPool(nextChar()));
return new Attribute.Constant(syms.booleanType, poolReader.getConstant(nextChar()));
case 's':
return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString());
return new Attribute.Constant(syms.stringType, poolReader.getName(nextChar()).toString());
case 'e':
return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar()));
return new EnumAttributeProxy(readTypeToProxy(nextChar()), poolReader.getName(nextChar()));
case 'c':
return new ClassAttributeProxy(readTypeOrClassSymbol(nextChar()));
case '[': {
@ -2401,8 +2132,8 @@ public class ClassReader {
*/
VarSymbol readField() {
long flags = adjustFieldFlags(nextChar());
Name name = readName(nextChar());
Type type = readType(nextChar());
Name name = poolReader.getName(nextChar());
Type type = poolReader.getType(nextChar());
VarSymbol v = new VarSymbol(flags, name, type, currentOwner);
readMemberAttrs(v);
return v;
@ -2412,8 +2143,8 @@ public class ClassReader {
*/
MethodSymbol readMethod() {
long flags = adjustMethodFlags(nextChar());
Name name = readName(nextChar());
Type type = readType(nextChar());
Name name = poolReader.getName(nextChar());
Type type = poolReader.getType(nextChar());
if (currentOwner.isInterface() &&
(flags & ABSTRACT) == 0 && !name.equals(names.clinit)) {
if (majorVersion > Version.V52.major ||
@ -2592,7 +2323,7 @@ public class ClassReader {
Name argName;
if (parameterNameIndices != null && index < parameterNameIndices.length
&& parameterNameIndices[index] != 0) {
argName = readName(parameterNameIndices[index]);
argName = optPoolEntry(parameterNameIndices[index], poolReader::getName, names.empty);
flags |= NAME_FILLED;
} else {
String prefix = "arg";
@ -2681,7 +2412,7 @@ public class ClassReader {
if (c.owner.kind == PCK || c.owner.kind == ERR) c.flags_field = flags;
// read own class name and check that it matches
currentModule = c.packge().modle;
ClassSymbol self = readClassSymbol(nextChar());
ClassSymbol self = poolReader.getClass(nextChar());
if (c != self) {
throw badClassFile("class.file.wrong.class",
self.flatname);
@ -2710,11 +2441,6 @@ public class ClassReader {
for (int i = 0; i < methodCount; i++) skipMember();
readClassAttrs(c);
if (readAllOfClassFile) {
for (int i = 1; i < poolObj.length; i++) readPool(i);
c.pool = new Pool(poolObj.length, poolObj, types);
}
// reset and read rest of classinfo
bp = startbp;
int n = nextChar();
@ -2722,13 +2448,12 @@ public class ClassReader {
throw badClassFile("module.info.invalid.super.class");
}
if (ct.supertype_field == null)
ct.supertype_field = (n == 0)
? Type.noType
: readClassSymbol(n).erasure(types);
ct.supertype_field =
optPoolEntry(n, idx -> poolReader.getClass(idx).erasure(types), Type.noType);
n = nextChar();
List<Type> is = List.nil();
for (int i = 0; i < n; i++) {
Type _inter = readClassSymbol(nextChar()).erasure(types);
Type _inter = poolReader.getClass(nextChar()).erasure(types);
is = is.prepend(_inter);
}
if (ct.interfaces_field == null)
@ -2749,8 +2474,10 @@ public class ClassReader {
int n = nextChar();
for (int i = 0; i < n; i++) {
nextChar(); // skip inner class symbol
ClassSymbol outer = readClassSymbol(nextChar());
Name name = readName(nextChar());
int outerIdx = nextChar();
int nameIdx = nextChar();
ClassSymbol outer = optPoolEntry(outerIdx, poolReader::getClass, null);
Name name = optPoolEntry(nameIdx, poolReader::getName, names.empty);
if (name == null) name = names.empty;
long flags = adjustClassFlags(nextChar());
if (outer != null) { // we have a member class
@ -2804,7 +2531,8 @@ public class ClassReader {
}
}
indexPool();
poolReader = new PoolReader(this, names, syms);
bp = poolReader.readPool(buf, bp);
if (signatureBuffer.length < bp) {
int ns = Integer.highestOneBit(bp) << 1;
signatureBuffer = new byte[ns];
@ -2821,7 +2549,8 @@ public class ClassReader {
repeatable = null;
try {
bp = 0;
buf = readInputStream(buf, c.classfile.openInputStream());
buf.reset();
buf.appendStream(c.classfile.openInputStream());
readClassBuffer(c);
if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) {
List<Type> missing = missingTypeVariables;
@ -2875,43 +2604,6 @@ public class ClassReader {
filling = false;
}
}
// where
private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
try {
buf = ensureCapacity(buf, s.available());
int r = s.read(buf);
int bp = 0;
while (r != -1) {
bp += r;
buf = ensureCapacity(buf, bp);
r = s.read(buf, bp, buf.length - bp);
}
return buf;
} finally {
try {
s.close();
} catch (IOException e) {
/* Ignore any errors, as this stream may have already
* thrown a related exception which is the one that
* should be reported.
*/
}
}
}
/*
* ensureCapacity will increase the buffer as needed, taking note that
* the new buffer will always be greater than the needed and never
* exactly equal to the needed size or bp. If equal then the read (above)
* will infinitely loop as buf.length - bp == 0.
*/
private static byte[] ensureCapacity(byte[] buf, int needed) {
if (buf.length <= needed) {
byte[] old = buf;
buf = new byte[Integer.highestOneBit(needed) << 1];
System.arraycopy(old, 0, buf, 0, old.length);
}
return buf;
}
/** We can only read a single class file at a time; this
* flag keeps track of when we are currently reading a class
@ -3098,11 +2790,11 @@ public class ClassReader {
private class ProxyType extends Type {
private final byte[] content;
private final Name name;
public ProxyType(byte[] content) {
public ProxyType(int index) {
super(syms.noSymbol, TypeMetadata.EMPTY);
this.content = content;
this.name = poolReader.getName(index);
}
@Override
@ -3116,7 +2808,7 @@ public class ClassReader {
}
public Type resolve() {
return sigToType(content, 0, content.length);
return name.map(ClassReader.this::sigToType);
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)

@ -29,9 +29,7 @@ import java.io.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.stream.Collectors;
import javax.tools.JavaFileManager;
import javax.tools.FileObject;
@ -44,13 +42,10 @@ import com.sun.tools.javac.code.Directive.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.comp.Check;
import com.sun.tools.javac.file.PathFileObject;
import com.sun.tools.javac.jvm.Pool.DynamicMethod;
import com.sun.tools.javac.jvm.Pool.Method;
import com.sun.tools.javac.jvm.Pool.MethodHandle;
import com.sun.tools.javac.jvm.Pool.Variable;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
import com.sun.tools.javac.util.*;
@ -121,7 +116,7 @@ public class ClassWriter extends ClassFile {
* Sizes are increased when buffers get full.
*/
static final int DATA_BUF_SIZE = 0x0fff0;
static final int POOL_BUF_SIZE = 0x1fff0;
static final int CLASS_BUF_SIZE = 0x1fff0;
/** An output buffer for member info.
*/
@ -129,25 +124,11 @@ public class ClassWriter extends ClassFile {
/** An output buffer for the constant pool.
*/
ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE);
/** The constant pool.
/** The constant pool writer.
*/
Pool pool;
/** The inner classes to be written, as a set.
*/
Set<ClassSymbol> innerClasses;
/** The inner classes to be written, as a queue where
* enclosing classes come first.
*/
ListBuffer<ClassSymbol> innerClassesQueue;
/** The bootstrap methods to be written in the corresponding class attribute
* (one for each invokedynamic)
*/
Map<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> bootstrapMethods;
final PoolWriter poolWriter;
/** The log to use for verbose output.
*/
@ -159,9 +140,6 @@ public class ClassWriter extends ClassFile {
/** Access to files. */
private final JavaFileManager fileManager;
/** Sole signature generator */
private final CWSignatureGenerator signatureGen;
/** The tags and constants used in compressed stackmap. */
static final int SAME_FRAME_SIZE = 64;
static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
@ -191,7 +169,7 @@ public class ClassWriter extends ClassFile {
types = Types.instance(context);
check = Check.instance(context);
fileManager = context.get(JavaFileManager.class);
signatureGen = new CWSignatureGenerator(types);
poolWriter = Gen.instance(context).poolWriter;
verbose = options.isSet(VERBOSE);
genCrt = options.isSet(XJCOV);
@ -272,108 +250,17 @@ public class ClassWriter extends ClassFile {
buf.elems[adr+3] = (byte)((x ) & 0xFF);
}
/**
* Signature Generation
*/
private class CWSignatureGenerator extends Types.SignatureGenerator {
/**
* An output buffer for type signatures.
*/
ByteBuffer sigbuf = new ByteBuffer();
CWSignatureGenerator(Types types) {
super(types);
}
/**
* Assemble signature of given type in string buffer.
* Check for uninitialized types before calling the general case.
*/
@Override
public void assembleSig(Type type) {
switch (type.getTag()) {
case UNINITIALIZED_THIS:
case UNINITIALIZED_OBJECT:
// we don't yet have a spec for uninitialized types in the
// local variable table
assembleSig(types.erasure(((UninitializedType)type).qtype));
break;
default:
super.assembleSig(type);
}
}
@Override
protected void append(char ch) {
sigbuf.appendByte(ch);
}
@Override
protected void append(byte[] ba) {
sigbuf.appendBytes(ba);
}
@Override
protected void append(Name name) {
sigbuf.appendName(name);
}
@Override
protected void classReference(ClassSymbol c) {
enterInner(c);
}
private void reset() {
sigbuf.reset();
}
private Name toName() {
return sigbuf.toName(names);
}
private boolean isEmpty() {
return sigbuf.length == 0;
}
}
/**
* Return signature of given type
*/
Name typeSig(Type type) {
Assert.check(signatureGen.isEmpty());
//- System.out.println(" ? " + type);
signatureGen.assembleSig(type);
Name n = signatureGen.toName();
signatureGen.reset();
//- System.out.println(" " + n);
return n;
}
/** Given a type t, return the extended class name of its erasure in
* external representation.
*/
public Name xClassName(Type t) {
if (t.hasTag(CLASS)) {
return names.fromUtf(externalize(t.tsym.flatName()));
} else if (t.hasTag(ARRAY)) {
return typeSig(types.erasure(t));
} else {
throw new AssertionError("xClassName expects class or array type, got " + t);
}
}
/******************************************************************
* Writing the Constant Pool
******************************************************************/
/** Thrown when the constant pool is over full.
*/
public static class PoolOverflow extends Exception {
public static class PoolOverflow extends RuntimeException {
private static final long serialVersionUID = 0;
public PoolOverflow() {}
}
public static class StringOverflow extends Exception {
public static class StringOverflow extends RuntimeException {
private static final long serialVersionUID = 0;
public final String value;
public StringOverflow(String s) {
@ -381,137 +268,6 @@ public class ClassWriter extends ClassFile {
}
}
/** Write constant pool to pool buffer.
* Note: during writing, constant pool
* might grow since some parts of constants still need to be entered.
*/
void writePool(Pool pool) throws PoolOverflow, StringOverflow {
int poolCountIdx = poolbuf.length;
poolbuf.appendChar(0);
int i = 1;
while (i < pool.pp) {
Object value = pool.pool[i];
Assert.checkNonNull(value);
if (value instanceof Method || value instanceof Variable)
value = ((DelegatedSymbol)value).getUnderlyingSymbol();
if (value instanceof MethodSymbol) {
MethodSymbol m = (MethodSymbol)value;
if (!m.isDynamic()) {
poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0
? CONSTANT_InterfaceMethodref
: CONSTANT_Methodref);
poolbuf.appendChar(pool.put(m.owner));
poolbuf.appendChar(pool.put(nameType(m)));
} else {
//invokedynamic
DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m;
MethodHandle handle = new MethodHandle(dynSym.bsmKind, dynSym.bsm, types);
DynamicMethod.BootstrapMethodsKey key = new DynamicMethod.BootstrapMethodsKey(dynSym, types);
// Figure out the index for existing BSM; create a new BSM if no key
DynamicMethod.BootstrapMethodsValue val = bootstrapMethods.get(key);
if (val == null) {
int index = bootstrapMethods.size();
val = new DynamicMethod.BootstrapMethodsValue(handle, index);
bootstrapMethods.put(key, val);
}
//init cp entries
pool.put(names.BootstrapMethods);
pool.put(handle);
for (Object staticArg : dynSym.staticArgs) {
pool.put(staticArg);
}
poolbuf.appendByte(CONSTANT_InvokeDynamic);
poolbuf.appendChar(val.index);
poolbuf.appendChar(pool.put(nameType(dynSym)));
}
} else if (value instanceof VarSymbol) {
VarSymbol v = (VarSymbol)value;
poolbuf.appendByte(CONSTANT_Fieldref);
poolbuf.appendChar(pool.put(v.owner));
poolbuf.appendChar(pool.put(nameType(v)));
} else if (value instanceof Name) {
poolbuf.appendByte(CONSTANT_Utf8);
byte[] bs = ((Name)value).toUtf();
poolbuf.appendChar(bs.length);
poolbuf.appendBytes(bs, 0, bs.length);
if (bs.length > Pool.MAX_STRING_LENGTH)
throw new StringOverflow(value.toString());
} else if (value instanceof ClassSymbol) {
ClassSymbol c = (ClassSymbol)value;
if (c.owner.kind == TYP) pool.put(c.owner);
poolbuf.appendByte(CONSTANT_Class);
if (c.type.hasTag(ARRAY)) {
poolbuf.appendChar(pool.put(typeSig(c.type)));
} else {
poolbuf.appendChar(pool.put(names.fromUtf(externalize(c.flatname))));
enterInner(c);
}
} else if (value instanceof NameAndType) {
NameAndType nt = (NameAndType)value;
poolbuf.appendByte(CONSTANT_NameandType);
poolbuf.appendChar(pool.put(nt.name));
poolbuf.appendChar(pool.put(typeSig(nt.uniqueType.type)));
} else if (value instanceof Integer) {
poolbuf.appendByte(CONSTANT_Integer);
poolbuf.appendInt(((Integer)value).intValue());
} else if (value instanceof Long) {
poolbuf.appendByte(CONSTANT_Long);
poolbuf.appendLong(((Long)value).longValue());
i++;
} else if (value instanceof Float) {
poolbuf.appendByte(CONSTANT_Float);
poolbuf.appendFloat(((Float)value).floatValue());
} else if (value instanceof Double) {
poolbuf.appendByte(CONSTANT_Double);
poolbuf.appendDouble(((Double)value).doubleValue());
i++;
} else if (value instanceof String) {
poolbuf.appendByte(CONSTANT_String);
poolbuf.appendChar(pool.put(names.fromString((String)value)));
} else if (value instanceof UniqueType) {
Type type = ((UniqueType)value).type;
if (type.hasTag(METHOD)) {
poolbuf.appendByte(CONSTANT_MethodType);
poolbuf.appendChar(pool.put(typeSig((MethodType)type)));
} else {
Assert.check(type.hasTag(ARRAY));
poolbuf.appendByte(CONSTANT_Class);
poolbuf.appendChar(pool.put(xClassName(type)));
}
} else if (value instanceof MethodHandle) {
MethodHandle ref = (MethodHandle)value;
poolbuf.appendByte(CONSTANT_MethodHandle);
poolbuf.appendByte(ref.refKind);
poolbuf.appendChar(pool.put(ref.refSym));
} else if (value instanceof ModuleSymbol) {
ModuleSymbol m = (ModuleSymbol)value;
poolbuf.appendByte(CONSTANT_Module);
poolbuf.appendChar(pool.put(m.name));
} else if (value instanceof PackageSymbol) {
PackageSymbol m = (PackageSymbol)value;
poolbuf.appendByte(CONSTANT_Package);
poolbuf.appendChar(pool.put(names.fromUtf(externalize(m.fullname))));
} else {
Assert.error("writePool " + value);
}
i++;
}
if (pool.pp > Pool.MAX_ENTRIES)
throw new PoolOverflow();
putChar(poolbuf, poolCountIdx, pool.pp);
}
/** Given a symbol, return its name-and-type.
*/
NameAndType nameType(Symbol sym) {
return new NameAndType(sym.name, sym.externalType(types), types);
// the NameAndType is generated from a symbol reference, and the
// adjustment of adding an additional this$n parameter needs to be made.
}
/******************************************************************
* Writing Attributes
******************************************************************/
@ -520,7 +276,8 @@ public class ClassWriter extends ClassFile {
* position past attribute length index.
*/
int writeAttr(Name attrName) {
databuf.appendChar(pool.put(attrName));
int index = poolWriter.putName(attrName);
databuf.appendChar(index);
databuf.appendInt(0);
return databuf.length;
}
@ -567,8 +324,8 @@ public class ClassWriter extends ClassFile {
|| c.owner.kind != MTH) // or member init
? null
: (MethodSymbol)c.owner;
databuf.appendChar(pool.put(enclClass));
databuf.appendChar(enclMethod == null ? 0 : pool.put(nameType(c.owner)));
databuf.appendChar(poolWriter.putClass(enclClass));
databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(c.owner));
endAttr(alenIdx);
return 1;
}
@ -594,11 +351,11 @@ public class ClassWriter extends ClassFile {
if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC &&
(flags & ANONCONSTR) == 0 &&
(!types.isSameType(sym.type, sym.erasure(types)) ||
signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
// note that a local class with captured variables
// will get a signature attribute
int alenIdx = writeAttr(names.Signature);
databuf.appendChar(pool.put(typeSig(sym.type)));
databuf.appendChar(poolWriter.putSignature(sym));
endAttr(alenIdx);
acount++;
}
@ -621,7 +378,7 @@ public class ClassWriter extends ClassFile {
final int flags =
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
((int) m.flags() & SYNTHETIC);
databuf.appendChar(pool.put(s.name));
databuf.appendChar(poolWriter.putName(s.name));
databuf.appendChar(flags);
}
// Now write the real parameters
@ -629,7 +386,7 @@ public class ClassWriter extends ClassFile {
final int flags =
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
((int) m.flags() & SYNTHETIC);
databuf.appendChar(pool.put(s.name));
databuf.appendChar(poolWriter.putName(s.name));
databuf.appendChar(flags);
}
// Now write the captured locals
@ -637,7 +394,7 @@ public class ClassWriter extends ClassFile {
final int flags =
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
((int) m.flags() & SYNTHETIC);
databuf.appendChar(pool.put(s.name));
databuf.appendChar(poolWriter.putName(s.name));
databuf.appendChar(flags);
}
endAttr(attrIndex);
@ -803,50 +560,51 @@ public class ClassWriter extends ClassFile {
*/
class AttributeWriter implements Attribute.Visitor {
public void visitConstant(Attribute.Constant _value) {
Object value = _value.value;
switch (_value.type.getTag()) {
case BYTE:
databuf.appendByte('B');
break;
case CHAR:
databuf.appendByte('C');
break;
case SHORT:
databuf.appendByte('S');
break;
case INT:
databuf.appendByte('I');
break;
case LONG:
databuf.appendByte('J');
break;
case FLOAT:
databuf.appendByte('F');
break;
case DOUBLE:
databuf.appendByte('D');
break;
case BOOLEAN:
databuf.appendByte('Z');
break;
case CLASS:
Assert.check(value instanceof String);
if (_value.type.getTag() == CLASS) {
Assert.check(_value.value instanceof String);
String s = (String)_value.value;
databuf.appendByte('s');
value = names.fromString(value.toString()); // CONSTANT_Utf8
break;
default:
throw new AssertionError(_value.type);
databuf.appendChar(poolWriter.putName(names.fromString(s)));
} else {
switch (_value.type.getTag()) {
case BYTE:
databuf.appendByte('B');
break;
case CHAR:
databuf.appendByte('C');
break;
case SHORT:
databuf.appendByte('S');
break;
case INT:
databuf.appendByte('I');
break;
case LONG:
databuf.appendByte('J');
break;
case FLOAT:
databuf.appendByte('F');
break;
case DOUBLE:
databuf.appendByte('D');
break;
case BOOLEAN:
databuf.appendByte('Z');
break;
default:
throw new AssertionError(_value.type);
}
databuf.appendChar(poolWriter.putConstant(_value.value));
}
databuf.appendChar(pool.put(value));
}
public void visitEnum(Attribute.Enum e) {
databuf.appendByte('e');
databuf.appendChar(pool.put(typeSig(e.value.type)));
databuf.appendChar(pool.put(e.value.name));
databuf.appendChar(poolWriter.putDescriptor(e.value.type));
databuf.appendChar(poolWriter.putName(e.value.name));
}
public void visitClass(Attribute.Class clazz) {
databuf.appendByte('c');
databuf.appendChar(pool.put(typeSig(types.erasure(clazz.classType))));
databuf.appendChar(poolWriter.putDescriptor(clazz.classType));
}
public void visitCompound(Attribute.Compound compound) {
databuf.appendByte('@');
@ -867,10 +625,10 @@ public class ClassWriter extends ClassFile {
/** Write a compound attribute excluding the '@' marker. */
void writeCompoundAttribute(Attribute.Compound c) {
databuf.appendChar(pool.put(typeSig(c.type)));
databuf.appendChar(poolWriter.putDescriptor(c.type));
databuf.appendChar(c.values.length());
for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) {
databuf.appendChar(pool.put(p.fst.name));
databuf.appendChar(poolWriter.putName(p.fst.name));
p.snd.accept(awriter);
}
}
@ -974,9 +732,9 @@ public class ClassWriter extends ClassFile {
int alenIdx = writeAttr(names.Module);
databuf.appendChar(pool.put(m));
databuf.appendChar(poolWriter.putModule(m));
databuf.appendChar(ModuleFlags.value(m.flags)); // module_flags
databuf.appendChar(m.version != null ? pool.put(m.version) : 0);
databuf.appendChar(m.version != null ? poolWriter.putName(m.version) : 0);
ListBuffer<RequiresDirective> requires = new ListBuffer<>();
for (RequiresDirective r: m.requires) {
@ -985,22 +743,22 @@ public class ClassWriter extends ClassFile {
}
databuf.appendChar(requires.size());
for (RequiresDirective r: requires) {
databuf.appendChar(pool.put(r.module));
databuf.appendChar(poolWriter.putModule(r.module));
databuf.appendChar(RequiresFlag.value(r.flags));
databuf.appendChar(r.module.version != null ? pool.put(r.module.version) : 0);
databuf.appendChar(r.module.version != null ? poolWriter.putName(r.module.version) : 0);
}
List<ExportsDirective> exports = m.exports;
databuf.appendChar(exports.size());
for (ExportsDirective e: exports) {
databuf.appendChar(pool.put(e.packge));
databuf.appendChar(poolWriter.putPackage(e.packge));
databuf.appendChar(ExportsFlag.value(e.flags));
if (e.modules == null) {
databuf.appendChar(0);
} else {
databuf.appendChar(e.modules.size());
for (ModuleSymbol msym: e.modules) {
databuf.appendChar(pool.put(msym));
databuf.appendChar(poolWriter.putModule(msym));
}
}
}
@ -1008,14 +766,14 @@ public class ClassWriter extends ClassFile {
List<OpensDirective> opens = m.opens;
databuf.appendChar(opens.size());
for (OpensDirective o: opens) {
databuf.appendChar(pool.put(o.packge));
databuf.appendChar(poolWriter.putPackage(o.packge));
databuf.appendChar(OpensFlag.value(o.flags));
if (o.modules == null) {
databuf.appendChar(0);
} else {
databuf.appendChar(o.modules.size());
for (ModuleSymbol msym: o.modules) {
databuf.appendChar(pool.put(msym));
databuf.appendChar(poolWriter.putModule(msym));
}
}
}
@ -1023,7 +781,7 @@ public class ClassWriter extends ClassFile {
List<UsesDirective> uses = m.uses;
databuf.appendChar(uses.size());
for (UsesDirective s: uses) {
databuf.appendChar(pool.put(s.service));
databuf.appendChar(poolWriter.putClass(s.service));
}
// temporary fix to merge repeated provides clause for same service;
@ -1035,9 +793,9 @@ public class ClassWriter extends ClassFile {
}
databuf.appendChar(mergedProvides.size());
mergedProvides.forEach((srvc, impls) -> {
databuf.appendChar(pool.put(srvc));
databuf.appendChar(poolWriter.putClass(srvc));
databuf.appendChar(impls.size());
impls.forEach(impl -> databuf.appendChar(pool.put(impl)));
impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
});
endAttr(alenIdx);
@ -1048,46 +806,12 @@ public class ClassWriter extends ClassFile {
* Writing Objects
**********************************************************************/
/** Enter an inner class into the `innerClasses' set/queue.
*/
void enterInner(ClassSymbol c) {
if (c.type.isCompound()) {
throw new AssertionError("Unexpected intersection type: " + c.type);
}
try {
c.complete();
} catch (CompletionFailure ex) {
System.err.println("error: " + c + ": " + ex.getMessage());
throw ex;
}
if (!c.type.hasTag(CLASS)) return; // arrays
if (pool != null && // pool might be null if called from xClassName
c.owner.enclClass() != null &&
(innerClasses == null || !innerClasses.contains(c))) {
// log.errWriter.println("enter inner " + c);//DEBUG
enterInner(c.owner.enclClass());
pool.put(c);
if (c.name != names.empty)
pool.put(c.name);
if (innerClasses == null) {
innerClasses = new HashSet<>();
innerClassesQueue = new ListBuffer<>();
pool.put(names.InnerClasses);
}
innerClasses.add(c);
innerClassesQueue.append(c);
}
}
/** Write "inner classes" attribute.
*/
void writeInnerClasses() {
int alenIdx = writeAttr(names.InnerClasses);
databuf.appendChar(innerClassesQueue.length());
for (List<ClassSymbol> l = innerClassesQueue.toList();
l.nonEmpty();
l = l.tail) {
ClassSymbol inner = l.head;
databuf.appendChar(poolWriter.innerClasses.size());
for (ClassSymbol inner : poolWriter.innerClasses) {
inner.markAbstractIfNeeded(types);
char flags = (char) adjustFlags(inner.flags_field);
if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
@ -1097,11 +821,11 @@ public class ClassWriter extends ClassFile {
pw.println("INNERCLASS " + inner.name);
pw.println("---" + flagNames(flags));
}
databuf.appendChar(pool.get(inner));
databuf.appendChar(poolWriter.putClass(inner));
databuf.appendChar(
inner.owner.kind == TYP && !inner.name.isEmpty() ? pool.get(inner.owner) : 0);
inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0);
databuf.appendChar(
!inner.name.isEmpty() ? pool.get(inner.name) : 0);
!inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0);
databuf.appendChar(flags);
}
endAttr(alenIdx);
@ -1111,14 +835,14 @@ public class ClassWriter extends ClassFile {
* Write NestMembers attribute (if needed)
*/
int writeNestMembersIfNeeded(ClassSymbol csym) {
ListBuffer<Symbol> nested = new ListBuffer<>();
ListBuffer<ClassSymbol> nested = new ListBuffer<>();
listNested(csym, nested);
Set<Symbol> nestedUnique = new LinkedHashSet<>(nested);
Set<ClassSymbol> nestedUnique = new LinkedHashSet<>(nested);
if (csym.owner.kind == PCK && !nestedUnique.isEmpty()) {
int alenIdx = writeAttr(names.NestMembers);
databuf.appendChar(nestedUnique.size());
for (Symbol s : nestedUnique) {
databuf.appendChar(pool.put(s));
for (ClassSymbol s : nestedUnique) {
databuf.appendChar(poolWriter.putClass(s));
}
endAttr(alenIdx);
return 1;
@ -1132,14 +856,14 @@ public class ClassWriter extends ClassFile {
int writeNestHostIfNeeded(ClassSymbol csym) {
if (csym.owner.kind != PCK) {
int alenIdx = writeAttr(names.NestHost);
databuf.appendChar(pool.put(csym.outermostClass()));
databuf.appendChar(poolWriter.putClass(csym.outermostClass()));
endAttr(alenIdx);
return 1;
}
return 0;
}
private void listNested(Symbol sym, ListBuffer<Symbol> seen) {
private void listNested(Symbol sym, ListBuffer<ClassSymbol> seen) {
if (sym.kind != TYP) return;
ClassSymbol csym = (ClassSymbol)sym;
if (csym.owner.kind != PCK) {
@ -1161,17 +885,16 @@ public class ClassWriter extends ClassFile {
*/
void writeBootstrapMethods() {
int alenIdx = writeAttr(names.BootstrapMethods);
databuf.appendChar(bootstrapMethods.size());
for (Map.Entry<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> entry : bootstrapMethods.entrySet()) {
DynamicMethod.BootstrapMethodsKey bsmKey = entry.getKey();
databuf.appendChar(poolWriter.bootstrapMethods.size());
for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) {
//write BSM handle
databuf.appendChar(pool.get(entry.getValue().mh));
Object[] uniqueArgs = bsmKey.getUniqueArgs();
databuf.appendChar(poolWriter.putConstant(bsmKey.bsm));
LoadableConstant[] uniqueArgs = bsmKey.staticArgs;
//write static args length
databuf.appendChar(uniqueArgs.length);
//write static args array
for (Object o : uniqueArgs) {
databuf.appendChar(pool.get(o));
for (LoadableConstant arg : uniqueArgs) {
databuf.appendChar(poolWriter.putConstant(arg));
}
}
endAttr(alenIdx);
@ -1187,13 +910,13 @@ public class ClassWriter extends ClassFile {
pw.println("FIELD " + v.name);
pw.println("---" + flagNames(v.flags()));
}
databuf.appendChar(pool.put(v.name));
databuf.appendChar(pool.put(typeSig(v.erasure(types))));
databuf.appendChar(poolWriter.putName(v.name));
databuf.appendChar(poolWriter.putDescriptor(v));
int acountIdx = beginAttrs();
int acount = 0;
if (v.getConstValue() != null) {
int alenIdx = writeAttr(names.ConstantValue);
databuf.appendChar(pool.put(v.getConstValue()));
databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
endAttr(alenIdx);
acount++;
}
@ -1211,8 +934,8 @@ public class ClassWriter extends ClassFile {
pw.println("METHOD " + m.name);
pw.println("---" + flagNames(m.flags()));
}
databuf.appendChar(pool.put(m.name));
databuf.appendChar(pool.put(typeSig(m.externalType(types))));
databuf.appendChar(poolWriter.putName(m.name));
databuf.appendChar(poolWriter.putDescriptor(m));
int acountIdx = beginAttrs();
int acount = 0;
if (m.code != null) {
@ -1227,7 +950,7 @@ public class ClassWriter extends ClassFile {
int alenIdx = writeAttr(names.Exceptions);
databuf.appendChar(thrown.length());
for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
databuf.appendChar(pool.put(l.head.tsym));
databuf.appendChar(poolWriter.putClass(l.head));
endAttr(alenIdx);
acount++;
}
@ -1303,9 +1026,8 @@ public class ClassWriter extends ClassFile {
&& (r.start_pc + r.length) <= code.cp);
databuf.appendChar(r.length);
VarSymbol sym = var.sym;
databuf.appendChar(pool.put(sym.name));
Type vartype = sym.erasure(types);
databuf.appendChar(pool.put(typeSig(vartype)));
databuf.appendChar(poolWriter.putName(sym.name));
databuf.appendChar(poolWriter.putDescriptor(sym));
databuf.appendChar(var.reg);
if (needsLocalVariableTypeEntry(var.sym.type)) {
nGenericVars++;
@ -1329,8 +1051,8 @@ public class ClassWriter extends ClassFile {
// write variable info
databuf.appendChar(r.start_pc);
databuf.appendChar(r.length);
databuf.appendChar(pool.put(sym.name));
databuf.appendChar(pool.put(typeSig(sym.type)));
databuf.appendChar(poolWriter.putName(sym.name));
databuf.appendChar(poolWriter.putSignature(sym));
databuf.appendChar(var.reg);
count++;
}
@ -1457,14 +1179,10 @@ public class ClassWriter extends ClassFile {
break;
case CLASS:
case ARRAY:
if (debugstackmap) System.out.print("object(" + t + ")");
databuf.appendByte(7);
databuf.appendChar(pool.put(t));
break;
case TYPEVAR:
if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
databuf.appendByte(7);
databuf.appendChar(pool.put(types.erasure(t).tsym));
databuf.appendChar(poolWriter.putClass(types.erasure(t)));
break;
case UNINITIALIZED_THIS:
if (debugstackmap) System.out.print("uninit_this");
@ -1763,11 +1481,6 @@ public class ClassWriter extends ClassFile {
Assert.check((c.flags() & COMPOUND) == 0);
databuf.reset();
poolbuf.reset();
signatureGen.reset();
pool = c.pool;
innerClasses = null;
innerClassesQueue = null;
bootstrapMethods = new LinkedHashMap<>();
Type supertype = types.supertype(c.type);
List<Type> interfaces = types.interfaces(c.type);
@ -1793,14 +1506,14 @@ public class ClassWriter extends ClassFile {
if (c.owner.kind == MDL) {
PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
databuf.appendChar(pool.put(new ClassSymbol(0, names.module_info, unnamed)));
databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
} else {
databuf.appendChar(pool.put(c));
databuf.appendChar(poolWriter.putClass(c));
}
databuf.appendChar(supertype.hasTag(CLASS) ? pool.put(supertype.tsym) : 0);
databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
databuf.appendChar(interfaces.length());
for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
databuf.appendChar(pool.put(l.head.tsym));
databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
int fieldsCount = 0;
int methodsCount = 0;
for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
@ -1808,14 +1521,14 @@ public class ClassWriter extends ClassFile {
case VAR: fieldsCount++; break;
case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
break;
case TYP: enterInner((ClassSymbol)sym); break;
case TYP: poolWriter.enterInner((ClassSymbol)sym); break;
default : Assert.error();
}
}
if (c.trans_local != null) {
for (ClassSymbol local : c.trans_local) {
enterInner(local);
poolWriter.enterInner(local);
}
}
@ -1833,12 +1546,7 @@ public class ClassWriter extends ClassFile {
sigReq = l.head.allparams().length() != 0;
if (sigReq) {
int alenIdx = writeAttr(names.Signature);
if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams);
signatureGen.assembleSig(supertype);
for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
signatureGen.assembleSig(l.head);
databuf.appendChar(pool.put(signatureGen.toName()));
signatureGen.reset();
databuf.appendChar(poolWriter.putSignature(c));
endAttr(alenIdx);
acount++;
}
@ -1848,9 +1556,8 @@ public class ClassWriter extends ClassFile {
// WHM 6/29/1999: Strip file path prefix. We do it here at
// the last possible moment because the sourcefile may be used
// elsewhere in error diagnostics. Fixes 4241573.
//databuf.appendChar(c.pool.put(c.sourcefile));
String simpleName = PathFileObject.getSimpleName(c.sourcefile);
databuf.appendChar(c.pool.put(names.fromString(simpleName)));
databuf.appendChar(poolWriter.putName(names.fromString(simpleName)));
endAttr(alenIdx);
acount++;
}
@ -1858,12 +1565,12 @@ public class ClassWriter extends ClassFile {
if (genCrt) {
// Append SourceID attribute
int alenIdx = writeAttr(names.SourceID);
databuf.appendChar(c.pool.put(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
endAttr(alenIdx);
acount++;
// Append CompilationID attribute
alenIdx = writeAttr(names.CompilationID);
databuf.appendChar(c.pool.put(names.fromString(Long.toString(System.currentTimeMillis()))));
databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis()))));
endAttr(alenIdx);
acount++;
}
@ -1893,24 +1600,24 @@ public class ClassWriter extends ClassFile {
}
}
writePool(c.pool);
if (innerClasses != null) {
writeInnerClasses();
if (!poolWriter.bootstrapMethods.isEmpty()) {
writeBootstrapMethods();
acount++;
}
if (!bootstrapMethods.isEmpty()) {
writeBootstrapMethods();
if (!poolWriter.innerClasses.isEmpty()) {
writeInnerClasses();
acount++;
}
endAttrs(acountIdx, acount);
poolbuf.appendBytes(databuf.elems, 0, databuf.length);
out.write(poolbuf.elems, 0, poolbuf.length);
pool = c.pool = null; // to conserve space
poolWriter.writePool(out);
poolWriter.reset(); // to save space
out.write(databuf.elems, 0, databuf.length);
}
/**Allows subclasses to write additional class attributes

@ -27,15 +27,27 @@ package com.sun.tools.javac.jvm;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import java.util.function.ToIntBiFunction;
import java.util.function.ToIntFunction;
import static com.sun.tools.javac.code.TypeTag.BOT;
import static com.sun.tools.javac.code.TypeTag.INT;
import static com.sun.tools.javac.jvm.ByteCodes.*;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
import static com.sun.tools.javac.jvm.UninitializedType.*;
import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
@ -72,6 +84,7 @@ public class Code {
final Types types;
final Symtab syms;
final PoolWriter poolWriter;
/*---------- classfile fields: --------------- */
@ -177,10 +190,6 @@ public class Code {
*/
Position.LineMap lineMap;
/** The constant pool of the current class.
*/
final Pool pool;
final MethodSymbol meth;
private int letExprStackPos = 0;
@ -197,7 +206,7 @@ public class Code {
CRTable crt,
Symtab syms,
Types types,
Pool pool) {
PoolWriter poolWriter) {
this.meth = meth;
this.fatcode = fatcode;
this.lineMap = lineMap;
@ -206,6 +215,7 @@ public class Code {
this.crt = crt;
this.syms = syms;
this.types = types;
this.poolWriter = poolWriter;
this.debugCode = debugCode;
this.stackMap = stackMap;
switch (stackMap) {
@ -218,7 +228,6 @@ public class Code {
}
state = new State();
lvar = new LocalVar[20];
this.pool = pool;
}
@ -389,12 +398,13 @@ public class Code {
/** Emit a ldc (or ldc_w) instruction, taking into account operand size
*/
public void emitLdc(int od) {
public void emitLdc(LoadableConstant constant) {
int od = poolWriter.putConstant(constant);
if (od <= 255) {
emitop1(ldc1, od);
emitop1(ldc1, od, constant);
}
else {
emitop2(ldc2, od);
emitop2(ldc2, od, constant);
}
}
@ -431,11 +441,11 @@ public class Code {
/** Emit an invokeinterface instruction.
*/
public void emitInvokeinterface(int meth, Type mtype) {
public void emitInvokeinterface(Symbol member, Type mtype) {
int argsize = width(mtype.getParameterTypes());
emitop(invokeinterface);
if (!alive) return;
emit2(meth);
emit2(poolWriter.putMember(member));
emit1(argsize + 1);
emit1(0);
state.pop(argsize + 1);
@ -444,14 +454,13 @@ public class Code {
/** Emit an invokespecial instruction.
*/
public void emitInvokespecial(int meth, Type mtype) {
public void emitInvokespecial(Symbol member, Type mtype) {
int argsize = width(mtype.getParameterTypes());
emitop(invokespecial);
if (!alive) return;
emit2(meth);
Symbol sym = (Symbol)pool.pool[meth];
emit2(poolWriter.putMember(member));
state.pop(argsize);
if (sym.isConstructor())
if (member.isConstructor())
state.markInitialized((UninitializedType)state.peek());
state.pop(1);
state.push(mtype.getReturnType());
@ -459,33 +468,33 @@ public class Code {
/** Emit an invokestatic instruction.
*/
public void emitInvokestatic(int meth, Type mtype) {
public void emitInvokestatic(Symbol member, Type mtype) {
int argsize = width(mtype.getParameterTypes());
emitop(invokestatic);
if (!alive) return;
emit2(meth);
emit2(poolWriter.putMember(member));
state.pop(argsize);
state.push(mtype.getReturnType());
}
/** Emit an invokevirtual instruction.
*/
public void emitInvokevirtual(int meth, Type mtype) {
public void emitInvokevirtual(Symbol member, Type mtype) {
int argsize = width(mtype.getParameterTypes());
emitop(invokevirtual);
if (!alive) return;
emit2(meth);
emit2(poolWriter.putMember(member));
state.pop(argsize + 1);
state.push(mtype.getReturnType());
}
/** Emit an invokedynamic instruction.
*/
public void emitInvokedynamic(int desc, Type mtype) {
public void emitInvokedynamic(DynamicMethodSymbol dynMember, Type mtype) {
int argsize = width(mtype.getParameterTypes());
emitop(invokedynamic);
if (!alive) return;
emit2(desc);
emit2(poolWriter.putDynamic(dynMember));
emit2(0);
state.pop(argsize);
state.push(mtype.getReturnType());
@ -896,6 +905,10 @@ public class Code {
/** Emit an opcode with a one-byte operand field.
*/
public void emitop1(int op, int od) {
emitop1(op, od, null);
}
public void emitop1(int op, int od, PoolConstant data) {
emitop(op);
if (!alive) return;
emit1(od);
@ -904,7 +917,7 @@ public class Code {
state.push(syms.intType);
break;
case ldc1:
state.push(typeForPool(pool.pool[od]));
state.push(types.constantType((LoadableConstant)data));
break;
default:
throw new AssertionError(mnem(op));
@ -912,25 +925,6 @@ public class Code {
postop();
}
/** The type of a constant pool entry. */
private Type typeForPool(Object o) {
if (o instanceof Integer) return syms.intType;
if (o instanceof Float) return syms.floatType;
if (o instanceof String) return syms.stringType;
if (o instanceof Long) return syms.longType;
if (o instanceof Double) return syms.doubleType;
if (o instanceof ClassSymbol) return syms.classType;
if (o instanceof Pool.MethodHandle) return syms.methodHandleType;
if (o instanceof UniqueType) return typeForPool(((UniqueType)o).type);
if (o instanceof Type) {
Type ty = (Type) o;
if (ty instanceof Type.ArrayType) return syms.classType;
if (ty instanceof Type.MethodType) return syms.methodTypeType;
}
throw new AssertionError("Invalid type of constant pool entry: " + o.getClass());
}
/** Emit an opcode with a one-byte operand field;
* widen if field does not fit in a byte.
*/
@ -1003,29 +997,31 @@ public class Code {
/** Emit an opcode with a two-byte operand field.
*/
public <P extends PoolConstant> void emitop2(int op, P constant, ToIntBiFunction<PoolWriter, P> poolFunc) {
int od = poolFunc.applyAsInt(poolWriter, constant);
emitop2(op, od, constant);
}
public void emitop2(int op, int od) {
emitop2(op, od, null);
}
public void emitop2(int op, int od, PoolConstant data) {
emitop(op);
if (!alive) return;
emit2(od);
switch (op) {
case getstatic:
state.push(((Symbol)(pool.pool[od])).erasure(types));
state.push(((Symbol)data).erasure(types));
break;
case putstatic:
state.pop(((Symbol)(pool.pool[od])).erasure(types));
state.pop(((Symbol)data).erasure(types));
break;
case new_:
Symbol sym;
if (pool.pool[od] instanceof UniqueType) {
// Required by change in Gen.makeRef to allow
// annotated types.
// TODO: is this needed anywhere else?
sym = ((UniqueType)(pool.pool[od])).type.tsym;
} else {
sym = (Symbol)(pool.pool[od]);
}
state.push(uninitializedObject(sym.erasure(types), cp-3));
case new_: {
Type t = (Type)data;
state.push(uninitializedObject(t.tsym.erasure(types), cp-3));
break;
}
case sipush:
state.push(syms.intType);
break;
@ -1053,30 +1049,27 @@ public class Code {
markDead();
break;
case putfield:
state.pop(((Symbol)(pool.pool[od])).erasure(types));
state.pop(((Symbol)data).erasure(types));
state.pop(1); // object ref
break;
case getfield:
state.pop(1); // object ref
state.push(((Symbol)(pool.pool[od])).erasure(types));
state.push(((Symbol)data).erasure(types));
break;
case checkcast: {
state.pop(1); // object ref
Object o = pool.pool[od];
Type t = (o instanceof Symbol)
? ((Symbol)o).erasure(types)
: types.erasure((((UniqueType)o).type));
Type t = types.erasure((Type)data);
state.push(t);
break; }
case ldc2w:
state.push(typeForPool(pool.pool[od]));
state.push(types.constantType((LoadableConstant)data));
break;
case instanceof_:
state.pop(1);
state.push(syms.intType);
break;
case ldc2:
state.push(typeForPool(pool.pool[od]));
state.push(types.constantType((LoadableConstant)data));
break;
case jsr:
break;

@ -25,6 +25,7 @@
package com.sun.tools.javac.jvm;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
import com.sun.tools.javac.tree.TreeInfo.PosKind;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@ -88,9 +89,9 @@ public class Gen extends JCTree.Visitor {
return instance;
}
/** Constant pool, reset by genClass.
/** Constant pool writer, set by genClass.
*/
private final Pool pool;
final PoolWriter poolWriter;
protected Gen(Context context) {
context.put(genKey, this);
@ -121,7 +122,7 @@ public class Gen extends JCTree.Visitor {
genCrt = options.isSet(XJCOV);
debugCode = options.isSet("debug.code");
disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
pool = new Pool(types);
poolWriter = new PoolWriter(types, names);
// ignore cldc because we cannot have both stackmap formats
this.stackMap = StackMapFormat.JSR202;
@ -252,17 +253,17 @@ public class Gen extends JCTree.Visitor {
* @param type The type for which a reference is inserted.
*/
int makeRef(DiagnosticPosition pos, Type type) {
checkDimension(pos, type);
if (type.isAnnotated()) {
return pool.put((Object)type);
} else {
return pool.put(type.hasTag(CLASS) ? (Object)type.tsym : (Object)type);
}
return poolWriter.putClass(checkDimension(pos, type));
}
/** Check if the given type is an array with too many dimensions.
*/
private void checkDimension(DiagnosticPosition pos, Type t) {
private Type checkDimension(DiagnosticPosition pos, Type t) {
checkDimensionInternal(pos, t);
return t;
}
private void checkDimensionInternal(DiagnosticPosition pos, Type t) {
switch (t.getTag()) {
case METHOD:
checkDimension(pos, t.getReturnType());
@ -516,7 +517,7 @@ public class Gen extends JCTree.Visitor {
if (nerrs != 0 || // only complain about a long string once
constValue == null ||
!(constValue instanceof String) ||
((String)constValue).length() < Pool.MAX_STRING_LENGTH)
((String)constValue).length() < PoolWriter.MAX_STRING_LENGTH)
return;
log.error(pos, Errors.LimitString);
nerrs++;
@ -806,7 +807,7 @@ public class Gen extends JCTree.Visitor {
@Override
public void visitIdent(JCIdent tree) {
if (tree.sym.owner instanceof ClassSymbol) {
pool.put(tree.sym.owner);
poolWriter.putClass((ClassSymbol)tree.sym.owner);
}
}
@ -1007,8 +1008,8 @@ public class Gen extends JCTree.Visitor {
: null,
syms,
types,
pool);
items = new Items(pool, code, syms, types);
poolWriter);
items = new Items(poolWriter, code, syms, types);
if (code.debugCode) {
System.err.println(meth + " for body " + tree);
}
@ -1886,7 +1887,7 @@ public class Gen extends JCTree.Visitor {
Assert.check(tree.encl == null && tree.def == null);
setTypeAnnotationPositions(tree.pos);
code.emitop2(new_, makeRef(tree.pos(), tree.type));
code.emitop2(new_, checkDimension(tree.pos(), tree.type), PoolWriter::putClass);
code.emitop0(dup);
// Generate code for all arguments, where the expected types are
@ -2162,7 +2163,7 @@ public class Gen extends JCTree.Visitor {
if (!tree.clazz.type.isPrimitive() &&
!types.isSameType(tree.expr.type, tree.clazz.type) &&
types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
code.emitop2(checkcast, makeRef(tree.pos(), tree.clazz.type));
code.emitop2(checkcast, checkDimension(tree.pos(), tree.clazz.type), PoolWriter::putClass);
}
}
@ -2221,7 +2222,7 @@ public class Gen extends JCTree.Visitor {
Symbol sym = tree.sym;
if (tree.name == names._class) {
code.emitLdc(makeRef(tree.pos(), tree.selected.type));
code.emitLdc((LoadableConstant)checkDimension(tree.pos(), tree.selected.type));
result = items.makeStackItem(pt);
return;
}
@ -2305,7 +2306,7 @@ public class Gen extends JCTree.Visitor {
code.endScopes(limit);
}
private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) {
private void generateReferencesToPrunedTree(ClassSymbol classSymbol) {
List<JCTree> prunedInfo = lower.prunedTree.get(classSymbol);
if (prunedInfo != null) {
for (JCTree prunedTree: prunedInfo) {
@ -2331,12 +2332,10 @@ public class Gen extends JCTree.Visitor {
ClassSymbol c = cdef.sym;
this.toplevel = env.toplevel;
this.endPosTable = toplevel.endPositions;
c.pool = pool;
pool.reset();
/* method normalizeDefs() can add references to external classes into the constant pool
*/
cdef.defs = normalizeDefs(cdef.defs, c);
generateReferencesToPrunedTree(c, pool);
generateReferencesToPrunedTree(c);
Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
localEnv.toplevel = env.toplevel;
localEnv.enclClass = cdef;
@ -2344,7 +2343,7 @@ public class Gen extends JCTree.Visitor {
for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
genDef(l.head, localEnv);
}
if (pool.numEntries() > Pool.MAX_ENTRIES) {
if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
log.error(cdef.pos(), Errors.LimitPool);
nerrs++;
}

@ -29,6 +29,8 @@ import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.jvm.Code.*;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Assert;
@ -50,9 +52,9 @@ import static com.sun.tools.javac.jvm.ByteCodes.*;
*/
public class Items {
/** The current constant pool.
/** The current constant pool writer.
*/
Pool pool;
PoolWriter poolWriter;
/** The current code buffer.
*/
@ -72,9 +74,9 @@ public class Items {
private final Item superItem;
private final Item[] stackItem = new Item[TypeCodeCount];
public Items(Pool pool, Code code, Symtab syms, Types types) {
public Items(PoolWriter poolWriter, Code code, Symtab syms, Types types) {
this.code = code;
this.pool = pool;
this.poolWriter = poolWriter;
this.types = types;
voidItem = new Item(VOIDcode) {
public String toString() { return "void"; }
@ -444,18 +446,18 @@ public class Items {
}
Item load() {
code.emitop2(getstatic, pool.put(member));
code.emitop2(getstatic, member, PoolWriter::putMember);
return stackItem[typecode];
}
void store() {
code.emitop2(putstatic, pool.put(member));
code.emitop2(putstatic, member, PoolWriter::putMember);
}
Item invoke() {
MethodType mtype = (MethodType)member.erasure(types);
int rescode = Code.typecode(mtype.restype);
code.emitInvokestatic(pool.put(member), mtype);
code.emitInvokestatic(member, mtype);
return stackItem[rescode];
}
@ -484,7 +486,7 @@ public class Items {
// assert target.hasNativeInvokeDynamic();
MethodType mtype = (MethodType)member.erasure(types);
int rescode = Code.typecode(mtype.restype);
code.emitInvokedynamic(pool.put(member), mtype);
code.emitInvokedynamic((DynamicMethodSymbol)member, mtype);
return stackItem[rescode];
}
@ -512,23 +514,23 @@ public class Items {
}
Item load() {
code.emitop2(getfield, pool.put(member));
code.emitop2(getfield, member, PoolWriter::putMember);
return stackItem[typecode];
}
void store() {
code.emitop2(putfield, pool.put(member));
code.emitop2(putfield, member, PoolWriter::putMember);
}
Item invoke() {
MethodType mtype = (MethodType)member.externalType(types);
int rescode = Code.typecode(mtype.restype);
if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) {
code.emitInvokeinterface(pool.put(member), mtype);
code.emitInvokeinterface(member, mtype);
} else if (nonvirtual) {
code.emitInvokespecial(pool.put(member), mtype);
code.emitInvokespecial(member, mtype);
} else {
code.emitInvokevirtual(pool.put(member), mtype);
code.emitInvokevirtual(member, mtype);
}
return stackItem[rescode];
}
@ -560,26 +562,50 @@ public class Items {
/** The literal's value.
*/
Object value;
final LoadableConstant value;
ImmediateItem(Type type, Object value) {
super(Code.typecode(type));
this.value = value;
switch (typecode) {
case BYTEcode:
case SHORTcode:
case CHARcode:
case INTcode:
this.value = LoadableConstant.Int((int)value);
break;
case LONGcode:
this.value = LoadableConstant.Long((long)value);
break;
case FLOATcode:
this.value = LoadableConstant.Float((float)value);
break;
case DOUBLEcode:
this.value = LoadableConstant.Double((double)value);
break;
case OBJECTcode:
this.value = LoadableConstant.String((String)value);
break;
default:
throw new UnsupportedOperationException("unsupported tag: " + typecode);
}
}
private void ldc() {
int idx = pool.put(value);
if (typecode == LONGcode || typecode == DOUBLEcode) {
code.emitop2(ldc2w, idx);
code.emitop2(ldc2w, value, PoolWriter::putConstant);
} else {
code.emitLdc(idx);
code.emitLdc(value);
}
}
private Number numericValue() {
return (Number)((BasicConstant)value).data;
}
Item load() {
switch (typecode) {
case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
int ival = ((Number)value).intValue();
int ival = numericValue().intValue();
if (-1 <= ival && ival <= 5)
code.emitop0(iconst_0 + ival);
else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
@ -590,14 +616,14 @@ public class Items {
ldc();
break;
case LONGcode:
long lval = ((Number)value).longValue();
long lval = numericValue().longValue();
if (lval == 0 || lval == 1)
code.emitop0(lconst_0 + (int)lval);
else
ldc();
break;
case FLOATcode:
float fval = ((Number)value).floatValue();
float fval = numericValue().floatValue();
if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
code.emitop0(fconst_0 + (int)fval);
else {
@ -605,7 +631,7 @@ public class Items {
}
break;
case DOUBLEcode:
double dval = ((Number)value).doubleValue();
double dval = numericValue().doubleValue();
if (isPosZero(dval) || dval == 1.0)
code.emitop0(dconst_0 + (int)dval);
else
@ -632,7 +658,7 @@ public class Items {
}
CondItem mkCond() {
int ival = ((Number)value).intValue();
int ival = numericValue().intValue();
return makeCondItem(ival != 0 ? goto_ : dontgoto);
}
@ -647,31 +673,31 @@ public class Items {
else
return new ImmediateItem(
syms.intType,
((Number)value).intValue());
numericValue().intValue());
case LONGcode:
return new ImmediateItem(
syms.longType,
((Number)value).longValue());
numericValue().longValue());
case FLOATcode:
return new ImmediateItem(
syms.floatType,
((Number)value).floatValue());
numericValue().floatValue());
case DOUBLEcode:
return new ImmediateItem(
syms.doubleType,
((Number)value).doubleValue());
numericValue().doubleValue());
case BYTEcode:
return new ImmediateItem(
syms.byteType,
(int)(byte)((Number)value).intValue());
(int)(byte)numericValue().intValue());
case CHARcode:
return new ImmediateItem(
syms.charType,
(int)(char)((Number)value).intValue());
(int)(char)numericValue().intValue());
case SHORTcode:
return new ImmediateItem(
syms.shortType,
(int)(short)((Number)value).intValue());
(int)(short)numericValue().intValue());
default:
return super.coerce(targetcode);
}

@ -24,6 +24,9 @@
*/
package com.sun.tools.javac.jvm;
import com.sun.tools.javac.util.ByteBuffer;
import com.sun.tools.javac.util.Name.NameMapper;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
@ -55,16 +58,15 @@ public class ModuleNameReader {
/** The buffer containing the currently read class file.
*/
private byte[] buf = new byte[INITIAL_BUFFER_SIZE];
private ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE);
/** The current input pointer.
*/
private int bp;
/** For every constant pool entry, an index into buf where the
* defining section of the entry is found.
/** The constant pool reader.
*/
private int[] poolIdx;
private PoolReader reader;
public ModuleNameReader() {
}
@ -83,7 +85,8 @@ public class ModuleNameReader {
public String readModuleName(InputStream in) throws IOException, BadClassFile {
bp = 0;
buf = readInputStream(buf, in);
buf.reset();
buf.appendStream(in);
int magic = nextInt();
if (magic != JAVA_MAGIC)
@ -94,7 +97,8 @@ public class ModuleNameReader {
if (majorVersion < 53)
throw new BadClassFile("bad major version number for module: " + majorVersion);
indexPool();
reader = new PoolReader(buf);
bp = reader.readPool(buf, bp);
int access_flags = nextChar();
if (access_flags != 0x8000)
@ -110,8 +114,8 @@ public class ModuleNameReader {
for (int i = 0; i < attributes_count; i++) {
int attr_name = nextChar();
int attr_length = nextInt();
if (getUtf8Value(attr_name, false).equals("Module") && attr_length > 2) {
return getModuleName(nextChar());
if (reader.peekName(attr_name, utf8Mapper(false)).equals("Module") && attr_length > 2) {
return reader.peekModuleName(nextChar(), utf8Mapper(true));
} else {
// skip over unknown attributes
bp += attr_length;
@ -125,132 +129,26 @@ public class ModuleNameReader {
throw new BadClassFile("invalid " + name + " for module: " + count);
}
/** Extract a character at position bp from buf.
*/
char getChar(int bp) {
return
(char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
}
/** Read a character.
*/
char nextChar() {
return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
char res = buf.getChar(bp);
bp += 2;
return res;
}
/** Read an integer.
*/
int nextInt() {
return
((buf[bp++] & 0xFF) << 24) +
((buf[bp++] & 0xFF) << 16) +
((buf[bp++] & 0xFF) << 8) +
(buf[bp++] & 0xFF);
int res = buf.getInt(bp);
bp += 4;
return res;
}
/** Index all constant pool entries, writing their start addresses into
* poolIdx.
*/
void indexPool() throws BadClassFile {
poolIdx = new int[nextChar()];
int i = 1;
while (i < poolIdx.length) {
poolIdx[i++] = bp;
byte tag = buf[bp++];
switch (tag) {
case CONSTANT_Utf8: case CONSTANT_Unicode: {
int len = nextChar();
bp = bp + len;
break;
}
case CONSTANT_Class:
case CONSTANT_String:
case CONSTANT_MethodType:
case CONSTANT_Module:
case CONSTANT_Package:
bp = bp + 2;
break;
case CONSTANT_MethodHandle:
bp = bp + 3;
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_NameandType:
case CONSTANT_Integer:
case CONSTANT_Float:
case CONSTANT_InvokeDynamic:
bp = bp + 4;
break;
case CONSTANT_Long:
case CONSTANT_Double:
bp = bp + 8;
i++;
break;
default:
throw new BadClassFile("malformed constant pool");
}
}
NameMapper<String> utf8Mapper(boolean internalize) {
return internalize ?
(buf, offset, len) -> new String(ClassFile.internalize(buf, offset, len)) :
String::new;
}
String getUtf8Value(int index, boolean internalize) throws BadClassFile {
int utf8Index = poolIdx[index];
if (buf[utf8Index] == CONSTANT_Utf8) {
int len = getChar(utf8Index + 1);
int start = utf8Index + 3;
if (internalize) {
return new String(ClassFile.internalize(buf, start, len));
} else {
return new String(buf, start, len);
}
}
throw new BadClassFile("bad name at index " + index);
}
String getModuleName(int index) throws BadClassFile {
int infoIndex = poolIdx[index];
if (buf[infoIndex] == CONSTANT_Module) {
return getUtf8Value(getChar(infoIndex + 1), true);
} else {
throw new BadClassFile("bad module name at index " + index);
}
}
private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
try {
buf = ensureCapacity(buf, s.available());
int r = s.read(buf);
int bp = 0;
while (r != -1) {
bp += r;
buf = ensureCapacity(buf, bp);
r = s.read(buf, bp, buf.length - bp);
}
return buf;
} finally {
try {
s.close();
} catch (IOException e) {
/* Ignore any errors, as this stream may have already
* thrown a related exception which is the one that
* should be reported.
*/
}
}
}
/*
* ensureCapacity will increase the buffer as needed, taking note that
* the new buffer will always be greater than the needed and never
* exactly equal to the needed size or bp. If equal then the read (above)
* will infinitely loop as buf.length - bp == 0.
*/
private static byte[] ensureCapacity(byte[] buf, int needed) {
if (buf.length <= needed) {
byte[] old = buf;
buf = new byte[Integer.highestOneBit(needed) << 1];
System.arraycopy(old, 0, buf, 0, old.length);
}
return buf;
}
}

@ -1,372 +0,0 @@
/*
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.jvm;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.util.ArrayUtils;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Filter;
import com.sun.tools.javac.util.Name;
import java.util.*;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import static com.sun.tools.javac.code.Kinds.*;
import static com.sun.tools.javac.code.Kinds.Kind.*;
/** An internal structure that corresponds to the constant pool of a classfile.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Pool {
public static final int MAX_ENTRIES = 0xFFFF;
public static final int MAX_STRING_LENGTH = 0xFFFF;
/** Index of next constant to be entered.
*/
int pp;
/** The initial pool buffer.
*/
Object[] pool;
/** A hashtable containing all constants in the pool.
*/
Map<Object,Integer> indices;
Types types;
/** Construct a pool with given number of elements and element array.
*/
public Pool(int pp, Object[] pool, Types types) {
this.pp = pp;
this.pool = pool;
this.types = types;
this.indices = new HashMap<>(pool.length);
for (int i = 1; i < pp; i++) {
if (pool[i] != null) indices.put(pool[i], i);
}
}
/** Construct an empty pool.
*/
public Pool(Types types) {
this(1, new Object[64], types);
}
/** Return the number of entries in the constant pool.
*/
public int numEntries() {
return pp;
}
/** Remove everything from this pool.
*/
public void reset() {
pp = 1;
indices.clear();
}
/** Place an object in the pool, unless it is already there.
* If object is a symbol also enter its owner unless the owner is a
* package. Return the object's index in the pool.
*/
public int put(Object value) {
value = makePoolValue(value);
Assert.check(!(value instanceof Type.TypeVar));
Assert.check(!(value instanceof Types.UniqueType &&
((UniqueType) value).type instanceof Type.TypeVar));
Integer index = indices.get(value);
if (index == null) {
index = pp;
indices.put(value, index);
pool = ArrayUtils.ensureCapacity(pool, pp);
pool[pp++] = value;
if (value instanceof Long || value instanceof Double) {
pool = ArrayUtils.ensureCapacity(pool, pp);
pool[pp++] = null;
}
}
return index.intValue();
}
Object makePoolValue(Object o) {
if (o instanceof DynamicMethodSymbol) {
return new DynamicMethod((DynamicMethodSymbol)o, types);
} else if (o instanceof MethodSymbol) {
return new Method((MethodSymbol)o, types);
} else if (o instanceof VarSymbol) {
return new Variable((VarSymbol)o, types);
} else if (o instanceof Type) {
Type t = (Type)o;
// ClassRefs can come from ClassSymbols or from Types.
// Return the symbol for these types to avoid duplicates
// in the constant pool
if (t.hasTag(TypeTag.CLASS))
return t.tsym;
else
return new UniqueType(t, types);
} else {
return o;
}
}
/** Return the given object's index in the pool,
* or -1 if object is not in there.
*/
public int get(Object o) {
Integer n = indices.get(o);
return n == null ? -1 : n.intValue();
}
static class Method extends DelegatedSymbol<MethodSymbol> {
UniqueType uniqueType;
Method(MethodSymbol m, Types types) {
super(m);
this.uniqueType = new UniqueType(m.type, types);
}
@DefinedBy(Api.LANGUAGE_MODEL)
public boolean equals(Object any) {
if (!(any instanceof Method)) return false;
MethodSymbol o = ((Method)any).other;
MethodSymbol m = this.other;
return
o.name == m.name &&
o.owner == m.owner &&
((Method)any).uniqueType.equals(uniqueType);
}
@DefinedBy(Api.LANGUAGE_MODEL)
public int hashCode() {
MethodSymbol m = this.other;
return
m.name.hashCode() * 33 +
m.owner.hashCode() * 9 +
uniqueType.hashCode();
}
}
public static class DynamicMethod extends Method {
public Object[] uniqueStaticArgs;
public DynamicMethod(DynamicMethodSymbol m, Types types) {
super(m, types);
uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types);
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public boolean equals(Object any) {
return equalsImpl(any, true);
}
protected boolean equalsImpl(Object any, boolean includeDynamicArgs) {
if (includeDynamicArgs && !super.equals(any)) return false;
if (!(any instanceof DynamicMethod)) return false;
DynamicMethodSymbol dm1 = (DynamicMethodSymbol)other;
DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)any).other;
return dm1.bsm == dm2.bsm &&
dm1.bsmKind == dm2.bsmKind &&
Arrays.equals(uniqueStaticArgs,
((DynamicMethod)any).uniqueStaticArgs);
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public int hashCode() {
return hashCodeImpl(true);
}
protected int hashCodeImpl(boolean includeDynamicArgs) {
int hash = includeDynamicArgs ? super.hashCode() : 0;
DynamicMethodSymbol dm = (DynamicMethodSymbol)other;
hash += dm.bsmKind * 7 +
dm.bsm.hashCode() * 11;
for (int i = 0; i < dm.staticArgs.length; i++) {
hash += (uniqueStaticArgs[i].hashCode() * 23);
}
return hash;
}
private Object[] getUniqueTypeArray(Object[] objects, Types types) {
Object[] result = new Object[objects.length];
for (int i = 0; i < objects.length; i++) {
if (objects[i] instanceof Type) {
result[i] = new UniqueType((Type)objects[i], types);
} else {
result[i] = objects[i];
}
}
return result;
}
static class BootstrapMethodsKey extends DynamicMethod {
BootstrapMethodsKey(DynamicMethodSymbol m, Types types) {
super(m, types);
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public boolean equals(Object any) {
return equalsImpl(any, false);
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public int hashCode() {
return hashCodeImpl(false);
}
Object[] getUniqueArgs() {
return uniqueStaticArgs;
}
}
static class BootstrapMethodsValue {
final MethodHandle mh;
final int index;
public BootstrapMethodsValue(MethodHandle mh, int index) {
this.mh = mh;
this.index = index;
}
}
}
static class Variable extends DelegatedSymbol<VarSymbol> {
UniqueType uniqueType;
Variable(VarSymbol v, Types types) {
super(v);
this.uniqueType = new UniqueType(v.type, types);
}
@DefinedBy(Api.LANGUAGE_MODEL)
public boolean equals(Object any) {
if (!(any instanceof Variable)) return false;
VarSymbol o = ((Variable)any).other;
VarSymbol v = other;
return
o.name == v.name &&
o.owner == v.owner &&
((Variable)any).uniqueType.equals(uniqueType);
}
@DefinedBy(Api.LANGUAGE_MODEL)
public int hashCode() {
VarSymbol v = other;
return
v.name.hashCode() * 33 +
v.owner.hashCode() * 9 +
uniqueType.hashCode();
}
}
public static class MethodHandle {
/** Reference kind - see ClassFile */
int refKind;
/** Reference symbol */
Symbol refSym;
UniqueType uniqueType;
public MethodHandle(int refKind, Symbol refSym, Types types) {
this.refKind = refKind;
this.refSym = refSym;
this.uniqueType = new UniqueType(this.refSym.type, types);
checkConsistent();
}
public boolean equals(Object other) {
if (!(other instanceof MethodHandle)) return false;
MethodHandle mr = (MethodHandle) other;
if (mr.refKind != refKind) return false;
Symbol o = mr.refSym;
return
o.name == refSym.name &&
o.owner == refSym.owner &&
((MethodHandle)other).uniqueType.equals(uniqueType);
}
public int hashCode() {
return
refKind * 65 +
refSym.name.hashCode() * 33 +
refSym.owner.hashCode() * 9 +
uniqueType.hashCode();
}
/**
* Check consistency of reference kind and symbol (see JVMS 4.4.8)
*/
@SuppressWarnings("fallthrough")
private void checkConsistent() {
boolean staticOk = false;
Kind expectedKind = null;
Filter<Name> nameFilter = nonInitFilter;
boolean interfaceOwner = false;
switch (refKind) {
case ClassFile.REF_getStatic:
case ClassFile.REF_putStatic:
staticOk = true;
case ClassFile.REF_getField:
case ClassFile.REF_putField:
expectedKind = VAR;
break;
case ClassFile.REF_newInvokeSpecial:
nameFilter = initFilter;
expectedKind = MTH;
break;
case ClassFile.REF_invokeInterface:
interfaceOwner = true;
expectedKind = MTH;
break;
case ClassFile.REF_invokeStatic:
interfaceOwner = true;
staticOk = true;
case ClassFile.REF_invokeVirtual:
expectedKind = MTH;
break;
case ClassFile.REF_invokeSpecial:
interfaceOwner = true;
expectedKind = MTH;
break;
}
Assert.check(!refSym.isStatic() || staticOk);
Assert.check(refSym.kind == expectedKind);
Assert.check(nameFilter.accepts(refSym.name));
Assert.check(!refSym.owner.isInterface() || interfaceOwner);
}
//where
Filter<Name> nonInitFilter = n -> (n != n.table.names.init && n != n.table.names.clinit);
Filter<Name> initFilter = n -> n == n.table.names.init;
}
}

@ -0,0 +1,224 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.jvm;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Pair;
import java.util.Objects;
import java.util.stream.Stream;
/**
* This interface models all javac entities that can be used to represent constant pool entries.
* A pool constant entity must (i) be associated with a constant pool entry tag and have a function
* which generates a key for the desired pool entry (so as to avoid duplicate entries when writing the
* constant pool).
*/
public interface PoolConstant {
/**
* The constant pool entry key.
*/
default Object poolKey(Types types) { return this; }
/**
* The constant pool entry tag.
*/
int poolTag();
/**
* The root of pool constants that can be loaded (e.g. with {@code ldc}, or appear as static
* arguments to a bootstrap method.
*/
interface LoadableConstant extends PoolConstant {
/**
* Create a pool constant describing a given {@code int} value.
*/
static LoadableConstant Int(int i) {
return new BasicConstant(ClassFile.CONSTANT_Integer, i);
}
/**
* Create a pool constant describing a given {@code float} value.
*/
static LoadableConstant Float(float f) {
return new BasicConstant(ClassFile.CONSTANT_Float, f);
}
/**
* Create a pool constant describing a given {@code long} value.
*/
static LoadableConstant Long(long l) {
return new BasicConstant(ClassFile.CONSTANT_Long, l);
}
/**
* Create a pool constant describing a given {@code double} value.
*/
static LoadableConstant Double(double d) {
return new BasicConstant(ClassFile.CONSTANT_Double, d);
}
/**
* Create a pool constant describing a given {@code String} value.
*/
static LoadableConstant String(String s) {
return new BasicConstant(ClassFile.CONSTANT_String, s);
}
/**
* This class models a pool constant of given basic type, one of {@code int}, {@code float},
* {@code long}, {@code double} or {@code String}.
*/
class BasicConstant implements LoadableConstant {
int tag;
Object data;
private BasicConstant(int tag, Object data) {
this.tag = tag;
this.data = data;
}
@Override
public int poolTag() {
return tag;
}
@Override
public Object poolKey(Types types) {
return data;
}
}
}
/**
* This interface models a dynamic pool constant (either of kind {@code InvokeDynamic} or
* {@code ConstantDynamic}). In addition to the functionalities provided by the base interface,
* a dynamic pool constant must expose its dynamic type, bootstrap method and static argument list.
* Finally, a dynamic constant must have a way to compute a bootstrap method key - that is,
* a unique key for the bootstrap method entry it refers to, to avoid duplicates when writing
* the {@code BootstrapMethods} attribute.
*/
interface Dynamic extends PoolConstant {
/**
* The dynamic constant's dynamic type.
*/
PoolConstant dynamicType();
/**
* The dynamic constant's static argument list.
*/
LoadableConstant[] staticArgs();
/**
* The dynamic constant's bootstrap method.
*/
LoadableConstant bootstrapMethod();
default BsmKey bsmKey(Types types) {
return new BsmKey(types, bootstrapMethod(), staticArgs());
}
@Override
default Object poolKey(Types types) {
return new Pair<>(bsmKey(types), dynamicType().poolKey(types));
}
/**
* A class modelling a bootstrap method key.
*/
class BsmKey {
/**
* The key's bootstrap method constant.
*/
public final LoadableConstant bsm;
/**
* The key's static argument list.
*/
public final LoadableConstant[] staticArgs;
private final Object bsmKey;
private final List<?> staticArgKeys;
private BsmKey(Types types, LoadableConstant bsm, LoadableConstant[] staticArgs) {
this.bsm = bsm;
this.bsmKey = bsm.poolKey(types);
this.staticArgs = staticArgs;
this.staticArgKeys = Stream.of(staticArgs)
.map(p -> p.poolKey(types))
.collect(List.collector());
}
@Override
public int hashCode() {
return bsmKey.hashCode() +
staticArgKeys.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof BsmKey) {
BsmKey other = (BsmKey)obj;
return Objects.equals(bsmKey, other.bsmKey) &&
Objects.equals(staticArgKeys, other.staticArgKeys);
} else {
return false;
}
}
}
}
/**
* A pool constant implememntation describing a name and type pool entry.
*/
final class NameAndType implements PoolConstant {
final Name name;
final Type type;
NameAndType(Name name, Type type) {
this.name = name;
this.type = type;
}
@Override
public int poolTag() {
return ClassFile.CONSTANT_NameandType;
}
@Override
public Object poolKey(Types types) {
return new Pair<>(name, new UniqueType(type, types));
}
}
}

@ -0,0 +1,329 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.jvm;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
import com.sun.tools.javac.util.ByteBuffer;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Name.NameMapper;
import com.sun.tools.javac.util.Names;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Dynamic;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InvokeDynamic;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Module;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_NameandType;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Package;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Utf8;
import static com.sun.tools.javac.jvm.ClassFile.internalize;
/**
* Pool interface towards {@code ClassReader}. Exposes methods to decode and read javac entities
* from the constant pool.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class PoolReader {
private final ClassReader reader;
private final ByteBuffer buf;
private final Names names;
private final Symtab syms;
private ImmutablePoolHelper pool;
PoolReader(ByteBuffer buf) {
this(null, buf, null, null);
}
PoolReader(ClassReader reader, Names names, Symtab syms) {
this(reader, reader.buf, names, syms);
}
PoolReader(ClassReader reader, ByteBuffer buf, Names names, Symtab syms) {
this.reader = reader;
this.buf = buf;
this.names = names;
this.syms = syms;
}
/**
* Get a class symbol from the pool at given index.
*/
ClassSymbol getClass(int index) {
return pool.readIfNeeded(index);
}
/**
* Get class name without resolving
*/
<Z> Z peekClassName(int index, NameMapper<Z> mapper) {
return peekName(buf.getChar(pool.offset(index)), mapper);
}
/**
* Get package name without resolving
*/
<Z> Z peekPackageName(int index, NameMapper<Z> mapper) {
return peekName(buf.getChar(pool.offset(index)), mapper);
}
/**
* Get module name without resolving
*/
<Z> Z peekModuleName(int index, NameMapper<Z> mapper) {
return peekName(buf.getChar(pool.offset(index)), mapper);
}
/**
* Get a module symbol from the pool at given index.
*/
ModuleSymbol getModule(int index) {
return pool.readIfNeeded(index);
}
/**
* Get a module symbol from the pool at given index.
*/
PackageSymbol getPackage(int index) {
return pool.readIfNeeded(index);
}
/**
* Peek a name from the pool at given index without resolving.
*/
<Z> Z peekName(int index, Name.NameMapper<Z> mapper) {
return getUtf8(index, mapper);
}
/**
* Get a name from the pool at given index.
*/
Name getName(int index) {
return pool.readIfNeeded(index);
}
/**
* Get a type from the pool at given index.
*/
Type getType(int index) {
return getName(index).map(reader::sigToType);
}
/**
* Get a name and type pair from the pool at given index.
*/
NameAndType getNameAndType(int index) {
return pool.readIfNeeded(index);
}
/**
* Get a class symbol from the pool at given index.
*/
Object getConstant(int index) {
return pool.readIfNeeded(index);
}
boolean hasTag(int index, int tag) {
return pool.tag(index) == tag;
}
private <Z> Z getUtf8(int index, NameMapper<Z> mapper) {
int tag = pool.tag(index);
if (tag == CONSTANT_Utf8) {
int offset = pool.offset(index);
int len = pool.poolbuf.getChar(offset);
return mapper.map(pool.poolbuf.elems, offset + 2, len);
} else {
throw new AssertionError("Unexpected constant tag: " + tag);
}
}
private Object resolve(ByteBuffer poolbuf, int tag, int offset) {
switch (tag) {
case CONSTANT_Utf8: {
int len = poolbuf.getChar(offset);
return names.fromUtf(poolbuf.elems, offset + 2, len);
}
case CONSTANT_Class: {
int index = poolbuf.getChar(offset);
Name name = names.fromUtf(getName(index).map(ClassFile::internalize));
return syms.enterClass(reader.currentModule, name);
}
case CONSTANT_NameandType: {
Name name = getName(poolbuf.getChar(offset));
Type type = getType(poolbuf.getChar(offset + 2));
return new NameAndType(name, type);
}
case CONSTANT_Integer:
return poolbuf.getInt(offset);
case CONSTANT_Float:
return poolbuf.getFloat(offset);
case CONSTANT_Long:
return poolbuf.getLong(offset);
case CONSTANT_Double:
return poolbuf.getDouble(offset);
case CONSTANT_String:
return getName(poolbuf.getChar(offset)).toString();
case CONSTANT_Package: {
Name name = getName(poolbuf.getChar(offset));
return syms.enterPackage(reader.currentModule, names.fromUtf(internalize(name)));
}
case CONSTANT_Module: {
Name name = getName(poolbuf.getChar(offset));
return syms.enterModule(name);
}
default:
throw new AssertionError("Unexpected constant tag: " + tag);
}
}
/**
* Parse all constant pool entries, and keep track of their offsets. For performance and laziness
* reasons, it would be unwise to eagerly turn all pool entries into corresponding javac
* entities. First, not all entries are actually going to be read/used by javac; secondly,
* there are cases where creating a symbol too early might result in issues (hence methods like
* {@link PoolReader#peekClassName(int, NameMapper)}.
*/
int readPool(ByteBuffer poolbuf, int offset) {
int poolSize = poolbuf.getChar(offset);
int index = 1;
offset += 2;
int[] offsets = new int[poolSize];
while (index < poolSize) {
byte tag = poolbuf.getByte(offset++);
offsets[index] = offset;
switch (tag) {
case CONSTANT_Utf8: {
int len = poolbuf.getChar(offset);
offset += 2 + len;
break;
}
case CONSTANT_Class:
case CONSTANT_String:
case CONSTANT_Module:
case CONSTANT_Package:
case CONSTANT_MethodType:
offset += 2;
break;
case CONSTANT_MethodHandle:
offset += 3;
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_NameandType:
case CONSTANT_Integer:
case CONSTANT_Float:
case CONSTANT_Dynamic:
case CONSTANT_InvokeDynamic:
offset += 4;
break;
case CONSTANT_Long:
case CONSTANT_Double:
offset += 8;
break;
default:
throw reader.badClassFile("bad.const.pool.tag.at",
Byte.toString(tag),
Integer.toString(offset - 1));
}
index += sizeof(tag);
}
pool = new ImmutablePoolHelper(poolbuf, offsets);
return offset;
}
private int sizeof(int tag) {
switch (tag) {
case ClassFile.CONSTANT_Double: case ClassFile.CONSTANT_Long:
return 2;
default:
return 1;
}
}
class ImmutablePoolHelper {
final Object[] values;
final int[] offsets;
final ByteBuffer poolbuf;
public ImmutablePoolHelper(ByteBuffer poolbuf, int[] offsets) {
this.offsets = offsets;
this.values = new Object[offsets.length];
this.poolbuf = poolbuf;
}
private int checkIndex(int index) {
if (index <= 0 || index >= offsets.length) {
//pool index is outside valid range.
throw reader.badClassFile("bad.const.pool.index", reader.currentClassFile,
index, offsets.length);
} else {
return index;
}
}
int offset(int index) {
return offsets[checkIndex(index)];
}
@SuppressWarnings("unchecked")
<P> P readIfNeeded(int index) {
Object v = values[checkIndex(index)];
if (v != null) {
return (P)v;
} else {
P p = (P)resolve(poolbuf, tag(index), offset(index));
values[index] = p;
return p;
}
}
int tag(int index) {
return poolbuf.elems[offset(index) - 1];
}
}
}

@ -0,0 +1,506 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.jvm;
import com.sun.tools.javac.code.Kinds.Kind;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.jvm.ClassWriter.PoolOverflow;
import com.sun.tools.javac.jvm.ClassWriter.StringOverflow;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant;
import com.sun.tools.javac.jvm.PoolConstant.Dynamic;
import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
import com.sun.tools.javac.util.ByteBuffer;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import static com.sun.tools.javac.code.Kinds.Kind.TYP;
import static com.sun.tools.javac.code.TypeTag.ARRAY;
import static com.sun.tools.javac.code.TypeTag.CLASS;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
import static com.sun.tools.javac.jvm.ClassFile.externalize;
/**
* Pool interface towards {@code ClassWriter}. Exposes methods to encode and write javac entities
* into the constant pool.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class PoolWriter {
/** Max number of constant pool entries. */
public static final int MAX_ENTRIES = 0xFFFF;
/** Max number of char in a string constant. */
public static final int MAX_STRING_LENGTH = 0xFFFF;
private static final int POOL_BUF_SIZE = 0x7fff;
private final Types types;
private final Names names;
/** Pool helper **/
final WriteablePoolHelper pool;
/** Sole signature generator */
final SharedSignatureGenerator signatureGen;
/** The inner classes to be written, as an ordered set (enclosing first). */
LinkedHashSet<ClassSymbol> innerClasses = new LinkedHashSet<>();
/** The list of entries in the BootstrapMethods attribute. */
Map<BsmKey, Integer> bootstrapMethods = new LinkedHashMap<>();
public PoolWriter(Types types, Names names) {
this.types = types;
this.names = names;
this.signatureGen = new SharedSignatureGenerator(types);
this.pool = new WriteablePoolHelper();
}
/**
* Puts a class symbol into the pool and return its index.
*/
int putClass(ClassSymbol csym) {
return putClass(csym.type);
}
/**
* Puts a type into the pool and return its index. The type could be either a class, a type variable
* or an array type.
*/
int putClass(Type t) {
return pool.writeIfNeeded(types.erasure(t));
}
/**
* Puts a member reference into the constant pool. Valid members are either field or method symbols.
*/
int putMember(Symbol s) {
return pool.writeIfNeeded(s);
}
/**
* Puts a dynamic reference into the constant pool and return its index.
*/
int putDynamic(DynamicMethodSymbol d) {
return pool.writeIfNeeded(d);
}
/**
* Puts a field or method descriptor into the constant pool and return its index.
*/
int putDescriptor(Type t) {
return putName(typeSig(types.erasure(t)));
}
/**
* Puts a field or method descriptor into the constant pool and return its index.
*/
int putDescriptor(Symbol s) {
return putDescriptor(descriptorType(s));
}
/**
* Puts a signature (see {@code Signature} attribute in JVMS 4.4) into the constant pool and
* return its index.
*/
int putSignature(Symbol s) {
if (s.kind == TYP) {
return putName(classSig(s.type));
} else {
return putName(typeSig(s.type));
}
}
/**
* Puts a constant value into the pool and return its index. Supported values are int, float, long,
* double and String.
*/
int putConstant(Object o) {
if (o instanceof Integer) {
return putConstant(LoadableConstant.Int((int)o));
} else if (o instanceof Float) {
return putConstant(LoadableConstant.Float((float)o));
} else if (o instanceof Long) {
return putConstant(LoadableConstant.Long((long)o));
} else if (o instanceof Double) {
return putConstant(LoadableConstant.Double((double)o));
} else if (o instanceof String) {
return putConstant(LoadableConstant.String((String)o));
} else {
throw new AssertionError("unexpected constant: " + o);
}
}
/**
* Puts a constant into the pool and return its index.
*/
int putConstant(LoadableConstant c) {
switch (c.poolTag()) {
case CONSTANT_Class:
return putClass((Type)c);
case CONSTANT_MethodType:
return pool.writeIfNeeded(types.erasure((Type)c));
default:
return pool.writeIfNeeded(c);
}
}
int putName(Name name) {
return pool.writeIfNeeded(name);
}
/**
* Puts a name and type pair into the pool and returns its index.
*/
int putNameAndType(Symbol s) {
return pool.writeIfNeeded(new NameAndType(s.name, descriptorType(s)));
}
/**
* Puts a package entry into the pool and returns its index.
*/
int putPackage(PackageSymbol pkg) {
return pool.writeIfNeeded(pkg);
}
/**
* Puts a module entry into the pool and returns its index.
*/
int putModule(ModuleSymbol mod) {
return pool.writeIfNeeded(mod);
}
/**
* Enter an inner class into the `innerClasses' set.
*/
void enterInner(ClassSymbol c) {
if (c.type.isCompound()) {
throw new AssertionError("Unexpected intersection type: " + c.type);
}
c.complete();
if (c.owner.enclClass() != null && !innerClasses.contains(c)) {
enterInner(c.owner.enclClass());
innerClasses.add(c);
}
}
/**
* Create a new Utf8 entry representing a descriptor for given (member) symbol.
*/
private Type descriptorType(Symbol s) {
return s.kind == Kind.MTH ? s.externalType(types) : s.erasure(types);
}
private int makeBoostrapEntry(Dynamic dynamic) {
BsmKey bsmKey = dynamic.bsmKey(types);
// Figure out the index for existing BSM; create a new BSM if no key
Integer index = bootstrapMethods.get(bsmKey);
if (index == null) {
index = bootstrapMethods.size();
bootstrapMethods.put(bsmKey, index);
}
return index;
}
/**
* Write pool contents into given byte buffer.
*/
void writePool(OutputStream out) throws IOException, PoolOverflow {
if (pool.overflowString != null) {
throw new StringOverflow(pool.overflowString);
}
int size = size();
if (size > MAX_ENTRIES) {
throw new PoolOverflow();
}
out.write(size >> 8);
out.write(size);
out.write(pool.poolbuf.elems, 0, pool.poolbuf.length);
}
/**
* Signature Generation
*/
class SharedSignatureGenerator extends Types.SignatureGenerator {
/**
* An output buffer for type signatures.
*/
ByteBuffer sigbuf = new ByteBuffer();
SharedSignatureGenerator(Types types) {
super(types);
}
/**
* Assemble signature of given type in string buffer.
* Check for uninitialized types before calling the general case.
*/
@Override
public void assembleSig(Type type) {
switch (type.getTag()) {
case UNINITIALIZED_THIS:
case UNINITIALIZED_OBJECT:
// we don't yet have a spec for uninitialized types in the
// local variable table
assembleSig(types.erasure(((UninitializedType)type).qtype));
break;
default:
super.assembleSig(type);
}
}
@Override
protected void append(char ch) {
sigbuf.appendByte(ch);
}
@Override
protected void append(byte[] ba) {
sigbuf.appendBytes(ba);
}
@Override
protected void append(Name name) {
sigbuf.appendName(name);
}
@Override
protected void classReference(ClassSymbol c) {
enterInner(c);
}
protected void reset() {
sigbuf.reset();
}
protected Name toName() {
return sigbuf.toName(names);
}
}
class WriteablePoolHelper {
/** Pool entries. */
private final Map<Object, Integer> keysToPos = new HashMap<>(64);
final ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
int currentIndex = 1;
ArrayDeque<PoolConstant> todo = new ArrayDeque<>();
String overflowString = null;
private <P extends PoolConstant> int writeIfNeeded(P p) {
Object key = p.poolKey(types);
Integer index = keysToPos.get(key);
if (index == null) {
keysToPos.put(key, index = currentIndex++);
boolean first = todo.isEmpty();
todo.addLast(p);
if (first) {
while (!todo.isEmpty()) {
writeConstant(todo.peekFirst());
todo.removeFirst();
}
}
}
return index;
}
void writeConstant(PoolConstant c) {
int tag = c.poolTag();
switch (tag) {
case ClassFile.CONSTANT_Class: {
Type ct = (Type)c;
Name name = ct.hasTag(ARRAY) ?
typeSig(ct) :
names.fromUtf(externalize(ct.tsym.flatName()));
poolbuf.appendByte(tag);
poolbuf.appendChar(putName(name));
if (ct.hasTag(CLASS)) {
enterInner((ClassSymbol)ct.tsym);
}
break;
}
case ClassFile.CONSTANT_Utf8: {
Name name = (Name)c;
poolbuf.appendByte(tag);
byte[] bs = name.toUtf();
poolbuf.appendChar(bs.length);
poolbuf.appendBytes(bs, 0, bs.length);
if (overflowString == null && bs.length > MAX_STRING_LENGTH) {
//report error only once
overflowString = new String(bs);
}
break;
}
case ClassFile.CONSTANT_InterfaceMethodref:
case ClassFile.CONSTANT_Methodref:
case ClassFile.CONSTANT_Fieldref: {
Symbol sym = (Symbol)c;
poolbuf.appendByte(tag);
poolbuf.appendChar(putClass((ClassSymbol)sym.owner));
poolbuf.appendChar(putNameAndType(sym));
break;
}
case ClassFile.CONSTANT_Package: {
PackageSymbol pkg = (PackageSymbol)c;
Name pkgName = names.fromUtf(externalize(pkg.flatName()));
poolbuf.appendByte(tag);
poolbuf.appendChar(putName(pkgName));
break;
}
case ClassFile.CONSTANT_Module: {
ModuleSymbol mod = (ModuleSymbol)c;
int modName = putName(mod.name);
poolbuf.appendByte(mod.poolTag());
poolbuf.appendChar(modName);
break;
}
case ClassFile.CONSTANT_Integer:
poolbuf.appendByte(tag);
poolbuf.appendInt((int)((BasicConstant)c).data);
break;
case ClassFile.CONSTANT_Float:
poolbuf.appendByte(tag);
poolbuf.appendFloat((float)((BasicConstant)c).data);
break;
case ClassFile.CONSTANT_Long:
currentIndex++;
poolbuf.appendByte(tag);
poolbuf.appendLong((long)((BasicConstant)c).data);
break;
case ClassFile.CONSTANT_Double:
currentIndex++;
poolbuf.appendByte(tag);
poolbuf.appendDouble((double)((BasicConstant)c).data);
break;
case ClassFile.CONSTANT_MethodHandle: {
MethodHandleSymbol h = (MethodHandleSymbol)c;
poolbuf.appendByte(tag);
poolbuf.appendByte(h.referenceKind());
poolbuf.appendChar(putMember(h.baseSymbol()));
break;
}
case ClassFile.CONSTANT_MethodType: {
Type.MethodType mt = (Type.MethodType)c;
poolbuf.appendByte(tag);
poolbuf.appendChar(putDescriptor(mt.baseType()));
break;
}
case ClassFile.CONSTANT_String: {
Name utf = names.fromString((String)((BasicConstant)c).data);
poolbuf.appendByte(tag);
poolbuf.appendChar(putName(utf));
break;
}
case ClassFile.CONSTANT_NameandType: {
NameAndType nt = (NameAndType)c;
poolbuf.appendByte(tag);
poolbuf.appendChar(putName(nt.name));
poolbuf.appendChar(putDescriptor(nt.type));
break;
}
case ClassFile.CONSTANT_InvokeDynamic: {
DynamicMethodSymbol d = (DynamicMethodSymbol)c;
poolbuf.appendByte(tag);
poolbuf.appendChar(makeBoostrapEntry(d));
poolbuf.appendChar(putNameAndType(d));
break;
}
default:
throw new AssertionError("Unexpected constant tag: " + tag);
}
}
void reset() {
keysToPos.clear();
currentIndex = 1;
todo.clear();
overflowString = null;
poolbuf.reset();
}
}
int size() {
return pool.currentIndex;
}
/**
* Return signature of given type
*/
private Name typeSig(Type type) {
signatureGen.reset();
signatureGen.assembleSig(type);
return signatureGen.toName();
}
private Name classSig(Type t) {
signatureGen.reset();
List<Type> typarams = t.getTypeArguments();
if (typarams.nonEmpty()) {
signatureGen.assembleParamsSig(typarams);
}
signatureGen.assembleSig(types.supertype(t));
for (Type i : types.interfaces(t))
signatureGen.assembleSig(i);
return signatureGen.toName();
}
void reset() {
innerClasses.clear();
bootstrapMethods.clear();
pool.reset();
}
}

@ -26,7 +26,9 @@
package com.sun.tools.javac.jvm;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.comp.Resolve;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.tree.TreeMaker;
@ -222,7 +224,7 @@ public abstract class StringConcat {
private JCDiagnostic.DiagnosticPosition newStringBuilder(JCTree tree) {
JCDiagnostic.DiagnosticPosition pos = tree.pos();
gen.getCode().emitop2(new_, gen.makeRef(pos, syms.stringBuilderType));
gen.getCode().emitop2(new_, gen.makeRef(pos, syms.stringBuilderType), syms.stringBuilderType);
gen.getCode().emitop0(dup);
gen.callMethod(pos, syms.stringBuilderType, names.init, List.nil(), false);
return pos;
@ -378,10 +380,9 @@ public abstract class StringConcat {
Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcat,
syms.noSymbol,
ClassFile.REF_invokeStatic,
(Symbol.MethodSymbol)bsm,
((MethodSymbol)bsm).asHandle(),
indyType,
List.nil().toArray());
List.nil().toArray(new LoadableConstant[0]));
Items.Item item = gen.getItems().makeDynamicItem(dynSym);
item.invoke();
@ -416,7 +417,7 @@ public abstract class StringConcat {
StringBuilder recipe = new StringBuilder(t.size());
ListBuffer<Type> dynamicArgs = new ListBuffer<>();
ListBuffer<Object> staticArgs = new ListBuffer<>();
ListBuffer<LoadableConstant> staticArgs = new ListBuffer<>();
for (JCTree arg : t) {
Object constVal = arg.type.constValue();
@ -431,7 +432,7 @@ public abstract class StringConcat {
String a = arg.type.stringValue();
if (a.indexOf(TAG_CONST) != -1 || a.indexOf(TAG_ARG) != -1) {
recipe.append(TAG_CONST);
staticArgs.add(a);
staticArgs.add(LoadableConstant.String(a));
} else {
recipe.append(a);
}
@ -463,7 +464,7 @@ public abstract class StringConcat {
}
/** Produce the actual invokedynamic call to StringConcatFactory */
private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, String recipe, List<Object> staticArgs, List<Type> dynamicArgTypes) {
private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, String recipe, List<LoadableConstant> staticArgs, List<Type> dynamicArgTypes) {
Type.MethodType indyType = new Type.MethodType(dynamicArgTypes,
type,
List.nil(),
@ -474,8 +475,8 @@ public abstract class StringConcat {
make.at(pos);
ListBuffer<Type> constTypes = new ListBuffer<>();
ListBuffer<Object> constants = new ListBuffer<>();
for (Object t : staticArgs) {
ListBuffer<LoadableConstant> constants = new ListBuffer<>();
for (LoadableConstant t : staticArgs) {
constants.add(t);
constTypes.add(syms.stringType);
}
@ -495,10 +496,10 @@ public abstract class StringConcat {
Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcatWithConstants,
syms.noSymbol,
ClassFile.REF_invokeStatic,
(Symbol.MethodSymbol)bsm,
((MethodSymbol)bsm).asHandle(),
indyType,
List.<Object>of(recipe).appendList(constants).toArray());
List.of(LoadableConstant.String(recipe))
.appendList(constants).toArray(new LoadableConstant[constants.size()]));
Items.Item item = gen.getItems().makeDynamicItem(dynSym);
item.invoke();

@ -2164,6 +2164,11 @@ compiler.misc.bad.const.pool.entry=\
bad constant pool entry in {0}\n\
expected {1} at index {2}
# 0: file name, 1: number (constant pool index), 2: number (constant pool size)
compiler.misc.bad.const.pool.index=\
bad constant pool index in {0}\n\
index {1} is not within pool size {2}.
# 0: file name, 1: message segment
compiler.misc.bad.class.file.header=\
bad class file: {0}\n\

@ -147,6 +147,90 @@ public class ByteBuffer {
appendBytes(name.getByteArray(), name.getByteOffset(), name.getByteLength());
}
/** Append the content of a given input stream.
*/
public void appendStream(InputStream is) throws IOException {
try {
int start = length;
int initialSize = is.available();
elems = ArrayUtils.ensureCapacity(elems, length + initialSize);
int r = is.read(elems, start, initialSize);
int bp = start;
while (r != -1) {
bp += r;
elems = ArrayUtils.ensureCapacity(elems, bp);
r = is.read(elems, bp, elems.length - bp);
}
} finally {
try {
is.close();
} catch (IOException e) {
/* Ignore any errors, as this stream may have already
* thrown a related exception which is the one that
* should be reported.
*/
}
}
}
/** Extract an integer at position bp from elems.
*/
public int getInt(int bp) {
return
((elems[bp] & 0xFF) << 24) +
((elems[bp+1] & 0xFF) << 16) +
((elems[bp+2] & 0xFF) << 8) +
(elems[bp+3] & 0xFF);
}
/** Extract a long integer at position bp from elems.
*/
public long getLong(int bp) {
DataInputStream elemsin =
new DataInputStream(new ByteArrayInputStream(elems, bp, 8));
try {
return elemsin.readLong();
} catch (IOException e) {
throw new AssertionError(e);
}
}
/** Extract a float at position bp from elems.
*/
public float getFloat(int bp) {
DataInputStream elemsin =
new DataInputStream(new ByteArrayInputStream(elems, bp, 4));
try {
return elemsin.readFloat();
} catch (IOException e) {
throw new AssertionError(e);
}
}
/** Extract a double at position bp from elems.
*/
public double getDouble(int bp) {
DataInputStream elemsin =
new DataInputStream(new ByteArrayInputStream(elems, bp, 8));
try {
return elemsin.readDouble();
} catch (IOException e) {
throw new AssertionError(e);
}
}
/** Extract a character at position bp from elems.
*/
public char getChar(int bp) {
return
(char)(((elems[bp] & 0xFF) << 8) + (elems[bp+1] & 0xFF));
}
public byte getByte(int bp) {
return elems[bp];
}
/** Reset to zero length.
*/
public void reset() {

@ -25,6 +25,8 @@
package com.sun.tools.javac.util;
import com.sun.tools.javac.jvm.ClassFile;
import com.sun.tools.javac.jvm.PoolConstant;
import com.sun.tools.javac.util.DefinedBy.Api;
/** An abstraction for internal compiler strings. They are stored in
@ -36,7 +38,7 @@ import com.sun.tools.javac.util.DefinedBy.Api;
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public abstract class Name implements javax.lang.model.element.Name {
public abstract class Name implements javax.lang.model.element.Name, PoolConstant {
public final Table table;
@ -52,6 +54,11 @@ public abstract class Name implements javax.lang.model.element.Name {
return toString().equals(cs.toString());
}
@Override
public int poolTag() {
return ClassFile.CONSTANT_Utf8;
}
/**
* {@inheritDoc}
*/
@ -188,6 +195,14 @@ public abstract class Name implements javax.lang.model.element.Name {
*/
public abstract int getByteOffset();
public interface NameMapper<X> {
X map(byte[] bytes, int offset, int len);
}
public <X> X map(NameMapper<X> mapper) {
return mapper.map(getByteArray(), getByteOffset(), getByteLength());
}
/** An abstraction for the hash table used to create unique Name instances.
*/
public static abstract class Table {

@ -59,7 +59,7 @@ public class AnnotatedExtendsTest {
.classes(classPath.toString())
.run()
.getOutput(Task.OutputKind.DIRECT);
if (!javapOut.contains("0: #21(): CLASS_EXTENDS, type_index=65535"))
if (!javapOut.contains("0: #22(): CLASS_EXTENDS, type_index=65535"))
throw new AssertionError("Expected output missing: " + javapOut);
}
}

@ -74,14 +74,14 @@ public class BridgeShouldHaveNoInteriorAnnotationsTest
// Expected output can't be directly encoded into NestedLambdasCastedTest !!!
static class OutputExpectedOnceHolder {
public String[] outputs = {
"0: #61(): CAST, offset=1, type_index=0, location=[TYPE_ARGUMENT(0)]",
"1: #61(): LOCAL_VARIABLE, {start_pc=5, length=2, index=1}, location=[TYPE_ARGUMENT(0)]",
"0: #120(): CAST, offset=1, type_index=0, location=[TYPE_ARGUMENT(0)]",
"1: #120(): LOCAL_VARIABLE, {start_pc=5, length=2, index=1}, location=[TYPE_ARGUMENT(0)]",
};
}
static class OutputExpectedTwiceHolder {
public String[] outputs = {
"0: #61(): METHOD_RETURN, location=[TYPE_ARGUMENT(0)]",
"0: #120(): METHOD_RETURN, location=[TYPE_ARGUMENT(0)]",
};
}

@ -53,10 +53,10 @@ public class NestedLambdasCastedTest {
"private static strictfp void lambda$main$2();",
"private static strictfp void lambda$main$1();",
"private static strictfp void lambda$main$0();",
"0: #62(#63=s#64): CAST, offset=5, type_index=0",
"0: #62(#63=s#69): CAST, offset=5, type_index=0",
"0: #62(#63=s#72): CAST, offset=5, type_index=0",
"0: #62(#63=s#75): CAST, offset=5, type_index=0"
"0: #111(#112=s#113): CAST, offset=5, type_index=0",
"0: #111(#112=s#119): CAST, offset=5, type_index=0",
"0: #111(#112=s#122): CAST, offset=5, type_index=0",
"0: #111(#112=s#125): CAST, offset=5, type_index=0"
};
}

@ -46,6 +46,7 @@ compiler.err.unsupported.cross.fp.lit # Scanner: host system d
compiler.misc.bad.class.signature # bad class file
compiler.misc.bad.const.pool.tag # bad class file
compiler.misc.bad.const.pool.tag.at # bad class file
compiler.misc.bad.const.pool.index # bad class file
compiler.misc.bad.constant.range # bad class file
compiler.misc.bad.constant.value # bad class file
compiler.misc.bad.enclosing.class # bad class file

@ -61,6 +61,7 @@ import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCIdent;
@ -190,7 +191,7 @@ public class TestBootstrapMethodsCount {
Symbol oldSym = ident.sym;
if (!oldSym.isConstructor()) {
ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name,
oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]);
oldSym.owner, bsm.asHandle(), oldSym.type, new LoadableConstant[0]);
}
return null;
}

@ -60,26 +60,23 @@ import com.sun.tools.classfile.Instruction;
import com.sun.tools.classfile.LineNumberTable_attribute;
import com.sun.tools.classfile.Method;
import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.code.Type.MethodType;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.jvm.Pool;
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Names;
import combo.ComboParameter;
import combo.ComboTask;
import combo.ComboTestHelper;
import combo.ComboInstance;
import combo.ComboTask.Result;
import static com.sun.tools.javac.jvm.ClassFile.*;
public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
enum StaticArgumentKind implements ComboParameter {
@ -168,21 +165,24 @@ public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
abstract boolean check(CPInfo cpInfo) throws Exception;
Object getValue(Symtab syms, Names names, Types types) {
LoadableConstant getValue(Symtab syms) {
switch (this) {
case STRING:
return LoadableConstant.String((String)value);
case INTEGER:
return LoadableConstant.Int((Integer)value);
case LONG:
return LoadableConstant.Long((Long)value);
case FLOAT:
return LoadableConstant.Float((Float)value);
case DOUBLE:
return value;
return LoadableConstant.Double((Double)value);
case CLASS:
return syms.stringType.tsym;
return (ClassType)syms.stringType;
case METHOD_HANDLE:
return new Pool.MethodHandle(REF_invokeVirtual,
syms.arrayCloneMethod, types);
return syms.arrayCloneMethod.asHandle();
case METHOD_TYPE:
return syms.arrayCloneMethod.type;
return ((MethodType)syms.arrayCloneMethod.type);
default:
throw new AssertionError();
}
@ -394,7 +394,7 @@ public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
class Indifier extends TreeScanner<Void, Void> implements TaskListener {
MethodSymbol bsm;
MethodHandleSymbol bsm;
Symtab syms;
Names names;
Types types;
@ -424,12 +424,12 @@ public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
JCIdent ident = (JCIdent)apply.meth;
Symbol oldSym = ident.sym;
if (!oldSym.isConstructor()) {
Object[] staticArgs = new Object[arity.arity];
LoadableConstant[] staticArgs = new LoadableConstant[arity.arity];
for (int i = 0; i < arity.arity ; i++) {
staticArgs[i] = saks[i].getValue(syms, names, types);
staticArgs[i] = saks[i].getValue(syms);
}
ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name,
oldSym.owner, REF_invokeStatic, bsm, oldSym.type, staticArgs);
oldSym.owner, bsm, oldSym.type, staticArgs);
}
return null;
}
@ -438,7 +438,7 @@ public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
public Void visitMethod(MethodTree node, Void p) {
super.visitMethod(node, p);
if (node.getName().toString().equals("bsm")) {
bsm = ((JCMethodDecl)node).sym;
bsm = ((JCMethodDecl)node).sym.asHandle();
}
return null;
}

@ -1,2 +1,2 @@
- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.name.mismatch: mod/module-info, <error>))
- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.bad.const.pool.index: module-info.class, 15, 10))
1 error

@ -90,8 +90,8 @@ public class CheckNestmateAttrs {
"NestHost: class CheckNestmateAttrs",
"0: aload_0",
"1: getfield #1 // Field this$1:LCheckNestmateAttrs$Inner;",
"4: getfield #3 // Field CheckNestmateAttrs$Inner.this$0:LCheckNestmateAttrs;",
"7: invokevirtual #4 // Method CheckNestmateAttrs.test:()V",
"4: getfield #13 // Field CheckNestmateAttrs$Inner.this$0:LCheckNestmateAttrs;",
"7: invokevirtual #19 // Method CheckNestmateAttrs.test:()V",
"10: return"
});

@ -49,50 +49,50 @@ public class AnnoTest {
expect(out,
"RuntimeVisibleAnnotations:\n" +
" 0: #18(#19=B#20)\n" +
" 0: #21(#22=B#23)\n" +
" AnnoTest$ByteAnno(\n" +
" value=(byte) 42\n" +
" )\n" +
" 1: #23(#19=S#24)\n" +
" 1: #24(#22=S#25)\n" +
" AnnoTest$ShortAnno(\n" +
" value=(short) 3\n" +
" )");
expect(out,
"RuntimeInvisibleAnnotations:\n" +
" 0: #28(#19=[J#29,J#31,J#33,J#35,J#37])\n" +
" 0: #27(#22=[J#28,J#30,J#32,J#34,J#36])\n" +
" AnnoTest$ArrayAnno(\n" +
" value=[1l,2l,3l,4l,5l]\n" +
" )\n" +
" 1: #41(#19=Z#42)\n" +
" 1: #38(#22=Z#39)\n" +
" AnnoTest$BooleanAnno(\n" +
" value=false\n" +
" )\n" +
" 2: #45(#46=c#47)\n" +
" 2: #40(#41=c#42)\n" +
" AnnoTest$ClassAnno(\n" +
" type=class Ljava/lang/Object;\n" +
" )\n" +
" 3: #50(#51=e#52.#53)\n" +
" 3: #43(#44=e#45.#46)\n" +
" AnnoTest$EnumAnno(\n" +
" kind=Ljavax/lang/model/element/ElementKind;.PACKAGE\n" +
" )\n" +
" 4: #56(#19=I#57)\n" +
" 4: #47(#22=I#48)\n" +
" AnnoTest$IntAnno(\n" +
" value=2\n" +
" )\n" +
" 5: #60()\n" +
" 5: #49()\n" +
" AnnoTest$IntDefaultAnno\n" +
" 6: #63(#64=s#65)\n" +
" 6: #50(#51=s#52)\n" +
" AnnoTest$NameAnno(\n" +
" name=\"NAME\"\n" +
" )\n" +
" 7: #68(#69=D#70,#72=F#73)\n" +
" 7: #53(#54=D#55,#57=F#58)\n" +
" AnnoTest$MultiAnno(\n" +
" d=3.14159d\n" +
" f=2.71828f\n" +
" )\n" +
" 8: #76()\n" +
" 8: #59()\n" +
" AnnoTest$SimpleAnno\n" +
" 9: #79(#19=@#56(#19=I#80))\n" +
" 9: #60(#22=@#47(#22=I#61))\n" +
" AnnoTest$AnnoAnno(\n" +
" value=@AnnoTest$IntAnno(\n" +
" value=5\n" +
@ -100,7 +100,7 @@ public class AnnoTest {
" )");
expect(out,
"RuntimeInvisibleTypeAnnotations:\n" +
" 0: #84(): CLASS_EXTENDS, type_index=0\n" +
" 0: #63(): CLASS_EXTENDS, type_index=0\n" +
" AnnoTest$TypeAnno");
if (errors > 0)

@ -51,7 +51,7 @@ public class AnnotationDefaultNewlineTest {
private static final String ExpectedSubstring =
" AnnotationDefault:\n" +
" default_value: I#7\n";
" default_value: I#9\n";
public static void main(String[] args) throws Exception {
ToolBox tb = new ToolBox();

@ -62,11 +62,11 @@ public class InvisibleParameterAnnotationsTest {
" RuntimeVisibleParameterAnnotations:\n" +
" parameter 0:\n" +
" parameter 1:\n" +
" 0: #16()\n" +
" 0: #14()\n" +
" Sample$VisAnno\n" +
" RuntimeInvisibleParameterAnnotations:\n" +
" parameter 0:\n" +
" 0: #18()\n" +
" 0: #16()\n" +
" Sample$InvisAnno\n" +
" parameter 1:";