8222289: Overhaul logic for reading/writing constant pool entries
Summary: Rewrite of Pool,ClassReader,ClassWriter to use shared pool helper components
Reviewed-by: vromero
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Wed Apr 17 15:37:20 2019 +0100
@@ -55,6 +55,7 @@
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 @@
* 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 @@
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 @@
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 @@
return members_field;
}
+ @Override
+ public int poolTag() {
+ return ClassFile.CONSTANT_Package;
+ }
+
public long flags() {
complete();
return flags_field;
@@ -1237,10 +1253,6 @@
*/
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 @@
this.flatname = formFlatName(name, owner);
this.sourcefile = null;
this.classfile = null;
- this.pool = null;
this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
}
@@ -1543,6 +1554,11 @@
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 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 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 @@
}
}
+ @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 @@
/** 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 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.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java Wed Apr 17 15:37:20 2019 +0100
@@ -36,7 +36,10 @@
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 @@
*
* @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 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 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 @@
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 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 @@
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 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 @@
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);
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Wed Apr 17 15:37:20 2019 +0100
@@ -48,6 +48,8 @@
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 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() {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Wed Apr 17 15:37:20 2019 +0100
@@ -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.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.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 @@
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 @@
//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 @@
//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 @@
//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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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;
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Wed Apr 17 15:37:20 2019 +0100
@@ -93,7 +93,6 @@
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 @@
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 @@
.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();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java Wed Apr 17 15:37:20 2019 +0100
@@ -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 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();
- }
- }
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Apr 17 15:37:20 2019 +0100
@@ -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.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.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 @@
*/
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 @@
/** 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 @@
/** 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 @@
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 @@
};
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
} 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 @@
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 @@
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 @@
} 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 @@
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 @@
} 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
/** 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 @@
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 @@
}
+ /**
+ * 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 @@
*/
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 @@
*/
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
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 @@
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 @@
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 Type resolve() {
- return sigToType(content, 0, content.length);
+ return name.map(ClassReader.this::sigToType);
}
@Override @DefinedBy(Api.LANGUAGE_MODEL)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Wed Apr 17 15:37:20 2019 +0100
@@ -29,9 +29,7 @@
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.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 @@
* 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 @@
/** An output buffer for the constant pool.
*/
- ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
-
- /** The constant pool.
- */
- Pool pool;
-
- /** The inner classes to be written, as a set.
- */
- Set<ClassSymbol> innerClasses;
+ ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE);
- /** The inner classes to be written, as a queue where
- * enclosing classes come first.
+ /** The constant pool writer.
*/
- 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 @@
/** 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 @@
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 @@
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 @@
}
}
- /** 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 @@
* 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 @@
|| 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 @@
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 @@
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 @@
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 @@
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 @@
*/
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 @@
/** 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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
* 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 @@
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 @@
* 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 @@
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 @@
*/
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 @@
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 @@
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 @@
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 @@
&& (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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
}
}
- 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
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Wed Apr 17 15:37:20 2019 +0100
@@ -27,15 +27,27 @@
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 @@
final Types types;
final Symtab syms;
+ final PoolWriter poolWriter;
/*---------- classfile fields: --------------- */
@@ -177,10 +190,6 @@
*/
Position.LineMap lineMap;
- /** The constant pool of the current class.
- */
- final Pool pool;
-
final MethodSymbol meth;
private int letExprStackPos = 0;
@@ -197,7 +206,7 @@
CRTable crt,
Symtab syms,
Types types,
- Pool pool) {
+ PoolWriter poolWriter) {
this.meth = meth;
this.fatcode = fatcode;
this.lineMap = lineMap;
@@ -206,6 +215,7 @@
this.crt = crt;
this.syms = syms;
this.types = types;
+ this.poolWriter = poolWriter;
this.debugCode = debugCode;
this.stackMap = stackMap;
switch (stackMap) {
@@ -218,7 +228,6 @@
}
state = new State();
lvar = new LocalVar[20];
- this.pool = pool;
}
@@ -389,12 +398,13 @@
/** 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 @@
/** 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 @@
/** 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 @@
/** 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 @@
/** 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 @@
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 @@
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 @@
/** 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 @@
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;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Wed Apr 17 15:37:20 2019 +0100
@@ -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 @@
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 @@
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 @@
* @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 @@
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 @@
@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 @@
: 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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++;
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java Wed Apr 17 15:37:20 2019 +0100
@@ -29,6 +29,8 @@
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 @@
*/
public class Items {
- /** The current constant pool.
+ /** The current constant pool writer.
*/
- Pool pool;
+ PoolWriter poolWriter;
/** The current code buffer.
*/
@@ -72,9 +74,9 @@
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 @@
}
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 @@
// 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 @@
}
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 @@
/** 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 @@
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 @@
}
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 @@
}
CondItem mkCond() {
- int ival = ((Number)value).intValue();
+ int ival = numericValue().intValue();
return makeCondItem(ival != 0 ? goto_ : dontgoto);
}
@@ -647,31 +673,31 @@
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);
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ModuleNameReader.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ModuleNameReader.java Wed Apr 17 15:37:20 2019 +0100
@@ -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 @@
/** 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 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 @@
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 @@
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 @@
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);
- }
-
- /** 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");
- }
- }
+ int res = buf.getInt(bp);
+ bp += 4;
+ return res;
}
- 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);
- }
+ NameMapper<String> utf8Mapper(boolean internalize) {
+ return internalize ?
+ (buf, offset, len) -> new String(ClassFile.internalize(buf, offset, len)) :
+ String::new;
}
- 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;
- }
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java Wed Apr 17 12:41:33 2019 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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;
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolConstant.java Wed Apr 17 15:37:20 2019 +0100
@@ -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));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolReader.java Wed Apr 17 15:37:20 2019 +0100
@@ -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];
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java Wed Apr 17 15:37:20 2019 +0100
@@ -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();
+ }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java Wed Apr 17 15:37:20 2019 +0100
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
}
/** 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 @@
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 @@
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();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Apr 17 15:37:20 2019 +0100
@@ -2164,6 +2164,11 @@
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\
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ByteBuffer.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ByteBuffer.java Wed Apr 17 15:37:20 2019 +0100
@@ -147,6 +147,90 @@
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() {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java Wed Apr 17 12:41:33 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Name.java Wed Apr 17 15:37:20 2019 +0100
@@ -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 @@
* 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 @@
return toString().equals(cs.toString());
}
+ @Override
+ public int poolTag() {
+ return ClassFile.CONSTANT_Utf8;
+ }
+
/**
* {@inheritDoc}
*/
@@ -188,6 +195,14 @@
*/
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 {
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnnotatedExtendsTest.java Wed Apr 17 15:37:20 2019 +0100
@@ -59,7 +59,7 @@
.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);
}
}
\ No newline at end of file
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/BridgeShouldHaveNoInteriorAnnotationsTest.java Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/BridgeShouldHaveNoInteriorAnnotationsTest.java Wed Apr 17 15:37:20 2019 +0100
@@ -74,14 +74,14 @@
// 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)]",
};
}
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NestedLambdasCastedTest.java Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NestedLambdasCastedTest.java Wed Apr 17 15:37:20 2019 +0100
@@ -53,10 +53,10 @@
"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"
};
}
--- a/test/langtools/tools/javac/diags/examples.not-yet.txt Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/diags/examples.not-yet.txt Wed Apr 17 15:37:20 2019 +0100
@@ -46,6 +46,7 @@
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
--- a/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java Wed Apr 17 15:37:20 2019 +0100
@@ -61,6 +61,7 @@
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 @@
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;
}
--- a/test/langtools/tools/javac/lambda/TestInvokeDynamic.java Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/lambda/TestInvokeDynamic.java Wed Apr 17 15:37:20 2019 +0100
@@ -60,26 +60,23 @@
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 @@
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 @@
class Indifier extends TreeScanner<Void, Void> implements TaskListener {
- MethodSymbol bsm;
+ MethodHandleSymbol bsm;
Symtab syms;
Names names;
Types types;
@@ -424,12 +424,12 @@
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 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;
}
--- a/test/langtools/tools/javac/modules/T8159439/NPEForModuleInfoWithNonZeroSuperClassTest.out Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/modules/T8159439/NPEForModuleInfoWithNonZeroSuperClassTest.out Wed Apr 17 15:37:20 2019 +0100
@@ -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
--- a/test/langtools/tools/javac/nestmates/CheckNestmateAttrs.java Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javac/nestmates/CheckNestmateAttrs.java Wed Apr 17 15:37:20 2019 +0100
@@ -90,8 +90,8 @@
"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"
});
--- a/test/langtools/tools/javap/AnnoTest.java Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javap/AnnoTest.java Wed Apr 17 15:37:20 2019 +0100
@@ -49,50 +49,50 @@
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 @@
" )");
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)
--- a/test/langtools/tools/javap/typeAnnotations/AnnotationDefaultNewlineTest.java Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javap/typeAnnotations/AnnotationDefaultNewlineTest.java Wed Apr 17 15:37:20 2019 +0100
@@ -51,7 +51,7 @@
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();
--- a/test/langtools/tools/javap/typeAnnotations/InvisibleParameterAnnotationsTest.java Wed Apr 17 12:41:33 2019 +0200
+++ b/test/langtools/tools/javap/typeAnnotations/InvisibleParameterAnnotationsTest.java Wed Apr 17 15:37:20 2019 +0100
@@ -62,11 +62,11 @@
" 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:";