8222289: Overhaul logic for reading/writing constant pool entries
Rewrite of Pool,ClassReader,ClassWriter to use shared pool helper components Reviewed-by: vromero
This commit is contained in:
parent
dce0c5c4ae
commit
7b7f9a6fd3
src/jdk.compiler/share/classes/com/sun/tools/javac
code
comp
jvm
ClassFile.javaClassReader.javaClassWriter.javaCode.javaGen.javaItems.javaModuleNameReader.javaPool.javaPoolConstant.javaPoolReader.javaPoolWriter.javaStringConcat.java
resources
util
test/langtools/tools
javac
annotations/typeAnnotations/classfile
diags
lambda
modules/T8159439
nestmates
javap
@ -55,6 +55,7 @@ import com.sun.tools.javac.comp.Attr;
|
||||
import com.sun.tools.javac.comp.AttrContext;
|
||||
import com.sun.tools.javac.comp.Env;
|
||||
import com.sun.tools.javac.jvm.*;
|
||||
import com.sun.tools.javac.jvm.PoolConstant;
|
||||
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.Tag;
|
||||
@ -91,7 +92,7 @@ import com.sun.tools.javac.util.Name;
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
public abstract class Symbol extends AnnoConstruct implements PoolConstant, Element {
|
||||
|
||||
/** The kind of this symbol.
|
||||
* @see Kinds
|
||||
@ -286,6 +287,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
throw new AssertionError("Invalid pool entry");
|
||||
}
|
||||
|
||||
/** Clone this symbol with new owner.
|
||||
* Legal only for fields and methods.
|
||||
*/
|
||||
@ -971,6 +977,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
this.type = new ModuleType(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
return ClassFile.CONSTANT_Module;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public Name getSimpleName() {
|
||||
return Convert.shortName(name);
|
||||
@ -1137,6 +1148,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
return members_field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
return ClassFile.CONSTANT_Package;
|
||||
}
|
||||
|
||||
public long flags() {
|
||||
complete();
|
||||
return flags_field;
|
||||
@ -1237,10 +1253,6 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
*/
|
||||
public List<ClassSymbol> trans_local;
|
||||
|
||||
/** the constant pool of the class
|
||||
*/
|
||||
public Pool pool;
|
||||
|
||||
/** the annotation metadata attached to this class */
|
||||
private AnnotationTypeMetadata annotationTypeMetadata;
|
||||
|
||||
@ -1251,7 +1263,6 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
this.flatname = formFlatName(name, owner);
|
||||
this.sourcefile = null;
|
||||
this.classfile = null;
|
||||
this.pool = null;
|
||||
this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
|
||||
}
|
||||
|
||||
@ -1543,6 +1554,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
super(VAR, flags, name, type, owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
return ClassFile.CONSTANT_Fieldref;
|
||||
}
|
||||
|
||||
/** Clone this symbol with new owner.
|
||||
*/
|
||||
public VarSymbol clone(Symbol newOwner) {
|
||||
@ -1551,6 +1567,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
public Symbol baseSymbol() {
|
||||
return VarSymbol.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poolKey(Types types) {
|
||||
return new Pair<>(newOwner, baseSymbol());
|
||||
}
|
||||
};
|
||||
v.pos = pos;
|
||||
v.adr = adr;
|
||||
@ -1711,6 +1732,11 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
public Symbol baseSymbol() {
|
||||
return MethodSymbol.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poolKey(Types types) {
|
||||
return new Pair<>(newOwner, baseSymbol());
|
||||
}
|
||||
};
|
||||
m.code = code;
|
||||
return m;
|
||||
@ -1740,10 +1766,25 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
return owner.isInterface() ?
|
||||
ClassFile.CONSTANT_InterfaceMethodref : ClassFile.CONSTANT_Methodref;
|
||||
}
|
||||
|
||||
public boolean isDynamic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isHandle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public MethodHandleSymbol asHandle() {
|
||||
return new MethodHandleSymbol(this);
|
||||
}
|
||||
|
||||
/** find a symbol that this (proxy method) symbol implements.
|
||||
* @param c The class whose members are searched for
|
||||
* implementations
|
||||
@ -2027,16 +2068,14 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
|
||||
/** A class for invokedynamic method calls.
|
||||
*/
|
||||
public static class DynamicMethodSymbol extends MethodSymbol {
|
||||
public static class DynamicMethodSymbol extends MethodSymbol implements Dynamic {
|
||||
|
||||
public Object[] staticArgs;
|
||||
public Symbol bsm;
|
||||
public int bsmKind;
|
||||
public LoadableConstant[] staticArgs;
|
||||
public MethodHandleSymbol bsm;
|
||||
|
||||
public DynamicMethodSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) {
|
||||
public DynamicMethodSymbol(Name name, Symbol owner, MethodHandleSymbol bsm, Type type, LoadableConstant[] staticArgs) {
|
||||
super(0, name, type, owner);
|
||||
this.bsm = bsm;
|
||||
this.bsmKind = bsmKind;
|
||||
this.staticArgs = staticArgs;
|
||||
}
|
||||
|
||||
@ -2044,6 +2083,83 @@ public abstract class Symbol extends AnnoConstruct implements Element {
|
||||
public boolean isDynamic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadableConstant[] staticArgs() {
|
||||
return staticArgs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandleSymbol bootstrapMethod() {
|
||||
return bsm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
return ClassFile.CONSTANT_InvokeDynamic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type dynamicType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
/** A class for method handles.
|
||||
*/
|
||||
public static class MethodHandleSymbol extends MethodSymbol implements LoadableConstant {
|
||||
|
||||
private Symbol refSym;
|
||||
|
||||
public MethodHandleSymbol(Symbol msym) {
|
||||
super(msym.flags_field, msym.name, msym.type, msym.owner);
|
||||
this.refSym = msym;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the kind associated with this method handle.
|
||||
*/
|
||||
public int referenceKind() {
|
||||
if (refSym.isConstructor()) {
|
||||
return ClassFile.REF_newInvokeSpecial;
|
||||
} else {
|
||||
if (refSym.isStatic()) {
|
||||
return ClassFile.REF_invokeStatic;
|
||||
} else if ((refSym.flags() & PRIVATE) != 0) {
|
||||
return ClassFile.REF_invokeSpecial;
|
||||
} else if (refSym.enclClass().isInterface()) {
|
||||
return ClassFile.REF_invokeInterface;
|
||||
} else {
|
||||
return ClassFile.REF_invokeVirtual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
return ClassFile.CONSTANT_MethodHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poolKey(Types types) {
|
||||
return new Pair<>(baseSymbol(), referenceKind());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandleSymbol asHandle() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol baseSymbol() {
|
||||
return refSym;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isHandle() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** A class for predefined operators.
|
||||
|
@ -36,7 +36,10 @@ import javax.lang.model.type.*;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.TypeMetadata.Entry;
|
||||
import com.sun.tools.javac.code.Types.TypeMapping;
|
||||
import com.sun.tools.javac.code.Types.UniqueType;
|
||||
import com.sun.tools.javac.comp.Infer.IncorporationAction;
|
||||
import com.sun.tools.javac.jvm.ClassFile;
|
||||
import com.sun.tools.javac.jvm.PoolConstant;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
|
||||
@ -73,7 +76,7 @@ import static com.sun.tools.javac.code.TypeTag.*;
|
||||
*
|
||||
* @see TypeTag
|
||||
*/
|
||||
public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
public abstract class Type extends AnnoConstruct implements TypeMirror, PoolConstant {
|
||||
|
||||
/**
|
||||
* Type metadata, Should be {@code null} for the default value.
|
||||
@ -125,6 +128,16 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
*/
|
||||
public TypeSymbol tsym;
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
throw new AssertionError("Invalid pool entry");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poolKey(Types types) {
|
||||
return new UniqueType(this, types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current type tag is equal to the given tag.
|
||||
* @return true if tag is equal to the current type tag.
|
||||
@ -930,7 +943,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
}
|
||||
}
|
||||
|
||||
public static class ClassType extends Type implements DeclaredType,
|
||||
public static class ClassType extends Type implements DeclaredType, LoadableConstant,
|
||||
javax.lang.model.type.ErrorType {
|
||||
|
||||
/** The enclosing type of this type. If this is the type of an inner
|
||||
@ -975,6 +988,10 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
this.interfaces_field = null;
|
||||
}
|
||||
|
||||
public int poolTag() {
|
||||
return ClassFile.CONSTANT_Class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassType cloneWithMetadata(TypeMetadata md) {
|
||||
return new ClassType(outer_field, typarams_field, tsym, md) {
|
||||
@ -1277,7 +1294,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
}
|
||||
|
||||
public static class ArrayType extends Type
|
||||
implements javax.lang.model.type.ArrayType {
|
||||
implements LoadableConstant, javax.lang.model.type.ArrayType {
|
||||
|
||||
public Type elemtype;
|
||||
|
||||
@ -1297,6 +1314,10 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
this(that.elemtype, that.tsym, that.getMetadata());
|
||||
}
|
||||
|
||||
public int poolTag() {
|
||||
return ClassFile.CONSTANT_Class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayType cloneWithMetadata(TypeMetadata md) {
|
||||
return new ArrayType(elemtype, tsym, md) {
|
||||
@ -1412,7 +1433,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MethodType extends Type implements ExecutableType {
|
||||
public static class MethodType extends Type implements ExecutableType, LoadableConstant {
|
||||
|
||||
public List<Type> argtypes;
|
||||
public Type restype;
|
||||
@ -1479,6 +1500,11 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
restype != null && restype.isErroneous();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
return ClassFile.CONSTANT_MethodType;
|
||||
}
|
||||
|
||||
public boolean contains(Type elem) {
|
||||
return elem.equalsIgnoreMetadata(this) || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem);
|
||||
}
|
||||
|
@ -48,6 +48,8 @@ import com.sun.tools.javac.comp.AttrContext;
|
||||
import com.sun.tools.javac.comp.Check;
|
||||
import com.sun.tools.javac.comp.Enter;
|
||||
import com.sun.tools.javac.comp.Env;
|
||||
import com.sun.tools.javac.comp.LambdaToMethod;
|
||||
import com.sun.tools.javac.jvm.ClassFile;
|
||||
import com.sun.tools.javac.util.*;
|
||||
|
||||
import static com.sun.tools.javac.code.BoundKind.*;
|
||||
@ -5181,6 +5183,29 @@ public class Types {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Type constantType(LoadableConstant c) {
|
||||
switch (c.poolTag()) {
|
||||
case ClassFile.CONSTANT_Class:
|
||||
return syms.classType;
|
||||
case ClassFile.CONSTANT_String:
|
||||
return syms.stringType;
|
||||
case ClassFile.CONSTANT_Integer:
|
||||
return syms.intType;
|
||||
case ClassFile.CONSTANT_Float:
|
||||
return syms.floatType;
|
||||
case ClassFile.CONSTANT_Long:
|
||||
return syms.longType;
|
||||
case ClassFile.CONSTANT_Double:
|
||||
return syms.doubleType;
|
||||
case ClassFile.CONSTANT_MethodHandle:
|
||||
return syms.methodHandleType;
|
||||
case ClassFile.CONSTANT_MethodType:
|
||||
return syms.methodTypeType;
|
||||
default:
|
||||
throw new AssertionError("Not a loadable constant: " + c.poolTag());
|
||||
}
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
public void newRound() {
|
||||
|
@ -25,7 +25,9 @@
|
||||
|
||||
package com.sun.tools.javac.comp;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
|
||||
import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Errors;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
|
||||
import com.sun.tools.javac.tree.*;
|
||||
@ -59,7 +61,6 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
@ -70,13 +71,10 @@ import static com.sun.tools.javac.code.Flags.*;
|
||||
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
||||
import static com.sun.tools.javac.code.TypeTag.*;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.*;
|
||||
import static com.sun.tools.javac.jvm.Pool.DynamicMethod;
|
||||
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
|
||||
import com.sun.tools.javac.code.Type.IntersectionClassType;
|
||||
import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
|
||||
import com.sun.tools.javac.main.Option;
|
||||
|
||||
/**
|
||||
@ -214,7 +212,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
|
||||
private Map<DedupedLambda, DedupedLambda> dedupedLambdas;
|
||||
|
||||
private Map<DynamicMethod, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
|
||||
private Map<Object, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
|
||||
|
||||
/**
|
||||
* list of deserialization cases
|
||||
@ -439,11 +437,8 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
//then, determine the arguments to the indy call
|
||||
List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
|
||||
|
||||
//build a sam instance using an indy call to the meta-factory
|
||||
int refKind = referenceKind(sym);
|
||||
|
||||
//convert to an invokedynamic call
|
||||
result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
|
||||
result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args);
|
||||
}
|
||||
|
||||
// where
|
||||
@ -488,7 +483,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
|
||||
//first determine the method symbol to be used to generate the sam instance
|
||||
//this is either the method reference symbol, or the bridged reference symbol
|
||||
Symbol refSym = tree.sym;
|
||||
MethodSymbol refSym = (MethodSymbol)tree.sym;
|
||||
|
||||
//the qualifying expression is treated as a special captured arg
|
||||
JCExpression init;
|
||||
@ -522,7 +517,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
|
||||
|
||||
//build a sam instance using an indy call to the meta-factory
|
||||
result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
|
||||
result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -765,8 +760,8 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
|
||||
}
|
||||
|
||||
private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
|
||||
DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
|
||||
private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym,
|
||||
DiagnosticPosition pos, List<LoadableConstant> staticArgs, MethodType indyType) {
|
||||
String functionalInterfaceClass = classSig(targetType);
|
||||
String functionalInterfaceMethodName = samSym.getSimpleName().toString();
|
||||
String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
|
||||
@ -774,7 +769,8 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
String implMethodName = refSym.getQualifiedName().toString();
|
||||
String implMethodSignature = typeSig(types.erasure(refSym.type));
|
||||
|
||||
JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
|
||||
JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType),
|
||||
make.Literal(refSym.referenceKind()));
|
||||
ListBuffer<JCExpression> serArgs = new ListBuffer<>();
|
||||
int i = 0;
|
||||
for (Type t : indyType.getParameterTypes()) {
|
||||
@ -1106,13 +1102,13 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
* Generate an indy method call to the meta factory
|
||||
*/
|
||||
private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
|
||||
int refKind, Symbol refSym, List<JCExpression> indy_args) {
|
||||
MethodHandleSymbol refSym, List<JCExpression> indy_args) {
|
||||
JCFunctionalExpression tree = context.tree;
|
||||
//determine the static bsm args
|
||||
MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
|
||||
List<Object> staticArgs = List.of(
|
||||
List<LoadableConstant> staticArgs = List.of(
|
||||
typeToMethodType(samSym.type),
|
||||
new Pool.MethodHandle(refKind, refSym, types),
|
||||
((MethodSymbol)refSym).asHandle(),
|
||||
typeToMethodType(tree.getDescriptorType(types)));
|
||||
|
||||
//computed indy arg types
|
||||
@ -1131,7 +1127,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
names.altMetafactory : names.metafactory;
|
||||
|
||||
if (context.needsAltMetafactory()) {
|
||||
ListBuffer<Object> markers = new ListBuffer<>();
|
||||
ListBuffer<Type> markers = new ListBuffer<>();
|
||||
List<Type> targets = tree.target.isIntersection() ?
|
||||
types.directSupertypes(tree.target) :
|
||||
List.nil();
|
||||
@ -1140,7 +1136,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
if (t.tsym != syms.serializableType.tsym &&
|
||||
t.tsym != tree.type.tsym &&
|
||||
t.tsym != syms.objectType.tsym) {
|
||||
markers.append(t.tsym);
|
||||
markers.append(t);
|
||||
}
|
||||
}
|
||||
int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
|
||||
@ -1152,17 +1148,17 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
if (hasBridges) {
|
||||
flags |= FLAG_BRIDGES;
|
||||
}
|
||||
staticArgs = staticArgs.append(flags);
|
||||
staticArgs = staticArgs.append(LoadableConstant.Int(flags));
|
||||
if (hasMarkers) {
|
||||
staticArgs = staticArgs.append(markers.length());
|
||||
staticArgs = staticArgs.appendList(markers.toList());
|
||||
staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
|
||||
staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
|
||||
}
|
||||
if (hasBridges) {
|
||||
staticArgs = staticArgs.append(context.bridges.length() - 1);
|
||||
staticArgs = staticArgs.append(LoadableConstant.Int(context.bridges.length() - 1));
|
||||
for (Symbol s : context.bridges) {
|
||||
Type s_erasure = s.erasure(types);
|
||||
if (!types.isSameType(s_erasure, samSym.erasure(types))) {
|
||||
staticArgs = staticArgs.append(s.erasure(types));
|
||||
staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1170,7 +1166,7 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
int prevPos = make.pos;
|
||||
try {
|
||||
make.at(kInfo.clazz);
|
||||
addDeserializationCase(refKind, refSym, tree.type, samSym,
|
||||
addDeserializationCase(refSym, tree.type, samSym,
|
||||
tree, staticArgs, indyType);
|
||||
} finally {
|
||||
make.at(prevPos);
|
||||
@ -1186,14 +1182,14 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
* arguments types
|
||||
*/
|
||||
private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
|
||||
List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
|
||||
Name methName) {
|
||||
List<LoadableConstant> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
|
||||
Name methName) {
|
||||
int prevPos = make.pos;
|
||||
try {
|
||||
make.at(pos);
|
||||
List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
|
||||
syms.stringType,
|
||||
syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
|
||||
syms.stringType,
|
||||
syms.methodTypeType).appendList(staticArgs.map(types::constantType));
|
||||
|
||||
Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
|
||||
bsmName, bsm_staticArgs, List.nil());
|
||||
@ -1201,15 +1197,12 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
DynamicMethodSymbol dynSym =
|
||||
new DynamicMethodSymbol(methName,
|
||||
syms.noSymbol,
|
||||
bsm.isStatic() ?
|
||||
ClassFile.REF_invokeStatic :
|
||||
ClassFile.REF_invokeVirtual,
|
||||
(MethodSymbol)bsm,
|
||||
((MethodSymbol)bsm).asHandle(),
|
||||
indyType,
|
||||
staticArgs.toArray());
|
||||
staticArgs.toArray(new LoadableConstant[staticArgs.length()]));
|
||||
JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
|
||||
DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
|
||||
new DynamicMethod(dynSym, types), dynSym);
|
||||
dynSym.poolKey(types), dynSym);
|
||||
qualifier.sym = existing != null ? existing : dynSym;
|
||||
qualifier.type = indyType.getReturnType();
|
||||
|
||||
@ -1220,57 +1213,6 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
make.at(prevPos);
|
||||
}
|
||||
}
|
||||
//where
|
||||
private List<Type> bsmStaticArgToTypes(List<Object> args) {
|
||||
ListBuffer<Type> argtypes = new ListBuffer<>();
|
||||
for (Object arg : args) {
|
||||
argtypes.append(bsmStaticArgToType(arg));
|
||||
}
|
||||
return argtypes.toList();
|
||||
}
|
||||
|
||||
private Type bsmStaticArgToType(Object arg) {
|
||||
Assert.checkNonNull(arg);
|
||||
if (arg instanceof ClassSymbol) {
|
||||
return syms.classType;
|
||||
} else if (arg instanceof Integer) {
|
||||
return syms.intType;
|
||||
} else if (arg instanceof Long) {
|
||||
return syms.longType;
|
||||
} else if (arg instanceof Float) {
|
||||
return syms.floatType;
|
||||
} else if (arg instanceof Double) {
|
||||
return syms.doubleType;
|
||||
} else if (arg instanceof String) {
|
||||
return syms.stringType;
|
||||
} else if (arg instanceof Pool.MethodHandle) {
|
||||
return syms.methodHandleType;
|
||||
} else if (arg instanceof MethodType) {
|
||||
return syms.methodTypeType;
|
||||
} else {
|
||||
Assert.error("bad static arg " + arg.getClass());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the opcode associated with this method reference
|
||||
*/
|
||||
private int referenceKind(Symbol refSym) {
|
||||
if (refSym.isConstructor()) {
|
||||
return ClassFile.REF_newInvokeSpecial;
|
||||
} else {
|
||||
if (refSym.isStatic()) {
|
||||
return ClassFile.REF_invokeStatic;
|
||||
} else if ((refSym.flags() & PRIVATE) != 0) {
|
||||
return ClassFile.REF_invokeSpecial;
|
||||
} else if (refSym.enclClass().isInterface()) {
|
||||
return ClassFile.REF_invokeInterface;
|
||||
} else {
|
||||
return ClassFile.REF_invokeVirtual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
|
||||
/**
|
||||
@ -2312,13 +2254,6 @@ public class LambdaToMethod extends TreeTranslator {
|
||||
this.isSuper = tree.hasKind(ReferenceKind.SUPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the opcode associated with this method reference
|
||||
*/
|
||||
int referenceKind() {
|
||||
return LambdaToMethod.this.referenceKind(tree.sym);
|
||||
}
|
||||
|
||||
boolean needsVarArgsConversion() {
|
||||
return tree.varargsElement != null;
|
||||
}
|
||||
|
@ -93,7 +93,6 @@ public class Lower extends TreeTranslator {
|
||||
private final Attr attr;
|
||||
private TreeMaker make;
|
||||
private DiagnosticPosition make_pos;
|
||||
private final ClassWriter writer;
|
||||
private final ConstFold cfolder;
|
||||
private final Target target;
|
||||
private final Source source;
|
||||
@ -116,7 +115,6 @@ public class Lower extends TreeTranslator {
|
||||
chk = Check.instance(context);
|
||||
attr = Attr.instance(context);
|
||||
make = TreeMaker.instance(context);
|
||||
writer = ClassWriter.instance(context);
|
||||
cfolder = ConstFold.instance(context);
|
||||
target = Target.instance(context);
|
||||
source = Source.instance(context);
|
||||
@ -475,7 +473,7 @@ public class Lower extends TreeTranslator {
|
||||
.fromString(target.syntheticNameChar() +
|
||||
"SwitchMap" +
|
||||
target.syntheticNameChar() +
|
||||
writer.xClassName(forEnum.type).toString()
|
||||
names.fromUtf(ClassWriter.externalize(forEnum.type.tsym.flatName())).toString()
|
||||
.replace('/', '.')
|
||||
.replace('.', target.syntheticNameChar()));
|
||||
ClassSymbol outerCacheClass = outerCacheClass();
|
||||
|
@ -25,9 +25,6 @@
|
||||
|
||||
package com.sun.tools.javac.jvm;
|
||||
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.code.Types.UniqueType;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
|
||||
@ -189,38 +186,4 @@ public class ClassFile {
|
||||
public static byte[] externalize(Name name) {
|
||||
return externalize(name.getByteArray(), name.getByteOffset(), name.getByteLength());
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Name-and-type
|
||||
***********************************************************************/
|
||||
|
||||
/** A class for the name-and-type signature of a method or field.
|
||||
*/
|
||||
public static class NameAndType {
|
||||
Name name;
|
||||
UniqueType uniqueType;
|
||||
Types types;
|
||||
|
||||
NameAndType(Name name, Type type, Types types) {
|
||||
this.name = name;
|
||||
this.uniqueType = new UniqueType(type, types);
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
void setType(Type type) {
|
||||
this.uniqueType = new UniqueType(type, types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return (other instanceof NameAndType &&
|
||||
name == ((NameAndType) other).name &&
|
||||
uniqueType.equals(((NameAndType) other).uniqueType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode() * uniqueType.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -36,6 +36,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.NestingKind;
|
||||
@ -55,8 +56,8 @@ import com.sun.tools.javac.code.Type.*;
|
||||
import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
|
||||
import com.sun.tools.javac.file.BaseFileManager;
|
||||
import com.sun.tools.javac.file.PathFileObject;
|
||||
import com.sun.tools.javac.jvm.ClassFile.NameAndType;
|
||||
import com.sun.tools.javac.jvm.ClassFile.Version;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
|
||||
import com.sun.tools.javac.main.Option;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Warnings;
|
||||
@ -100,11 +101,6 @@ public class ClassReader {
|
||||
*/
|
||||
boolean verbose;
|
||||
|
||||
/** Switch: read constant pool and code sections. This switch is initially
|
||||
* set to false but can be turned on from outside.
|
||||
*/
|
||||
public boolean readAllOfClassFile = false;
|
||||
|
||||
/** Switch: allow modules.
|
||||
*/
|
||||
boolean allowModules;
|
||||
@ -170,20 +166,15 @@ public class ClassReader {
|
||||
|
||||
/** The buffer containing the currently read class file.
|
||||
*/
|
||||
byte[] buf = new byte[INITIAL_BUFFER_SIZE];
|
||||
ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE);
|
||||
|
||||
/** The current input pointer.
|
||||
*/
|
||||
protected int bp;
|
||||
|
||||
/** The objects of the constant pool.
|
||||
/** The pool reader.
|
||||
*/
|
||||
Object[] poolObj;
|
||||
|
||||
/** For every constant pool entry, an index into buf where the
|
||||
* defining section of the entry is found.
|
||||
*/
|
||||
int[] poolIdx;
|
||||
PoolReader poolReader;
|
||||
|
||||
/** The major version number of the class file being read. */
|
||||
int majorVersion;
|
||||
@ -323,294 +314,29 @@ public class ClassReader {
|
||||
/** Read a character.
|
||||
*/
|
||||
char nextChar() {
|
||||
return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
|
||||
char res = buf.getChar(bp);
|
||||
bp += 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Read a byte.
|
||||
*/
|
||||
int nextByte() {
|
||||
return buf[bp++] & 0xFF;
|
||||
return buf.getByte(bp++) & 0xFF;
|
||||
}
|
||||
|
||||
/** Read an integer.
|
||||
*/
|
||||
int nextInt() {
|
||||
return
|
||||
((buf[bp++] & 0xFF) << 24) +
|
||||
((buf[bp++] & 0xFF) << 16) +
|
||||
((buf[bp++] & 0xFF) << 8) +
|
||||
(buf[bp++] & 0xFF);
|
||||
}
|
||||
|
||||
/** Extract a character at position bp from buf.
|
||||
*/
|
||||
char getChar(int bp) {
|
||||
return
|
||||
(char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
|
||||
}
|
||||
|
||||
/** Extract an integer at position bp from buf.
|
||||
*/
|
||||
int getInt(int bp) {
|
||||
return
|
||||
((buf[bp] & 0xFF) << 24) +
|
||||
((buf[bp+1] & 0xFF) << 16) +
|
||||
((buf[bp+2] & 0xFF) << 8) +
|
||||
(buf[bp+3] & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
/** Extract a long integer at position bp from buf.
|
||||
*/
|
||||
long getLong(int bp) {
|
||||
DataInputStream bufin =
|
||||
new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
|
||||
try {
|
||||
return bufin.readLong();
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Extract a float at position bp from buf.
|
||||
*/
|
||||
float getFloat(int bp) {
|
||||
DataInputStream bufin =
|
||||
new DataInputStream(new ByteArrayInputStream(buf, bp, 4));
|
||||
try {
|
||||
return bufin.readFloat();
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Extract a double at position bp from buf.
|
||||
*/
|
||||
double getDouble(int bp) {
|
||||
DataInputStream bufin =
|
||||
new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
|
||||
try {
|
||||
return bufin.readDouble();
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
int res = buf.getInt(bp);
|
||||
bp += 4;
|
||||
return res;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Constant Pool Access
|
||||
***********************************************************************/
|
||||
|
||||
/** Index all constant pool entries, writing their start addresses into
|
||||
* poolIdx.
|
||||
*/
|
||||
void indexPool() {
|
||||
poolIdx = new int[nextChar()];
|
||||
poolObj = new Object[poolIdx.length];
|
||||
int i = 1;
|
||||
while (i < poolIdx.length) {
|
||||
poolIdx[i++] = bp;
|
||||
byte tag = buf[bp++];
|
||||
switch (tag) {
|
||||
case CONSTANT_Utf8: case CONSTANT_Unicode: {
|
||||
int len = nextChar();
|
||||
bp = bp + len;
|
||||
break;
|
||||
}
|
||||
case CONSTANT_Class:
|
||||
case CONSTANT_String:
|
||||
case CONSTANT_MethodType:
|
||||
case CONSTANT_Module:
|
||||
case CONSTANT_Package:
|
||||
bp = bp + 2;
|
||||
break;
|
||||
case CONSTANT_MethodHandle:
|
||||
bp = bp + 3;
|
||||
break;
|
||||
case CONSTANT_Fieldref:
|
||||
case CONSTANT_Methodref:
|
||||
case CONSTANT_InterfaceMethodref:
|
||||
case CONSTANT_NameandType:
|
||||
case CONSTANT_Integer:
|
||||
case CONSTANT_Float:
|
||||
case CONSTANT_Dynamic:
|
||||
case CONSTANT_InvokeDynamic:
|
||||
bp = bp + 4;
|
||||
break;
|
||||
case CONSTANT_Long:
|
||||
case CONSTANT_Double:
|
||||
bp = bp + 8;
|
||||
i++;
|
||||
break;
|
||||
default:
|
||||
throw badClassFile("bad.const.pool.tag.at",
|
||||
Byte.toString(tag),
|
||||
Integer.toString(bp -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Read constant pool entry at start address i, use pool as a cache.
|
||||
*/
|
||||
Object readPool(int i) {
|
||||
Object result = poolObj[i];
|
||||
if (result != null) return result;
|
||||
|
||||
int index = poolIdx[i];
|
||||
if (index == 0) return null;
|
||||
|
||||
byte tag = buf[index];
|
||||
switch (tag) {
|
||||
case CONSTANT_Utf8:
|
||||
poolObj[i] = names.fromUtf(buf, index + 3, getChar(index + 1));
|
||||
break;
|
||||
case CONSTANT_Unicode:
|
||||
throw badClassFile("unicode.str.not.supported");
|
||||
case CONSTANT_Class:
|
||||
poolObj[i] = readClassOrType(getChar(index + 1));
|
||||
break;
|
||||
case CONSTANT_String:
|
||||
// FIXME: (footprint) do not use toString here
|
||||
poolObj[i] = readName(getChar(index + 1)).toString();
|
||||
break;
|
||||
case CONSTANT_Fieldref: {
|
||||
ClassSymbol owner = readClassSymbol(getChar(index + 1));
|
||||
NameAndType nt = readNameAndType(getChar(index + 3));
|
||||
poolObj[i] = new VarSymbol(0, nt.name, nt.uniqueType.type, owner);
|
||||
break;
|
||||
}
|
||||
case CONSTANT_Methodref:
|
||||
case CONSTANT_InterfaceMethodref: {
|
||||
ClassSymbol owner = readClassSymbol(getChar(index + 1));
|
||||
NameAndType nt = readNameAndType(getChar(index + 3));
|
||||
poolObj[i] = new MethodSymbol(0, nt.name, nt.uniqueType.type, owner);
|
||||
break;
|
||||
}
|
||||
case CONSTANT_NameandType:
|
||||
poolObj[i] = new NameAndType(
|
||||
readName(getChar(index + 1)),
|
||||
readType(getChar(index + 3)), types);
|
||||
break;
|
||||
case CONSTANT_Integer:
|
||||
poolObj[i] = getInt(index + 1);
|
||||
break;
|
||||
case CONSTANT_Float:
|
||||
poolObj[i] = Float.valueOf(getFloat(index + 1));
|
||||
break;
|
||||
case CONSTANT_Long:
|
||||
poolObj[i] = Long.valueOf(getLong(index + 1));
|
||||
break;
|
||||
case CONSTANT_Double:
|
||||
poolObj[i] = Double.valueOf(getDouble(index + 1));
|
||||
break;
|
||||
case CONSTANT_MethodHandle:
|
||||
skipBytes(4);
|
||||
break;
|
||||
case CONSTANT_MethodType:
|
||||
skipBytes(3);
|
||||
break;
|
||||
case CONSTANT_Dynamic:
|
||||
case CONSTANT_InvokeDynamic:
|
||||
skipBytes(5);
|
||||
break;
|
||||
case CONSTANT_Module:
|
||||
case CONSTANT_Package:
|
||||
// this is temporary for now: treat as a simple reference to the underlying Utf8.
|
||||
poolObj[i] = readName(getChar(index + 1));
|
||||
break;
|
||||
default:
|
||||
throw badClassFile("bad.const.pool.tag", Byte.toString(tag));
|
||||
}
|
||||
return poolObj[i];
|
||||
}
|
||||
|
||||
/** Read signature and convert to type.
|
||||
*/
|
||||
Type readType(int i) {
|
||||
int index = poolIdx[i];
|
||||
return sigToType(buf, index + 3, getChar(index + 1));
|
||||
}
|
||||
|
||||
/** If name is an array type or class signature, return the
|
||||
* corresponding type; otherwise return a ClassSymbol with given name.
|
||||
*/
|
||||
Object readClassOrType(int i) {
|
||||
int index = poolIdx[i];
|
||||
int len = getChar(index + 1);
|
||||
int start = index + 3;
|
||||
Assert.check(buf[start] == '[' || buf[start + len - 1] != ';');
|
||||
// by the above assertion, the following test can be
|
||||
// simplified to (buf[start] == '[')
|
||||
return (buf[start] == '[' || buf[start + len - 1] == ';')
|
||||
? (Object)sigToType(buf, start, len)
|
||||
: (Object)enterClass(names.fromUtf(internalize(buf, start,
|
||||
len)));
|
||||
}
|
||||
|
||||
/** Read signature and convert to type parameters.
|
||||
*/
|
||||
List<Type> readTypeParams(int i) {
|
||||
int index = poolIdx[i];
|
||||
return sigToTypeParams(buf, index + 3, getChar(index + 1));
|
||||
}
|
||||
|
||||
/** Read class entry.
|
||||
*/
|
||||
ClassSymbol readClassSymbol(int i) {
|
||||
Object obj = readPool(i);
|
||||
if (obj != null && !(obj instanceof ClassSymbol))
|
||||
throw badClassFile("bad.const.pool.entry",
|
||||
currentClassFile.toString(),
|
||||
"CONSTANT_Class_info", i);
|
||||
return (ClassSymbol)obj;
|
||||
}
|
||||
|
||||
Name readClassName(int i) {
|
||||
int index = poolIdx[i];
|
||||
if (index == 0) return null;
|
||||
byte tag = buf[index];
|
||||
if (tag != CONSTANT_Class) {
|
||||
throw badClassFile("bad.const.pool.entry",
|
||||
currentClassFile.toString(),
|
||||
"CONSTANT_Class_info", i);
|
||||
}
|
||||
int nameIndex = poolIdx[getChar(index + 1)];
|
||||
int len = getChar(nameIndex + 1);
|
||||
int start = nameIndex + 3;
|
||||
if (buf[start] == '[' || buf[start + len - 1] == ';')
|
||||
throw badClassFile("wrong class name"); //TODO: proper diagnostics
|
||||
return names.fromUtf(internalize(buf, start, len));
|
||||
}
|
||||
|
||||
/** Read name.
|
||||
*/
|
||||
Name readName(int i) {
|
||||
Object obj = readPool(i);
|
||||
if (obj != null && !(obj instanceof Name))
|
||||
throw badClassFile("bad.const.pool.entry",
|
||||
currentClassFile.toString(),
|
||||
"CONSTANT_Utf8_info or CONSTANT_String_info", i);
|
||||
return (Name)obj;
|
||||
}
|
||||
|
||||
/** Read name and type.
|
||||
*/
|
||||
NameAndType readNameAndType(int i) {
|
||||
Object obj = readPool(i);
|
||||
if (obj != null && !(obj instanceof NameAndType))
|
||||
throw badClassFile("bad.const.pool.entry",
|
||||
currentClassFile.toString(),
|
||||
"CONSTANT_NameAndType_info", i);
|
||||
return (NameAndType)obj;
|
||||
}
|
||||
|
||||
/** Read the name of a module.
|
||||
* The name is stored in a CONSTANT_Module entry, in
|
||||
* JVMS 4.2 binary form (using ".", not "/")
|
||||
*/
|
||||
Name readModuleName(int i) {
|
||||
return readName(i);
|
||||
}
|
||||
|
||||
/** Read module_flags.
|
||||
*/
|
||||
Set<ModuleFlags> readModuleFlags(int flags) {
|
||||
@ -762,7 +488,7 @@ public class ClassReader {
|
||||
List<Type> argtypes = sigToTypes(')');
|
||||
Type restype = sigToType();
|
||||
List<Type> thrown = List.nil();
|
||||
while (signature[sigp] == '^') {
|
||||
while (sigp < siglimit && signature[sigp] == '^') {
|
||||
sigp++;
|
||||
thrown = thrown.prepend(sigToType());
|
||||
}
|
||||
@ -855,7 +581,7 @@ public class ClassReader {
|
||||
};
|
||||
switch (signature[sigp++]) {
|
||||
case ';':
|
||||
if (sigp < signature.length && signature[sigp] == '.') {
|
||||
if (sigp < siglimit && signature[sigp] == '.') {
|
||||
// support old-style GJC signatures
|
||||
// The signature produced was
|
||||
// Lfoo/Outer<Lfoo/X;>;.Lfoo/Outer$Inner<Lfoo/Y;>;
|
||||
@ -1049,7 +775,7 @@ public class ClassReader {
|
||||
|
||||
new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
|
||||
protected void read(Symbol sym, int attrLen) {
|
||||
if (readAllOfClassFile || saveParameterNames)
|
||||
if (saveParameterNames)
|
||||
((MethodSymbol)sym).code = readCode(sym);
|
||||
else
|
||||
bp = bp + attrLen;
|
||||
@ -1058,7 +784,7 @@ public class ClassReader {
|
||||
|
||||
new AttributeReader(names.ConstantValue, V45_3, MEMBER_ATTRIBUTE) {
|
||||
protected void read(Symbol sym, int attrLen) {
|
||||
Object v = readPool(nextChar());
|
||||
Object v = poolReader.getConstant(nextChar());
|
||||
// Ignore ConstantValue attribute if field not final.
|
||||
if ((sym.flags() & FINAL) == 0) {
|
||||
return;
|
||||
@ -1115,7 +841,7 @@ public class ClassReader {
|
||||
int nexceptions = nextChar();
|
||||
List<Type> thrown = List.nil();
|
||||
for (int j = 0; j < nexceptions; j++)
|
||||
thrown = thrown.prepend(readClassSymbol(nextChar()).type);
|
||||
thrown = thrown.prepend(poolReader.getClass(nextChar()).type);
|
||||
if (sym.type.getThrownTypes().isEmpty())
|
||||
sym.type.asMethodType().thrown = thrown.reverse();
|
||||
}
|
||||
@ -1173,7 +899,7 @@ public class ClassReader {
|
||||
new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) {
|
||||
protected void read(Symbol sym, int attrLen) {
|
||||
ClassSymbol c = (ClassSymbol) sym;
|
||||
Name n = readName(nextChar());
|
||||
Name n = poolReader.getName(nextChar());
|
||||
c.sourcefile = new SourceFileObject(n);
|
||||
// If the class is a toplevel class, originating from a Java source file,
|
||||
// but the class name does not match the file name, then it is
|
||||
@ -1211,7 +937,8 @@ public class ClassReader {
|
||||
try {
|
||||
ClassType ct1 = (ClassType)c.type;
|
||||
Assert.check(c == currentOwner);
|
||||
ct1.typarams_field = readTypeParams(nextChar());
|
||||
ct1.typarams_field = poolReader.getName(nextChar())
|
||||
.map(ClassReader.this::sigToTypeParams);
|
||||
ct1.supertype_field = sigToType();
|
||||
ListBuffer<Type> is = new ListBuffer<>();
|
||||
while (sigp != siglimit) is.append(sigToType());
|
||||
@ -1221,7 +948,7 @@ public class ClassReader {
|
||||
}
|
||||
} else {
|
||||
List<Type> thrown = sym.type.getThrownTypes();
|
||||
sym.type = readType(nextChar());
|
||||
sym.type = poolReader.getType(nextChar());
|
||||
//- System.err.println(" # " + sym.type);
|
||||
if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
|
||||
sym.type.asMethodType().thrown = thrown;
|
||||
@ -1342,19 +1069,19 @@ public class ClassReader {
|
||||
ModuleSymbol msym = (ModuleSymbol) sym.owner;
|
||||
ListBuffer<Directive> directives = new ListBuffer<>();
|
||||
|
||||
Name moduleName = readModuleName(nextChar());
|
||||
Name moduleName = poolReader.peekModuleName(nextChar(), names::fromUtf);
|
||||
if (currentModule.name != moduleName) {
|
||||
throw badClassFile("module.name.mismatch", moduleName, currentModule.name);
|
||||
}
|
||||
|
||||
Set<ModuleFlags> moduleFlags = readModuleFlags(nextChar());
|
||||
msym.flags.addAll(moduleFlags);
|
||||
msym.version = readName(nextChar());
|
||||
msym.version = optPoolEntry(nextChar(), poolReader::getName, null);
|
||||
|
||||
ListBuffer<RequiresDirective> requires = new ListBuffer<>();
|
||||
int nrequires = nextChar();
|
||||
for (int i = 0; i < nrequires; i++) {
|
||||
ModuleSymbol rsym = syms.enterModule(readModuleName(nextChar()));
|
||||
ModuleSymbol rsym = poolReader.getModule(nextChar());
|
||||
Set<RequiresFlag> flags = readRequiresFlags(nextChar());
|
||||
if (rsym == syms.java_base && majorVersion >= V54.major) {
|
||||
if (flags.contains(RequiresFlag.TRANSITIVE)) {
|
||||
@ -1373,8 +1100,7 @@ public class ClassReader {
|
||||
ListBuffer<ExportsDirective> exports = new ListBuffer<>();
|
||||
int nexports = nextChar();
|
||||
for (int i = 0; i < nexports; i++) {
|
||||
Name n = readName(nextChar());
|
||||
PackageSymbol p = syms.enterPackage(currentModule, names.fromUtf(internalize(n)));
|
||||
PackageSymbol p = poolReader.getPackage(nextChar());
|
||||
Set<ExportsFlag> flags = readExportsFlags(nextChar());
|
||||
int nto = nextChar();
|
||||
List<ModuleSymbol> to;
|
||||
@ -1383,7 +1109,7 @@ public class ClassReader {
|
||||
} else {
|
||||
ListBuffer<ModuleSymbol> lb = new ListBuffer<>();
|
||||
for (int t = 0; t < nto; t++)
|
||||
lb.append(syms.enterModule(readModuleName(nextChar())));
|
||||
lb.append(poolReader.getModule(nextChar()));
|
||||
to = lb.toList();
|
||||
}
|
||||
exports.add(new ExportsDirective(p, to, flags));
|
||||
@ -1396,8 +1122,7 @@ public class ClassReader {
|
||||
throw badClassFile("module.non.zero.opens", currentModule.name);
|
||||
}
|
||||
for (int i = 0; i < nopens; i++) {
|
||||
Name n = readName(nextChar());
|
||||
PackageSymbol p = syms.enterPackage(currentModule, names.fromUtf(internalize(n)));
|
||||
PackageSymbol p = poolReader.getPackage(nextChar());
|
||||
Set<OpensFlag> flags = readOpensFlags(nextChar());
|
||||
int nto = nextChar();
|
||||
List<ModuleSymbol> to;
|
||||
@ -1406,7 +1131,7 @@ public class ClassReader {
|
||||
} else {
|
||||
ListBuffer<ModuleSymbol> lb = new ListBuffer<>();
|
||||
for (int t = 0; t < nto; t++)
|
||||
lb.append(syms.enterModule(readModuleName(nextChar())));
|
||||
lb.append(poolReader.getModule(nextChar()));
|
||||
to = lb.toList();
|
||||
}
|
||||
opens.add(new OpensDirective(p, to, flags));
|
||||
@ -1419,7 +1144,7 @@ public class ClassReader {
|
||||
ListBuffer<InterimUsesDirective> uses = new ListBuffer<>();
|
||||
int nuses = nextChar();
|
||||
for (int i = 0; i < nuses; i++) {
|
||||
Name srvc = readClassName(nextChar());
|
||||
Name srvc = poolReader.peekClassName(nextChar(), this::classNameMapper);
|
||||
uses.add(new InterimUsesDirective(srvc));
|
||||
}
|
||||
interimUses = uses.toList();
|
||||
@ -1427,17 +1152,21 @@ public class ClassReader {
|
||||
ListBuffer<InterimProvidesDirective> provides = new ListBuffer<>();
|
||||
int nprovides = nextChar();
|
||||
for (int p = 0; p < nprovides; p++) {
|
||||
Name srvc = readClassName(nextChar());
|
||||
Name srvc = poolReader.peekClassName(nextChar(), this::classNameMapper);
|
||||
int nimpls = nextChar();
|
||||
ListBuffer<Name> impls = new ListBuffer<>();
|
||||
for (int i = 0; i < nimpls; i++) {
|
||||
impls.append(readClassName(nextChar()));
|
||||
impls.append(poolReader.peekClassName(nextChar(), this::classNameMapper));
|
||||
provides.add(new InterimProvidesDirective(srvc, impls.toList()));
|
||||
}
|
||||
}
|
||||
interimProvides = provides.toList();
|
||||
}
|
||||
}
|
||||
|
||||
private Name classNameMapper(byte[] arr, int offset, int length) {
|
||||
return names.fromUtf(ClassFile.internalize(arr, offset, length));
|
||||
}
|
||||
},
|
||||
|
||||
new AttributeReader(names.ModuleResolution, V53, CLASS_ATTRIBUTE) {
|
||||
@ -1464,8 +1193,8 @@ public class ClassReader {
|
||||
// the scope specified by the attribute
|
||||
sym.owner.members().remove(sym);
|
||||
ClassSymbol self = (ClassSymbol)sym;
|
||||
ClassSymbol c = readClassSymbol(nextChar());
|
||||
NameAndType nt = readNameAndType(nextChar());
|
||||
ClassSymbol c = poolReader.getClass(nextChar());
|
||||
NameAndType nt = optPoolEntry(nextChar(), poolReader::getNameAndType, null);
|
||||
|
||||
if (c.members_field == null || c.kind != TYP)
|
||||
throw badClassFile("bad.enclosing.class", self, c);
|
||||
@ -1520,7 +1249,7 @@ public class ClassReader {
|
||||
if (nt == null)
|
||||
return null;
|
||||
|
||||
MethodType type = nt.uniqueType.type.asMethodType();
|
||||
MethodType type = nt.type.asMethodType();
|
||||
|
||||
for (Symbol sym : scope.getSymbolsByName(nt.name)) {
|
||||
if (sym.kind == MTH && isSameBinaryType(sym.type.asMethodType(), type))
|
||||
@ -1533,15 +1262,15 @@ public class ClassReader {
|
||||
if ((flags & INTERFACE) != 0)
|
||||
// no enclosing instance
|
||||
return null;
|
||||
if (nt.uniqueType.type.getParameterTypes().isEmpty())
|
||||
if (nt.type.getParameterTypes().isEmpty())
|
||||
// no parameters
|
||||
return null;
|
||||
|
||||
// A constructor of an inner class.
|
||||
// Remove the first argument (the enclosing instance)
|
||||
nt.setType(new MethodType(nt.uniqueType.type.getParameterTypes().tail,
|
||||
nt.uniqueType.type.getReturnType(),
|
||||
nt.uniqueType.type.getThrownTypes(),
|
||||
nt = new NameAndType(nt.name, new MethodType(nt.type.getParameterTypes().tail,
|
||||
nt.type.getReturnType(),
|
||||
nt.type.getThrownTypes(),
|
||||
syms.methodClass));
|
||||
// Try searching again
|
||||
return findMethod(nt, scope, flags);
|
||||
@ -1578,7 +1307,7 @@ public class ClassReader {
|
||||
void readAttrs(Symbol sym, AttributeKind kind) {
|
||||
char ac = nextChar();
|
||||
for (int i = 0; i < ac; i++) {
|
||||
Name attrName = readName(nextChar());
|
||||
Name attrName = poolReader.getName(nextChar());
|
||||
int attrLen = nextInt();
|
||||
AttributeReader r = attributeReaders.get(attrName);
|
||||
if (r != null && r.accepts(kind))
|
||||
@ -1681,7 +1410,7 @@ public class ClassReader {
|
||||
/** Read parameter annotations.
|
||||
*/
|
||||
void readParameterAnnotations(Symbol meth) {
|
||||
int numParameters = buf[bp++] & 0xFF;
|
||||
int numParameters = buf.getByte(bp++) & 0xFF;
|
||||
if (parameterAnnotations == null) {
|
||||
parameterAnnotations = new ParameterAnnotations[numParameters];
|
||||
} else if (parameterAnnotations.length != numParameters) {
|
||||
@ -1725,39 +1454,30 @@ public class ClassReader {
|
||||
|
||||
Type readTypeOrClassSymbol(int i) {
|
||||
// support preliminary jsr175-format class files
|
||||
if (buf[poolIdx[i]] == CONSTANT_Class)
|
||||
return readClassSymbol(i).type;
|
||||
return readTypeToProxy(i);
|
||||
}
|
||||
Type readEnumType(int i) {
|
||||
// support preliminary jsr175-format class files
|
||||
int index = poolIdx[i];
|
||||
int length = getChar(index + 1);
|
||||
if (buf[index + length + 2] != ';')
|
||||
return enterClass(readName(i)).type;
|
||||
if (poolReader.hasTag(i, CONSTANT_Class))
|
||||
return poolReader.getClass(i).type;
|
||||
return readTypeToProxy(i);
|
||||
}
|
||||
Type readTypeToProxy(int i) {
|
||||
if (currentModule.module_info == currentOwner) {
|
||||
int index = poolIdx[i];
|
||||
return new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1)));
|
||||
return new ProxyType(i);
|
||||
} else {
|
||||
return readType(i);
|
||||
return poolReader.getType(i);
|
||||
}
|
||||
}
|
||||
|
||||
CompoundAnnotationProxy readCompoundAnnotation() {
|
||||
Type t;
|
||||
if (currentModule.module_info == currentOwner) {
|
||||
int index = poolIdx[nextChar()];
|
||||
t = new ProxyType(Arrays.copyOfRange(buf, index + 3, index + 3 + getChar(index + 1)));
|
||||
int cpIndex = nextChar();
|
||||
t = new ProxyType(cpIndex);
|
||||
} else {
|
||||
t = readTypeOrClassSymbol(nextChar());
|
||||
}
|
||||
int numFields = nextChar();
|
||||
ListBuffer<Pair<Name,Attribute>> pairs = new ListBuffer<>();
|
||||
for (int i=0; i<numFields; i++) {
|
||||
Name name = readName(nextChar());
|
||||
Name name = poolReader.getName(nextChar());
|
||||
Attribute value = readAttributeValue();
|
||||
pairs.append(new Pair<>(name, value));
|
||||
}
|
||||
@ -1970,29 +1690,40 @@ public class ClassReader {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to read an optional pool entry (with given function); this is used while parsing
|
||||
* InnerClasses and EnclosingMethod attributes, as well as when parsing supertype descriptor,
|
||||
* as per JVMS.
|
||||
*/
|
||||
<Z> Z optPoolEntry(int index, IntFunction<Z> poolFunc, Z defaultValue) {
|
||||
return (index == 0) ?
|
||||
defaultValue :
|
||||
poolFunc.apply(index);
|
||||
}
|
||||
|
||||
Attribute readAttributeValue() {
|
||||
char c = (char) buf[bp++];
|
||||
char c = (char) buf.getByte(bp++);
|
||||
switch (c) {
|
||||
case 'B':
|
||||
return new Attribute.Constant(syms.byteType, readPool(nextChar()));
|
||||
return new Attribute.Constant(syms.byteType, poolReader.getConstant(nextChar()));
|
||||
case 'C':
|
||||
return new Attribute.Constant(syms.charType, readPool(nextChar()));
|
||||
return new Attribute.Constant(syms.charType, poolReader.getConstant(nextChar()));
|
||||
case 'D':
|
||||
return new Attribute.Constant(syms.doubleType, readPool(nextChar()));
|
||||
return new Attribute.Constant(syms.doubleType, poolReader.getConstant(nextChar()));
|
||||
case 'F':
|
||||
return new Attribute.Constant(syms.floatType, readPool(nextChar()));
|
||||
return new Attribute.Constant(syms.floatType, poolReader.getConstant(nextChar()));
|
||||
case 'I':
|
||||
return new Attribute.Constant(syms.intType, readPool(nextChar()));
|
||||
return new Attribute.Constant(syms.intType, poolReader.getConstant(nextChar()));
|
||||
case 'J':
|
||||
return new Attribute.Constant(syms.longType, readPool(nextChar()));
|
||||
return new Attribute.Constant(syms.longType, poolReader.getConstant(nextChar()));
|
||||
case 'S':
|
||||
return new Attribute.Constant(syms.shortType, readPool(nextChar()));
|
||||
return new Attribute.Constant(syms.shortType, poolReader.getConstant(nextChar()));
|
||||
case 'Z':
|
||||
return new Attribute.Constant(syms.booleanType, readPool(nextChar()));
|
||||
return new Attribute.Constant(syms.booleanType, poolReader.getConstant(nextChar()));
|
||||
case 's':
|
||||
return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString());
|
||||
return new Attribute.Constant(syms.stringType, poolReader.getName(nextChar()).toString());
|
||||
case 'e':
|
||||
return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar()));
|
||||
return new EnumAttributeProxy(readTypeToProxy(nextChar()), poolReader.getName(nextChar()));
|
||||
case 'c':
|
||||
return new ClassAttributeProxy(readTypeOrClassSymbol(nextChar()));
|
||||
case '[': {
|
||||
@ -2401,8 +2132,8 @@ public class ClassReader {
|
||||
*/
|
||||
VarSymbol readField() {
|
||||
long flags = adjustFieldFlags(nextChar());
|
||||
Name name = readName(nextChar());
|
||||
Type type = readType(nextChar());
|
||||
Name name = poolReader.getName(nextChar());
|
||||
Type type = poolReader.getType(nextChar());
|
||||
VarSymbol v = new VarSymbol(flags, name, type, currentOwner);
|
||||
readMemberAttrs(v);
|
||||
return v;
|
||||
@ -2412,8 +2143,8 @@ public class ClassReader {
|
||||
*/
|
||||
MethodSymbol readMethod() {
|
||||
long flags = adjustMethodFlags(nextChar());
|
||||
Name name = readName(nextChar());
|
||||
Type type = readType(nextChar());
|
||||
Name name = poolReader.getName(nextChar());
|
||||
Type type = poolReader.getType(nextChar());
|
||||
if (currentOwner.isInterface() &&
|
||||
(flags & ABSTRACT) == 0 && !name.equals(names.clinit)) {
|
||||
if (majorVersion > Version.V52.major ||
|
||||
@ -2592,7 +2323,7 @@ public class ClassReader {
|
||||
Name argName;
|
||||
if (parameterNameIndices != null && index < parameterNameIndices.length
|
||||
&& parameterNameIndices[index] != 0) {
|
||||
argName = readName(parameterNameIndices[index]);
|
||||
argName = optPoolEntry(parameterNameIndices[index], poolReader::getName, names.empty);
|
||||
flags |= NAME_FILLED;
|
||||
} else {
|
||||
String prefix = "arg";
|
||||
@ -2681,7 +2412,7 @@ public class ClassReader {
|
||||
if (c.owner.kind == PCK || c.owner.kind == ERR) c.flags_field = flags;
|
||||
// read own class name and check that it matches
|
||||
currentModule = c.packge().modle;
|
||||
ClassSymbol self = readClassSymbol(nextChar());
|
||||
ClassSymbol self = poolReader.getClass(nextChar());
|
||||
if (c != self) {
|
||||
throw badClassFile("class.file.wrong.class",
|
||||
self.flatname);
|
||||
@ -2710,11 +2441,6 @@ public class ClassReader {
|
||||
for (int i = 0; i < methodCount; i++) skipMember();
|
||||
readClassAttrs(c);
|
||||
|
||||
if (readAllOfClassFile) {
|
||||
for (int i = 1; i < poolObj.length; i++) readPool(i);
|
||||
c.pool = new Pool(poolObj.length, poolObj, types);
|
||||
}
|
||||
|
||||
// reset and read rest of classinfo
|
||||
bp = startbp;
|
||||
int n = nextChar();
|
||||
@ -2722,13 +2448,12 @@ public class ClassReader {
|
||||
throw badClassFile("module.info.invalid.super.class");
|
||||
}
|
||||
if (ct.supertype_field == null)
|
||||
ct.supertype_field = (n == 0)
|
||||
? Type.noType
|
||||
: readClassSymbol(n).erasure(types);
|
||||
ct.supertype_field =
|
||||
optPoolEntry(n, idx -> poolReader.getClass(idx).erasure(types), Type.noType);
|
||||
n = nextChar();
|
||||
List<Type> is = List.nil();
|
||||
for (int i = 0; i < n; i++) {
|
||||
Type _inter = readClassSymbol(nextChar()).erasure(types);
|
||||
Type _inter = poolReader.getClass(nextChar()).erasure(types);
|
||||
is = is.prepend(_inter);
|
||||
}
|
||||
if (ct.interfaces_field == null)
|
||||
@ -2749,8 +2474,10 @@ public class ClassReader {
|
||||
int n = nextChar();
|
||||
for (int i = 0; i < n; i++) {
|
||||
nextChar(); // skip inner class symbol
|
||||
ClassSymbol outer = readClassSymbol(nextChar());
|
||||
Name name = readName(nextChar());
|
||||
int outerIdx = nextChar();
|
||||
int nameIdx = nextChar();
|
||||
ClassSymbol outer = optPoolEntry(outerIdx, poolReader::getClass, null);
|
||||
Name name = optPoolEntry(nameIdx, poolReader::getName, names.empty);
|
||||
if (name == null) name = names.empty;
|
||||
long flags = adjustClassFlags(nextChar());
|
||||
if (outer != null) { // we have a member class
|
||||
@ -2804,7 +2531,8 @@ public class ClassReader {
|
||||
}
|
||||
}
|
||||
|
||||
indexPool();
|
||||
poolReader = new PoolReader(this, names, syms);
|
||||
bp = poolReader.readPool(buf, bp);
|
||||
if (signatureBuffer.length < bp) {
|
||||
int ns = Integer.highestOneBit(bp) << 1;
|
||||
signatureBuffer = new byte[ns];
|
||||
@ -2821,7 +2549,8 @@ public class ClassReader {
|
||||
repeatable = null;
|
||||
try {
|
||||
bp = 0;
|
||||
buf = readInputStream(buf, c.classfile.openInputStream());
|
||||
buf.reset();
|
||||
buf.appendStream(c.classfile.openInputStream());
|
||||
readClassBuffer(c);
|
||||
if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) {
|
||||
List<Type> missing = missingTypeVariables;
|
||||
@ -2875,43 +2604,6 @@ public class ClassReader {
|
||||
filling = false;
|
||||
}
|
||||
}
|
||||
// where
|
||||
private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
|
||||
try {
|
||||
buf = ensureCapacity(buf, s.available());
|
||||
int r = s.read(buf);
|
||||
int bp = 0;
|
||||
while (r != -1) {
|
||||
bp += r;
|
||||
buf = ensureCapacity(buf, bp);
|
||||
r = s.read(buf, bp, buf.length - bp);
|
||||
}
|
||||
return buf;
|
||||
} finally {
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException e) {
|
||||
/* Ignore any errors, as this stream may have already
|
||||
* thrown a related exception which is the one that
|
||||
* should be reported.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ensureCapacity will increase the buffer as needed, taking note that
|
||||
* the new buffer will always be greater than the needed and never
|
||||
* exactly equal to the needed size or bp. If equal then the read (above)
|
||||
* will infinitely loop as buf.length - bp == 0.
|
||||
*/
|
||||
private static byte[] ensureCapacity(byte[] buf, int needed) {
|
||||
if (buf.length <= needed) {
|
||||
byte[] old = buf;
|
||||
buf = new byte[Integer.highestOneBit(needed) << 1];
|
||||
System.arraycopy(old, 0, buf, 0, old.length);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/** We can only read a single class file at a time; this
|
||||
* flag keeps track of when we are currently reading a class
|
||||
@ -3098,11 +2790,11 @@ public class ClassReader {
|
||||
|
||||
private class ProxyType extends Type {
|
||||
|
||||
private final byte[] content;
|
||||
private final Name name;
|
||||
|
||||
public ProxyType(byte[] content) {
|
||||
public ProxyType(int index) {
|
||||
super(syms.noSymbol, TypeMetadata.EMPTY);
|
||||
this.content = content;
|
||||
this.name = poolReader.getName(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -3116,7 +2808,7 @@ public class ClassReader {
|
||||
}
|
||||
|
||||
public Type resolve() {
|
||||
return sigToType(content, 0, content.length);
|
||||
return name.map(ClassReader.this::sigToType);
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
|
@ -29,9 +29,7 @@ import java.io.*;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.FileObject;
|
||||
@ -44,13 +42,10 @@ import com.sun.tools.javac.code.Directive.*;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.Type.*;
|
||||
import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
|
||||
import com.sun.tools.javac.code.Types.UniqueType;
|
||||
import com.sun.tools.javac.comp.Check;
|
||||
import com.sun.tools.javac.file.PathFileObject;
|
||||
import com.sun.tools.javac.jvm.Pool.DynamicMethod;
|
||||
import com.sun.tools.javac.jvm.Pool.Method;
|
||||
import com.sun.tools.javac.jvm.Pool.MethodHandle;
|
||||
import com.sun.tools.javac.jvm.Pool.Variable;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Errors;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
|
||||
import com.sun.tools.javac.util.*;
|
||||
@ -121,7 +116,7 @@ public class ClassWriter extends ClassFile {
|
||||
* Sizes are increased when buffers get full.
|
||||
*/
|
||||
static final int DATA_BUF_SIZE = 0x0fff0;
|
||||
static final int POOL_BUF_SIZE = 0x1fff0;
|
||||
static final int CLASS_BUF_SIZE = 0x1fff0;
|
||||
|
||||
/** An output buffer for member info.
|
||||
*/
|
||||
@ -129,25 +124,11 @@ public class ClassWriter extends ClassFile {
|
||||
|
||||
/** An output buffer for the constant pool.
|
||||
*/
|
||||
ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
|
||||
ByteBuffer poolbuf = new ByteBuffer(CLASS_BUF_SIZE);
|
||||
|
||||
/** The constant pool.
|
||||
/** The constant pool writer.
|
||||
*/
|
||||
Pool pool;
|
||||
|
||||
/** The inner classes to be written, as a set.
|
||||
*/
|
||||
Set<ClassSymbol> innerClasses;
|
||||
|
||||
/** The inner classes to be written, as a queue where
|
||||
* enclosing classes come first.
|
||||
*/
|
||||
ListBuffer<ClassSymbol> innerClassesQueue;
|
||||
|
||||
/** The bootstrap methods to be written in the corresponding class attribute
|
||||
* (one for each invokedynamic)
|
||||
*/
|
||||
Map<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> bootstrapMethods;
|
||||
final PoolWriter poolWriter;
|
||||
|
||||
/** The log to use for verbose output.
|
||||
*/
|
||||
@ -159,9 +140,6 @@ public class ClassWriter extends ClassFile {
|
||||
/** Access to files. */
|
||||
private final JavaFileManager fileManager;
|
||||
|
||||
/** Sole signature generator */
|
||||
private final CWSignatureGenerator signatureGen;
|
||||
|
||||
/** The tags and constants used in compressed stackmap. */
|
||||
static final int SAME_FRAME_SIZE = 64;
|
||||
static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
|
||||
@ -191,7 +169,7 @@ public class ClassWriter extends ClassFile {
|
||||
types = Types.instance(context);
|
||||
check = Check.instance(context);
|
||||
fileManager = context.get(JavaFileManager.class);
|
||||
signatureGen = new CWSignatureGenerator(types);
|
||||
poolWriter = Gen.instance(context).poolWriter;
|
||||
|
||||
verbose = options.isSet(VERBOSE);
|
||||
genCrt = options.isSet(XJCOV);
|
||||
@ -272,108 +250,17 @@ public class ClassWriter extends ClassFile {
|
||||
buf.elems[adr+3] = (byte)((x ) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature Generation
|
||||
*/
|
||||
private class CWSignatureGenerator extends Types.SignatureGenerator {
|
||||
|
||||
/**
|
||||
* An output buffer for type signatures.
|
||||
*/
|
||||
ByteBuffer sigbuf = new ByteBuffer();
|
||||
|
||||
CWSignatureGenerator(Types types) {
|
||||
super(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assemble signature of given type in string buffer.
|
||||
* Check for uninitialized types before calling the general case.
|
||||
*/
|
||||
@Override
|
||||
public void assembleSig(Type type) {
|
||||
switch (type.getTag()) {
|
||||
case UNINITIALIZED_THIS:
|
||||
case UNINITIALIZED_OBJECT:
|
||||
// we don't yet have a spec for uninitialized types in the
|
||||
// local variable table
|
||||
assembleSig(types.erasure(((UninitializedType)type).qtype));
|
||||
break;
|
||||
default:
|
||||
super.assembleSig(type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(char ch) {
|
||||
sigbuf.appendByte(ch);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(byte[] ba) {
|
||||
sigbuf.appendBytes(ba);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(Name name) {
|
||||
sigbuf.appendName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void classReference(ClassSymbol c) {
|
||||
enterInner(c);
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
sigbuf.reset();
|
||||
}
|
||||
|
||||
private Name toName() {
|
||||
return sigbuf.toName(names);
|
||||
}
|
||||
|
||||
private boolean isEmpty() {
|
||||
return sigbuf.length == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return signature of given type
|
||||
*/
|
||||
Name typeSig(Type type) {
|
||||
Assert.check(signatureGen.isEmpty());
|
||||
//- System.out.println(" ? " + type);
|
||||
signatureGen.assembleSig(type);
|
||||
Name n = signatureGen.toName();
|
||||
signatureGen.reset();
|
||||
//- System.out.println(" " + n);
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Given a type t, return the extended class name of its erasure in
|
||||
* external representation.
|
||||
*/
|
||||
public Name xClassName(Type t) {
|
||||
if (t.hasTag(CLASS)) {
|
||||
return names.fromUtf(externalize(t.tsym.flatName()));
|
||||
} else if (t.hasTag(ARRAY)) {
|
||||
return typeSig(types.erasure(t));
|
||||
} else {
|
||||
throw new AssertionError("xClassName expects class or array type, got " + t);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Writing the Constant Pool
|
||||
******************************************************************/
|
||||
|
||||
/** Thrown when the constant pool is over full.
|
||||
*/
|
||||
public static class PoolOverflow extends Exception {
|
||||
public static class PoolOverflow extends RuntimeException {
|
||||
private static final long serialVersionUID = 0;
|
||||
public PoolOverflow() {}
|
||||
}
|
||||
public static class StringOverflow extends Exception {
|
||||
public static class StringOverflow extends RuntimeException {
|
||||
private static final long serialVersionUID = 0;
|
||||
public final String value;
|
||||
public StringOverflow(String s) {
|
||||
@ -381,137 +268,6 @@ public class ClassWriter extends ClassFile {
|
||||
}
|
||||
}
|
||||
|
||||
/** Write constant pool to pool buffer.
|
||||
* Note: during writing, constant pool
|
||||
* might grow since some parts of constants still need to be entered.
|
||||
*/
|
||||
void writePool(Pool pool) throws PoolOverflow, StringOverflow {
|
||||
int poolCountIdx = poolbuf.length;
|
||||
poolbuf.appendChar(0);
|
||||
int i = 1;
|
||||
while (i < pool.pp) {
|
||||
Object value = pool.pool[i];
|
||||
Assert.checkNonNull(value);
|
||||
if (value instanceof Method || value instanceof Variable)
|
||||
value = ((DelegatedSymbol)value).getUnderlyingSymbol();
|
||||
|
||||
if (value instanceof MethodSymbol) {
|
||||
MethodSymbol m = (MethodSymbol)value;
|
||||
if (!m.isDynamic()) {
|
||||
poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0
|
||||
? CONSTANT_InterfaceMethodref
|
||||
: CONSTANT_Methodref);
|
||||
poolbuf.appendChar(pool.put(m.owner));
|
||||
poolbuf.appendChar(pool.put(nameType(m)));
|
||||
} else {
|
||||
//invokedynamic
|
||||
DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m;
|
||||
MethodHandle handle = new MethodHandle(dynSym.bsmKind, dynSym.bsm, types);
|
||||
DynamicMethod.BootstrapMethodsKey key = new DynamicMethod.BootstrapMethodsKey(dynSym, types);
|
||||
|
||||
// Figure out the index for existing BSM; create a new BSM if no key
|
||||
DynamicMethod.BootstrapMethodsValue val = bootstrapMethods.get(key);
|
||||
if (val == null) {
|
||||
int index = bootstrapMethods.size();
|
||||
val = new DynamicMethod.BootstrapMethodsValue(handle, index);
|
||||
bootstrapMethods.put(key, val);
|
||||
}
|
||||
|
||||
//init cp entries
|
||||
pool.put(names.BootstrapMethods);
|
||||
pool.put(handle);
|
||||
for (Object staticArg : dynSym.staticArgs) {
|
||||
pool.put(staticArg);
|
||||
}
|
||||
poolbuf.appendByte(CONSTANT_InvokeDynamic);
|
||||
poolbuf.appendChar(val.index);
|
||||
poolbuf.appendChar(pool.put(nameType(dynSym)));
|
||||
}
|
||||
} else if (value instanceof VarSymbol) {
|
||||
VarSymbol v = (VarSymbol)value;
|
||||
poolbuf.appendByte(CONSTANT_Fieldref);
|
||||
poolbuf.appendChar(pool.put(v.owner));
|
||||
poolbuf.appendChar(pool.put(nameType(v)));
|
||||
} else if (value instanceof Name) {
|
||||
poolbuf.appendByte(CONSTANT_Utf8);
|
||||
byte[] bs = ((Name)value).toUtf();
|
||||
poolbuf.appendChar(bs.length);
|
||||
poolbuf.appendBytes(bs, 0, bs.length);
|
||||
if (bs.length > Pool.MAX_STRING_LENGTH)
|
||||
throw new StringOverflow(value.toString());
|
||||
} else if (value instanceof ClassSymbol) {
|
||||
ClassSymbol c = (ClassSymbol)value;
|
||||
if (c.owner.kind == TYP) pool.put(c.owner);
|
||||
poolbuf.appendByte(CONSTANT_Class);
|
||||
if (c.type.hasTag(ARRAY)) {
|
||||
poolbuf.appendChar(pool.put(typeSig(c.type)));
|
||||
} else {
|
||||
poolbuf.appendChar(pool.put(names.fromUtf(externalize(c.flatname))));
|
||||
enterInner(c);
|
||||
}
|
||||
} else if (value instanceof NameAndType) {
|
||||
NameAndType nt = (NameAndType)value;
|
||||
poolbuf.appendByte(CONSTANT_NameandType);
|
||||
poolbuf.appendChar(pool.put(nt.name));
|
||||
poolbuf.appendChar(pool.put(typeSig(nt.uniqueType.type)));
|
||||
} else if (value instanceof Integer) {
|
||||
poolbuf.appendByte(CONSTANT_Integer);
|
||||
poolbuf.appendInt(((Integer)value).intValue());
|
||||
} else if (value instanceof Long) {
|
||||
poolbuf.appendByte(CONSTANT_Long);
|
||||
poolbuf.appendLong(((Long)value).longValue());
|
||||
i++;
|
||||
} else if (value instanceof Float) {
|
||||
poolbuf.appendByte(CONSTANT_Float);
|
||||
poolbuf.appendFloat(((Float)value).floatValue());
|
||||
} else if (value instanceof Double) {
|
||||
poolbuf.appendByte(CONSTANT_Double);
|
||||
poolbuf.appendDouble(((Double)value).doubleValue());
|
||||
i++;
|
||||
} else if (value instanceof String) {
|
||||
poolbuf.appendByte(CONSTANT_String);
|
||||
poolbuf.appendChar(pool.put(names.fromString((String)value)));
|
||||
} else if (value instanceof UniqueType) {
|
||||
Type type = ((UniqueType)value).type;
|
||||
if (type.hasTag(METHOD)) {
|
||||
poolbuf.appendByte(CONSTANT_MethodType);
|
||||
poolbuf.appendChar(pool.put(typeSig((MethodType)type)));
|
||||
} else {
|
||||
Assert.check(type.hasTag(ARRAY));
|
||||
poolbuf.appendByte(CONSTANT_Class);
|
||||
poolbuf.appendChar(pool.put(xClassName(type)));
|
||||
}
|
||||
} else if (value instanceof MethodHandle) {
|
||||
MethodHandle ref = (MethodHandle)value;
|
||||
poolbuf.appendByte(CONSTANT_MethodHandle);
|
||||
poolbuf.appendByte(ref.refKind);
|
||||
poolbuf.appendChar(pool.put(ref.refSym));
|
||||
} else if (value instanceof ModuleSymbol) {
|
||||
ModuleSymbol m = (ModuleSymbol)value;
|
||||
poolbuf.appendByte(CONSTANT_Module);
|
||||
poolbuf.appendChar(pool.put(m.name));
|
||||
} else if (value instanceof PackageSymbol) {
|
||||
PackageSymbol m = (PackageSymbol)value;
|
||||
poolbuf.appendByte(CONSTANT_Package);
|
||||
poolbuf.appendChar(pool.put(names.fromUtf(externalize(m.fullname))));
|
||||
} else {
|
||||
Assert.error("writePool " + value);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (pool.pp > Pool.MAX_ENTRIES)
|
||||
throw new PoolOverflow();
|
||||
putChar(poolbuf, poolCountIdx, pool.pp);
|
||||
}
|
||||
|
||||
/** Given a symbol, return its name-and-type.
|
||||
*/
|
||||
NameAndType nameType(Symbol sym) {
|
||||
return new NameAndType(sym.name, sym.externalType(types), types);
|
||||
// the NameAndType is generated from a symbol reference, and the
|
||||
// adjustment of adding an additional this$n parameter needs to be made.
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Writing Attributes
|
||||
******************************************************************/
|
||||
@ -520,7 +276,8 @@ public class ClassWriter extends ClassFile {
|
||||
* position past attribute length index.
|
||||
*/
|
||||
int writeAttr(Name attrName) {
|
||||
databuf.appendChar(pool.put(attrName));
|
||||
int index = poolWriter.putName(attrName);
|
||||
databuf.appendChar(index);
|
||||
databuf.appendInt(0);
|
||||
return databuf.length;
|
||||
}
|
||||
@ -567,8 +324,8 @@ public class ClassWriter extends ClassFile {
|
||||
|| c.owner.kind != MTH) // or member init
|
||||
? null
|
||||
: (MethodSymbol)c.owner;
|
||||
databuf.appendChar(pool.put(enclClass));
|
||||
databuf.appendChar(enclMethod == null ? 0 : pool.put(nameType(c.owner)));
|
||||
databuf.appendChar(poolWriter.putClass(enclClass));
|
||||
databuf.appendChar(enclMethod == null ? 0 : poolWriter.putNameAndType(c.owner));
|
||||
endAttr(alenIdx);
|
||||
return 1;
|
||||
}
|
||||
@ -594,11 +351,11 @@ public class ClassWriter extends ClassFile {
|
||||
if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC &&
|
||||
(flags & ANONCONSTR) == 0 &&
|
||||
(!types.isSameType(sym.type, sym.erasure(types)) ||
|
||||
signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
|
||||
poolWriter.signatureGen.hasTypeVar(sym.type.getThrownTypes()))) {
|
||||
// note that a local class with captured variables
|
||||
// will get a signature attribute
|
||||
int alenIdx = writeAttr(names.Signature);
|
||||
databuf.appendChar(pool.put(typeSig(sym.type)));
|
||||
databuf.appendChar(poolWriter.putSignature(sym));
|
||||
endAttr(alenIdx);
|
||||
acount++;
|
||||
}
|
||||
@ -621,7 +378,7 @@ public class ClassWriter extends ClassFile {
|
||||
final int flags =
|
||||
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
|
||||
((int) m.flags() & SYNTHETIC);
|
||||
databuf.appendChar(pool.put(s.name));
|
||||
databuf.appendChar(poolWriter.putName(s.name));
|
||||
databuf.appendChar(flags);
|
||||
}
|
||||
// Now write the real parameters
|
||||
@ -629,7 +386,7 @@ public class ClassWriter extends ClassFile {
|
||||
final int flags =
|
||||
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
|
||||
((int) m.flags() & SYNTHETIC);
|
||||
databuf.appendChar(pool.put(s.name));
|
||||
databuf.appendChar(poolWriter.putName(s.name));
|
||||
databuf.appendChar(flags);
|
||||
}
|
||||
// Now write the captured locals
|
||||
@ -637,7 +394,7 @@ public class ClassWriter extends ClassFile {
|
||||
final int flags =
|
||||
((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) |
|
||||
((int) m.flags() & SYNTHETIC);
|
||||
databuf.appendChar(pool.put(s.name));
|
||||
databuf.appendChar(poolWriter.putName(s.name));
|
||||
databuf.appendChar(flags);
|
||||
}
|
||||
endAttr(attrIndex);
|
||||
@ -803,50 +560,51 @@ public class ClassWriter extends ClassFile {
|
||||
*/
|
||||
class AttributeWriter implements Attribute.Visitor {
|
||||
public void visitConstant(Attribute.Constant _value) {
|
||||
Object value = _value.value;
|
||||
switch (_value.type.getTag()) {
|
||||
case BYTE:
|
||||
databuf.appendByte('B');
|
||||
break;
|
||||
case CHAR:
|
||||
databuf.appendByte('C');
|
||||
break;
|
||||
case SHORT:
|
||||
databuf.appendByte('S');
|
||||
break;
|
||||
case INT:
|
||||
databuf.appendByte('I');
|
||||
break;
|
||||
case LONG:
|
||||
databuf.appendByte('J');
|
||||
break;
|
||||
case FLOAT:
|
||||
databuf.appendByte('F');
|
||||
break;
|
||||
case DOUBLE:
|
||||
databuf.appendByte('D');
|
||||
break;
|
||||
case BOOLEAN:
|
||||
databuf.appendByte('Z');
|
||||
break;
|
||||
case CLASS:
|
||||
Assert.check(value instanceof String);
|
||||
if (_value.type.getTag() == CLASS) {
|
||||
Assert.check(_value.value instanceof String);
|
||||
String s = (String)_value.value;
|
||||
databuf.appendByte('s');
|
||||
value = names.fromString(value.toString()); // CONSTANT_Utf8
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError(_value.type);
|
||||
databuf.appendChar(poolWriter.putName(names.fromString(s)));
|
||||
} else {
|
||||
switch (_value.type.getTag()) {
|
||||
case BYTE:
|
||||
databuf.appendByte('B');
|
||||
break;
|
||||
case CHAR:
|
||||
databuf.appendByte('C');
|
||||
break;
|
||||
case SHORT:
|
||||
databuf.appendByte('S');
|
||||
break;
|
||||
case INT:
|
||||
databuf.appendByte('I');
|
||||
break;
|
||||
case LONG:
|
||||
databuf.appendByte('J');
|
||||
break;
|
||||
case FLOAT:
|
||||
databuf.appendByte('F');
|
||||
break;
|
||||
case DOUBLE:
|
||||
databuf.appendByte('D');
|
||||
break;
|
||||
case BOOLEAN:
|
||||
databuf.appendByte('Z');
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError(_value.type);
|
||||
}
|
||||
databuf.appendChar(poolWriter.putConstant(_value.value));
|
||||
}
|
||||
databuf.appendChar(pool.put(value));
|
||||
}
|
||||
public void visitEnum(Attribute.Enum e) {
|
||||
databuf.appendByte('e');
|
||||
databuf.appendChar(pool.put(typeSig(e.value.type)));
|
||||
databuf.appendChar(pool.put(e.value.name));
|
||||
databuf.appendChar(poolWriter.putDescriptor(e.value.type));
|
||||
databuf.appendChar(poolWriter.putName(e.value.name));
|
||||
}
|
||||
public void visitClass(Attribute.Class clazz) {
|
||||
databuf.appendByte('c');
|
||||
databuf.appendChar(pool.put(typeSig(types.erasure(clazz.classType))));
|
||||
databuf.appendChar(poolWriter.putDescriptor(clazz.classType));
|
||||
}
|
||||
public void visitCompound(Attribute.Compound compound) {
|
||||
databuf.appendByte('@');
|
||||
@ -867,10 +625,10 @@ public class ClassWriter extends ClassFile {
|
||||
|
||||
/** Write a compound attribute excluding the '@' marker. */
|
||||
void writeCompoundAttribute(Attribute.Compound c) {
|
||||
databuf.appendChar(pool.put(typeSig(c.type)));
|
||||
databuf.appendChar(poolWriter.putDescriptor(c.type));
|
||||
databuf.appendChar(c.values.length());
|
||||
for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) {
|
||||
databuf.appendChar(pool.put(p.fst.name));
|
||||
databuf.appendChar(poolWriter.putName(p.fst.name));
|
||||
p.snd.accept(awriter);
|
||||
}
|
||||
}
|
||||
@ -974,9 +732,9 @@ public class ClassWriter extends ClassFile {
|
||||
|
||||
int alenIdx = writeAttr(names.Module);
|
||||
|
||||
databuf.appendChar(pool.put(m));
|
||||
databuf.appendChar(poolWriter.putModule(m));
|
||||
databuf.appendChar(ModuleFlags.value(m.flags)); // module_flags
|
||||
databuf.appendChar(m.version != null ? pool.put(m.version) : 0);
|
||||
databuf.appendChar(m.version != null ? poolWriter.putName(m.version) : 0);
|
||||
|
||||
ListBuffer<RequiresDirective> requires = new ListBuffer<>();
|
||||
for (RequiresDirective r: m.requires) {
|
||||
@ -985,22 +743,22 @@ public class ClassWriter extends ClassFile {
|
||||
}
|
||||
databuf.appendChar(requires.size());
|
||||
for (RequiresDirective r: requires) {
|
||||
databuf.appendChar(pool.put(r.module));
|
||||
databuf.appendChar(poolWriter.putModule(r.module));
|
||||
databuf.appendChar(RequiresFlag.value(r.flags));
|
||||
databuf.appendChar(r.module.version != null ? pool.put(r.module.version) : 0);
|
||||
databuf.appendChar(r.module.version != null ? poolWriter.putName(r.module.version) : 0);
|
||||
}
|
||||
|
||||
List<ExportsDirective> exports = m.exports;
|
||||
databuf.appendChar(exports.size());
|
||||
for (ExportsDirective e: exports) {
|
||||
databuf.appendChar(pool.put(e.packge));
|
||||
databuf.appendChar(poolWriter.putPackage(e.packge));
|
||||
databuf.appendChar(ExportsFlag.value(e.flags));
|
||||
if (e.modules == null) {
|
||||
databuf.appendChar(0);
|
||||
} else {
|
||||
databuf.appendChar(e.modules.size());
|
||||
for (ModuleSymbol msym: e.modules) {
|
||||
databuf.appendChar(pool.put(msym));
|
||||
databuf.appendChar(poolWriter.putModule(msym));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1008,14 +766,14 @@ public class ClassWriter extends ClassFile {
|
||||
List<OpensDirective> opens = m.opens;
|
||||
databuf.appendChar(opens.size());
|
||||
for (OpensDirective o: opens) {
|
||||
databuf.appendChar(pool.put(o.packge));
|
||||
databuf.appendChar(poolWriter.putPackage(o.packge));
|
||||
databuf.appendChar(OpensFlag.value(o.flags));
|
||||
if (o.modules == null) {
|
||||
databuf.appendChar(0);
|
||||
} else {
|
||||
databuf.appendChar(o.modules.size());
|
||||
for (ModuleSymbol msym: o.modules) {
|
||||
databuf.appendChar(pool.put(msym));
|
||||
databuf.appendChar(poolWriter.putModule(msym));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1023,7 +781,7 @@ public class ClassWriter extends ClassFile {
|
||||
List<UsesDirective> uses = m.uses;
|
||||
databuf.appendChar(uses.size());
|
||||
for (UsesDirective s: uses) {
|
||||
databuf.appendChar(pool.put(s.service));
|
||||
databuf.appendChar(poolWriter.putClass(s.service));
|
||||
}
|
||||
|
||||
// temporary fix to merge repeated provides clause for same service;
|
||||
@ -1035,9 +793,9 @@ public class ClassWriter extends ClassFile {
|
||||
}
|
||||
databuf.appendChar(mergedProvides.size());
|
||||
mergedProvides.forEach((srvc, impls) -> {
|
||||
databuf.appendChar(pool.put(srvc));
|
||||
databuf.appendChar(poolWriter.putClass(srvc));
|
||||
databuf.appendChar(impls.size());
|
||||
impls.forEach(impl -> databuf.appendChar(pool.put(impl)));
|
||||
impls.forEach(impl -> databuf.appendChar(poolWriter.putClass(impl)));
|
||||
});
|
||||
|
||||
endAttr(alenIdx);
|
||||
@ -1048,46 +806,12 @@ public class ClassWriter extends ClassFile {
|
||||
* Writing Objects
|
||||
**********************************************************************/
|
||||
|
||||
/** Enter an inner class into the `innerClasses' set/queue.
|
||||
*/
|
||||
void enterInner(ClassSymbol c) {
|
||||
if (c.type.isCompound()) {
|
||||
throw new AssertionError("Unexpected intersection type: " + c.type);
|
||||
}
|
||||
try {
|
||||
c.complete();
|
||||
} catch (CompletionFailure ex) {
|
||||
System.err.println("error: " + c + ": " + ex.getMessage());
|
||||
throw ex;
|
||||
}
|
||||
if (!c.type.hasTag(CLASS)) return; // arrays
|
||||
if (pool != null && // pool might be null if called from xClassName
|
||||
c.owner.enclClass() != null &&
|
||||
(innerClasses == null || !innerClasses.contains(c))) {
|
||||
// log.errWriter.println("enter inner " + c);//DEBUG
|
||||
enterInner(c.owner.enclClass());
|
||||
pool.put(c);
|
||||
if (c.name != names.empty)
|
||||
pool.put(c.name);
|
||||
if (innerClasses == null) {
|
||||
innerClasses = new HashSet<>();
|
||||
innerClassesQueue = new ListBuffer<>();
|
||||
pool.put(names.InnerClasses);
|
||||
}
|
||||
innerClasses.add(c);
|
||||
innerClassesQueue.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
/** Write "inner classes" attribute.
|
||||
*/
|
||||
void writeInnerClasses() {
|
||||
int alenIdx = writeAttr(names.InnerClasses);
|
||||
databuf.appendChar(innerClassesQueue.length());
|
||||
for (List<ClassSymbol> l = innerClassesQueue.toList();
|
||||
l.nonEmpty();
|
||||
l = l.tail) {
|
||||
ClassSymbol inner = l.head;
|
||||
databuf.appendChar(poolWriter.innerClasses.size());
|
||||
for (ClassSymbol inner : poolWriter.innerClasses) {
|
||||
inner.markAbstractIfNeeded(types);
|
||||
char flags = (char) adjustFlags(inner.flags_field);
|
||||
if ((flags & INTERFACE) != 0) flags |= ABSTRACT; // Interfaces are always ABSTRACT
|
||||
@ -1097,11 +821,11 @@ public class ClassWriter extends ClassFile {
|
||||
pw.println("INNERCLASS " + inner.name);
|
||||
pw.println("---" + flagNames(flags));
|
||||
}
|
||||
databuf.appendChar(pool.get(inner));
|
||||
databuf.appendChar(poolWriter.putClass(inner));
|
||||
databuf.appendChar(
|
||||
inner.owner.kind == TYP && !inner.name.isEmpty() ? pool.get(inner.owner) : 0);
|
||||
inner.owner.kind == TYP && !inner.name.isEmpty() ? poolWriter.putClass((ClassSymbol)inner.owner) : 0);
|
||||
databuf.appendChar(
|
||||
!inner.name.isEmpty() ? pool.get(inner.name) : 0);
|
||||
!inner.name.isEmpty() ? poolWriter.putName(inner.name) : 0);
|
||||
databuf.appendChar(flags);
|
||||
}
|
||||
endAttr(alenIdx);
|
||||
@ -1111,14 +835,14 @@ public class ClassWriter extends ClassFile {
|
||||
* Write NestMembers attribute (if needed)
|
||||
*/
|
||||
int writeNestMembersIfNeeded(ClassSymbol csym) {
|
||||
ListBuffer<Symbol> nested = new ListBuffer<>();
|
||||
ListBuffer<ClassSymbol> nested = new ListBuffer<>();
|
||||
listNested(csym, nested);
|
||||
Set<Symbol> nestedUnique = new LinkedHashSet<>(nested);
|
||||
Set<ClassSymbol> nestedUnique = new LinkedHashSet<>(nested);
|
||||
if (csym.owner.kind == PCK && !nestedUnique.isEmpty()) {
|
||||
int alenIdx = writeAttr(names.NestMembers);
|
||||
databuf.appendChar(nestedUnique.size());
|
||||
for (Symbol s : nestedUnique) {
|
||||
databuf.appendChar(pool.put(s));
|
||||
for (ClassSymbol s : nestedUnique) {
|
||||
databuf.appendChar(poolWriter.putClass(s));
|
||||
}
|
||||
endAttr(alenIdx);
|
||||
return 1;
|
||||
@ -1132,14 +856,14 @@ public class ClassWriter extends ClassFile {
|
||||
int writeNestHostIfNeeded(ClassSymbol csym) {
|
||||
if (csym.owner.kind != PCK) {
|
||||
int alenIdx = writeAttr(names.NestHost);
|
||||
databuf.appendChar(pool.put(csym.outermostClass()));
|
||||
databuf.appendChar(poolWriter.putClass(csym.outermostClass()));
|
||||
endAttr(alenIdx);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void listNested(Symbol sym, ListBuffer<Symbol> seen) {
|
||||
private void listNested(Symbol sym, ListBuffer<ClassSymbol> seen) {
|
||||
if (sym.kind != TYP) return;
|
||||
ClassSymbol csym = (ClassSymbol)sym;
|
||||
if (csym.owner.kind != PCK) {
|
||||
@ -1161,17 +885,16 @@ public class ClassWriter extends ClassFile {
|
||||
*/
|
||||
void writeBootstrapMethods() {
|
||||
int alenIdx = writeAttr(names.BootstrapMethods);
|
||||
databuf.appendChar(bootstrapMethods.size());
|
||||
for (Map.Entry<DynamicMethod.BootstrapMethodsKey, DynamicMethod.BootstrapMethodsValue> entry : bootstrapMethods.entrySet()) {
|
||||
DynamicMethod.BootstrapMethodsKey bsmKey = entry.getKey();
|
||||
databuf.appendChar(poolWriter.bootstrapMethods.size());
|
||||
for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) {
|
||||
//write BSM handle
|
||||
databuf.appendChar(pool.get(entry.getValue().mh));
|
||||
Object[] uniqueArgs = bsmKey.getUniqueArgs();
|
||||
databuf.appendChar(poolWriter.putConstant(bsmKey.bsm));
|
||||
LoadableConstant[] uniqueArgs = bsmKey.staticArgs;
|
||||
//write static args length
|
||||
databuf.appendChar(uniqueArgs.length);
|
||||
//write static args array
|
||||
for (Object o : uniqueArgs) {
|
||||
databuf.appendChar(pool.get(o));
|
||||
for (LoadableConstant arg : uniqueArgs) {
|
||||
databuf.appendChar(poolWriter.putConstant(arg));
|
||||
}
|
||||
}
|
||||
endAttr(alenIdx);
|
||||
@ -1187,13 +910,13 @@ public class ClassWriter extends ClassFile {
|
||||
pw.println("FIELD " + v.name);
|
||||
pw.println("---" + flagNames(v.flags()));
|
||||
}
|
||||
databuf.appendChar(pool.put(v.name));
|
||||
databuf.appendChar(pool.put(typeSig(v.erasure(types))));
|
||||
databuf.appendChar(poolWriter.putName(v.name));
|
||||
databuf.appendChar(poolWriter.putDescriptor(v));
|
||||
int acountIdx = beginAttrs();
|
||||
int acount = 0;
|
||||
if (v.getConstValue() != null) {
|
||||
int alenIdx = writeAttr(names.ConstantValue);
|
||||
databuf.appendChar(pool.put(v.getConstValue()));
|
||||
databuf.appendChar(poolWriter.putConstant(v.getConstValue()));
|
||||
endAttr(alenIdx);
|
||||
acount++;
|
||||
}
|
||||
@ -1211,8 +934,8 @@ public class ClassWriter extends ClassFile {
|
||||
pw.println("METHOD " + m.name);
|
||||
pw.println("---" + flagNames(m.flags()));
|
||||
}
|
||||
databuf.appendChar(pool.put(m.name));
|
||||
databuf.appendChar(pool.put(typeSig(m.externalType(types))));
|
||||
databuf.appendChar(poolWriter.putName(m.name));
|
||||
databuf.appendChar(poolWriter.putDescriptor(m));
|
||||
int acountIdx = beginAttrs();
|
||||
int acount = 0;
|
||||
if (m.code != null) {
|
||||
@ -1227,7 +950,7 @@ public class ClassWriter extends ClassFile {
|
||||
int alenIdx = writeAttr(names.Exceptions);
|
||||
databuf.appendChar(thrown.length());
|
||||
for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
|
||||
databuf.appendChar(pool.put(l.head.tsym));
|
||||
databuf.appendChar(poolWriter.putClass(l.head));
|
||||
endAttr(alenIdx);
|
||||
acount++;
|
||||
}
|
||||
@ -1303,9 +1026,8 @@ public class ClassWriter extends ClassFile {
|
||||
&& (r.start_pc + r.length) <= code.cp);
|
||||
databuf.appendChar(r.length);
|
||||
VarSymbol sym = var.sym;
|
||||
databuf.appendChar(pool.put(sym.name));
|
||||
Type vartype = sym.erasure(types);
|
||||
databuf.appendChar(pool.put(typeSig(vartype)));
|
||||
databuf.appendChar(poolWriter.putName(sym.name));
|
||||
databuf.appendChar(poolWriter.putDescriptor(sym));
|
||||
databuf.appendChar(var.reg);
|
||||
if (needsLocalVariableTypeEntry(var.sym.type)) {
|
||||
nGenericVars++;
|
||||
@ -1329,8 +1051,8 @@ public class ClassWriter extends ClassFile {
|
||||
// write variable info
|
||||
databuf.appendChar(r.start_pc);
|
||||
databuf.appendChar(r.length);
|
||||
databuf.appendChar(pool.put(sym.name));
|
||||
databuf.appendChar(pool.put(typeSig(sym.type)));
|
||||
databuf.appendChar(poolWriter.putName(sym.name));
|
||||
databuf.appendChar(poolWriter.putSignature(sym));
|
||||
databuf.appendChar(var.reg);
|
||||
count++;
|
||||
}
|
||||
@ -1457,14 +1179,10 @@ public class ClassWriter extends ClassFile {
|
||||
break;
|
||||
case CLASS:
|
||||
case ARRAY:
|
||||
if (debugstackmap) System.out.print("object(" + t + ")");
|
||||
databuf.appendByte(7);
|
||||
databuf.appendChar(pool.put(t));
|
||||
break;
|
||||
case TYPEVAR:
|
||||
if (debugstackmap) System.out.print("object(" + types.erasure(t).tsym + ")");
|
||||
databuf.appendByte(7);
|
||||
databuf.appendChar(pool.put(types.erasure(t).tsym));
|
||||
databuf.appendChar(poolWriter.putClass(types.erasure(t)));
|
||||
break;
|
||||
case UNINITIALIZED_THIS:
|
||||
if (debugstackmap) System.out.print("uninit_this");
|
||||
@ -1763,11 +1481,6 @@ public class ClassWriter extends ClassFile {
|
||||
Assert.check((c.flags() & COMPOUND) == 0);
|
||||
databuf.reset();
|
||||
poolbuf.reset();
|
||||
signatureGen.reset();
|
||||
pool = c.pool;
|
||||
innerClasses = null;
|
||||
innerClassesQueue = null;
|
||||
bootstrapMethods = new LinkedHashMap<>();
|
||||
|
||||
Type supertype = types.supertype(c.type);
|
||||
List<Type> interfaces = types.interfaces(c.type);
|
||||
@ -1793,14 +1506,14 @@ public class ClassWriter extends ClassFile {
|
||||
|
||||
if (c.owner.kind == MDL) {
|
||||
PackageSymbol unnamed = ((ModuleSymbol) c.owner).unnamedPackage;
|
||||
databuf.appendChar(pool.put(new ClassSymbol(0, names.module_info, unnamed)));
|
||||
databuf.appendChar(poolWriter.putClass(new ClassSymbol(0, names.module_info, unnamed)));
|
||||
} else {
|
||||
databuf.appendChar(pool.put(c));
|
||||
databuf.appendChar(poolWriter.putClass(c));
|
||||
}
|
||||
databuf.appendChar(supertype.hasTag(CLASS) ? pool.put(supertype.tsym) : 0);
|
||||
databuf.appendChar(supertype.hasTag(CLASS) ? poolWriter.putClass((ClassSymbol)supertype.tsym) : 0);
|
||||
databuf.appendChar(interfaces.length());
|
||||
for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
|
||||
databuf.appendChar(pool.put(l.head.tsym));
|
||||
databuf.appendChar(poolWriter.putClass((ClassSymbol)l.head.tsym));
|
||||
int fieldsCount = 0;
|
||||
int methodsCount = 0;
|
||||
for (Symbol sym : c.members().getSymbols(NON_RECURSIVE)) {
|
||||
@ -1808,14 +1521,14 @@ public class ClassWriter extends ClassFile {
|
||||
case VAR: fieldsCount++; break;
|
||||
case MTH: if ((sym.flags() & HYPOTHETICAL) == 0) methodsCount++;
|
||||
break;
|
||||
case TYP: enterInner((ClassSymbol)sym); break;
|
||||
case TYP: poolWriter.enterInner((ClassSymbol)sym); break;
|
||||
default : Assert.error();
|
||||
}
|
||||
}
|
||||
|
||||
if (c.trans_local != null) {
|
||||
for (ClassSymbol local : c.trans_local) {
|
||||
enterInner(local);
|
||||
poolWriter.enterInner(local);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1833,12 +1546,7 @@ public class ClassWriter extends ClassFile {
|
||||
sigReq = l.head.allparams().length() != 0;
|
||||
if (sigReq) {
|
||||
int alenIdx = writeAttr(names.Signature);
|
||||
if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams);
|
||||
signatureGen.assembleSig(supertype);
|
||||
for (List<Type> l = interfaces; l.nonEmpty(); l = l.tail)
|
||||
signatureGen.assembleSig(l.head);
|
||||
databuf.appendChar(pool.put(signatureGen.toName()));
|
||||
signatureGen.reset();
|
||||
databuf.appendChar(poolWriter.putSignature(c));
|
||||
endAttr(alenIdx);
|
||||
acount++;
|
||||
}
|
||||
@ -1848,9 +1556,8 @@ public class ClassWriter extends ClassFile {
|
||||
// WHM 6/29/1999: Strip file path prefix. We do it here at
|
||||
// the last possible moment because the sourcefile may be used
|
||||
// elsewhere in error diagnostics. Fixes 4241573.
|
||||
//databuf.appendChar(c.pool.put(c.sourcefile));
|
||||
String simpleName = PathFileObject.getSimpleName(c.sourcefile);
|
||||
databuf.appendChar(c.pool.put(names.fromString(simpleName)));
|
||||
databuf.appendChar(poolWriter.putName(names.fromString(simpleName)));
|
||||
endAttr(alenIdx);
|
||||
acount++;
|
||||
}
|
||||
@ -1858,12 +1565,12 @@ public class ClassWriter extends ClassFile {
|
||||
if (genCrt) {
|
||||
// Append SourceID attribute
|
||||
int alenIdx = writeAttr(names.SourceID);
|
||||
databuf.appendChar(c.pool.put(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
|
||||
databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(getLastModified(c.sourcefile)))));
|
||||
endAttr(alenIdx);
|
||||
acount++;
|
||||
// Append CompilationID attribute
|
||||
alenIdx = writeAttr(names.CompilationID);
|
||||
databuf.appendChar(c.pool.put(names.fromString(Long.toString(System.currentTimeMillis()))));
|
||||
databuf.appendChar(poolWriter.putName(names.fromString(Long.toString(System.currentTimeMillis()))));
|
||||
endAttr(alenIdx);
|
||||
acount++;
|
||||
}
|
||||
@ -1893,24 +1600,24 @@ public class ClassWriter extends ClassFile {
|
||||
}
|
||||
}
|
||||
|
||||
writePool(c.pool);
|
||||
|
||||
if (innerClasses != null) {
|
||||
writeInnerClasses();
|
||||
if (!poolWriter.bootstrapMethods.isEmpty()) {
|
||||
writeBootstrapMethods();
|
||||
acount++;
|
||||
}
|
||||
|
||||
if (!bootstrapMethods.isEmpty()) {
|
||||
writeBootstrapMethods();
|
||||
if (!poolWriter.innerClasses.isEmpty()) {
|
||||
writeInnerClasses();
|
||||
acount++;
|
||||
}
|
||||
|
||||
endAttrs(acountIdx, acount);
|
||||
|
||||
poolbuf.appendBytes(databuf.elems, 0, databuf.length);
|
||||
out.write(poolbuf.elems, 0, poolbuf.length);
|
||||
|
||||
pool = c.pool = null; // to conserve space
|
||||
poolWriter.writePool(out);
|
||||
poolWriter.reset(); // to save space
|
||||
|
||||
out.write(databuf.elems, 0, databuf.length);
|
||||
}
|
||||
|
||||
/**Allows subclasses to write additional class attributes
|
||||
|
@ -27,15 +27,27 @@ package com.sun.tools.javac.jvm;
|
||||
|
||||
import com.sun.tools.javac.code.*;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.Types.UniqueType;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Errors;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
|
||||
import java.util.function.ToIntBiFunction;
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
import static com.sun.tools.javac.code.TypeTag.BOT;
|
||||
import static com.sun.tools.javac.code.TypeTag.INT;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.*;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
|
||||
import static com.sun.tools.javac.jvm.UninitializedType.*;
|
||||
import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
|
||||
|
||||
@ -72,6 +84,7 @@ public class Code {
|
||||
|
||||
final Types types;
|
||||
final Symtab syms;
|
||||
final PoolWriter poolWriter;
|
||||
|
||||
/*---------- classfile fields: --------------- */
|
||||
|
||||
@ -177,10 +190,6 @@ public class Code {
|
||||
*/
|
||||
Position.LineMap lineMap;
|
||||
|
||||
/** The constant pool of the current class.
|
||||
*/
|
||||
final Pool pool;
|
||||
|
||||
final MethodSymbol meth;
|
||||
|
||||
private int letExprStackPos = 0;
|
||||
@ -197,7 +206,7 @@ public class Code {
|
||||
CRTable crt,
|
||||
Symtab syms,
|
||||
Types types,
|
||||
Pool pool) {
|
||||
PoolWriter poolWriter) {
|
||||
this.meth = meth;
|
||||
this.fatcode = fatcode;
|
||||
this.lineMap = lineMap;
|
||||
@ -206,6 +215,7 @@ public class Code {
|
||||
this.crt = crt;
|
||||
this.syms = syms;
|
||||
this.types = types;
|
||||
this.poolWriter = poolWriter;
|
||||
this.debugCode = debugCode;
|
||||
this.stackMap = stackMap;
|
||||
switch (stackMap) {
|
||||
@ -218,7 +228,6 @@ public class Code {
|
||||
}
|
||||
state = new State();
|
||||
lvar = new LocalVar[20];
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
|
||||
@ -389,12 +398,13 @@ public class Code {
|
||||
|
||||
/** Emit a ldc (or ldc_w) instruction, taking into account operand size
|
||||
*/
|
||||
public void emitLdc(int od) {
|
||||
public void emitLdc(LoadableConstant constant) {
|
||||
int od = poolWriter.putConstant(constant);
|
||||
if (od <= 255) {
|
||||
emitop1(ldc1, od);
|
||||
emitop1(ldc1, od, constant);
|
||||
}
|
||||
else {
|
||||
emitop2(ldc2, od);
|
||||
emitop2(ldc2, od, constant);
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,11 +441,11 @@ public class Code {
|
||||
|
||||
/** Emit an invokeinterface instruction.
|
||||
*/
|
||||
public void emitInvokeinterface(int meth, Type mtype) {
|
||||
public void emitInvokeinterface(Symbol member, Type mtype) {
|
||||
int argsize = width(mtype.getParameterTypes());
|
||||
emitop(invokeinterface);
|
||||
if (!alive) return;
|
||||
emit2(meth);
|
||||
emit2(poolWriter.putMember(member));
|
||||
emit1(argsize + 1);
|
||||
emit1(0);
|
||||
state.pop(argsize + 1);
|
||||
@ -444,14 +454,13 @@ public class Code {
|
||||
|
||||
/** Emit an invokespecial instruction.
|
||||
*/
|
||||
public void emitInvokespecial(int meth, Type mtype) {
|
||||
public void emitInvokespecial(Symbol member, Type mtype) {
|
||||
int argsize = width(mtype.getParameterTypes());
|
||||
emitop(invokespecial);
|
||||
if (!alive) return;
|
||||
emit2(meth);
|
||||
Symbol sym = (Symbol)pool.pool[meth];
|
||||
emit2(poolWriter.putMember(member));
|
||||
state.pop(argsize);
|
||||
if (sym.isConstructor())
|
||||
if (member.isConstructor())
|
||||
state.markInitialized((UninitializedType)state.peek());
|
||||
state.pop(1);
|
||||
state.push(mtype.getReturnType());
|
||||
@ -459,33 +468,33 @@ public class Code {
|
||||
|
||||
/** Emit an invokestatic instruction.
|
||||
*/
|
||||
public void emitInvokestatic(int meth, Type mtype) {
|
||||
public void emitInvokestatic(Symbol member, Type mtype) {
|
||||
int argsize = width(mtype.getParameterTypes());
|
||||
emitop(invokestatic);
|
||||
if (!alive) return;
|
||||
emit2(meth);
|
||||
emit2(poolWriter.putMember(member));
|
||||
state.pop(argsize);
|
||||
state.push(mtype.getReturnType());
|
||||
}
|
||||
|
||||
/** Emit an invokevirtual instruction.
|
||||
*/
|
||||
public void emitInvokevirtual(int meth, Type mtype) {
|
||||
public void emitInvokevirtual(Symbol member, Type mtype) {
|
||||
int argsize = width(mtype.getParameterTypes());
|
||||
emitop(invokevirtual);
|
||||
if (!alive) return;
|
||||
emit2(meth);
|
||||
emit2(poolWriter.putMember(member));
|
||||
state.pop(argsize + 1);
|
||||
state.push(mtype.getReturnType());
|
||||
}
|
||||
|
||||
/** Emit an invokedynamic instruction.
|
||||
*/
|
||||
public void emitInvokedynamic(int desc, Type mtype) {
|
||||
public void emitInvokedynamic(DynamicMethodSymbol dynMember, Type mtype) {
|
||||
int argsize = width(mtype.getParameterTypes());
|
||||
emitop(invokedynamic);
|
||||
if (!alive) return;
|
||||
emit2(desc);
|
||||
emit2(poolWriter.putDynamic(dynMember));
|
||||
emit2(0);
|
||||
state.pop(argsize);
|
||||
state.push(mtype.getReturnType());
|
||||
@ -896,6 +905,10 @@ public class Code {
|
||||
/** Emit an opcode with a one-byte operand field.
|
||||
*/
|
||||
public void emitop1(int op, int od) {
|
||||
emitop1(op, od, null);
|
||||
}
|
||||
|
||||
public void emitop1(int op, int od, PoolConstant data) {
|
||||
emitop(op);
|
||||
if (!alive) return;
|
||||
emit1(od);
|
||||
@ -904,7 +917,7 @@ public class Code {
|
||||
state.push(syms.intType);
|
||||
break;
|
||||
case ldc1:
|
||||
state.push(typeForPool(pool.pool[od]));
|
||||
state.push(types.constantType((LoadableConstant)data));
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError(mnem(op));
|
||||
@ -912,25 +925,6 @@ public class Code {
|
||||
postop();
|
||||
}
|
||||
|
||||
/** The type of a constant pool entry. */
|
||||
private Type typeForPool(Object o) {
|
||||
if (o instanceof Integer) return syms.intType;
|
||||
if (o instanceof Float) return syms.floatType;
|
||||
if (o instanceof String) return syms.stringType;
|
||||
if (o instanceof Long) return syms.longType;
|
||||
if (o instanceof Double) return syms.doubleType;
|
||||
if (o instanceof ClassSymbol) return syms.classType;
|
||||
if (o instanceof Pool.MethodHandle) return syms.methodHandleType;
|
||||
if (o instanceof UniqueType) return typeForPool(((UniqueType)o).type);
|
||||
if (o instanceof Type) {
|
||||
Type ty = (Type) o;
|
||||
|
||||
if (ty instanceof Type.ArrayType) return syms.classType;
|
||||
if (ty instanceof Type.MethodType) return syms.methodTypeType;
|
||||
}
|
||||
throw new AssertionError("Invalid type of constant pool entry: " + o.getClass());
|
||||
}
|
||||
|
||||
/** Emit an opcode with a one-byte operand field;
|
||||
* widen if field does not fit in a byte.
|
||||
*/
|
||||
@ -1003,29 +997,31 @@ public class Code {
|
||||
|
||||
/** Emit an opcode with a two-byte operand field.
|
||||
*/
|
||||
public <P extends PoolConstant> void emitop2(int op, P constant, ToIntBiFunction<PoolWriter, P> poolFunc) {
|
||||
int od = poolFunc.applyAsInt(poolWriter, constant);
|
||||
emitop2(op, od, constant);
|
||||
}
|
||||
|
||||
public void emitop2(int op, int od) {
|
||||
emitop2(op, od, null);
|
||||
}
|
||||
|
||||
public void emitop2(int op, int od, PoolConstant data) {
|
||||
emitop(op);
|
||||
if (!alive) return;
|
||||
emit2(od);
|
||||
switch (op) {
|
||||
case getstatic:
|
||||
state.push(((Symbol)(pool.pool[od])).erasure(types));
|
||||
state.push(((Symbol)data).erasure(types));
|
||||
break;
|
||||
case putstatic:
|
||||
state.pop(((Symbol)(pool.pool[od])).erasure(types));
|
||||
state.pop(((Symbol)data).erasure(types));
|
||||
break;
|
||||
case new_:
|
||||
Symbol sym;
|
||||
if (pool.pool[od] instanceof UniqueType) {
|
||||
// Required by change in Gen.makeRef to allow
|
||||
// annotated types.
|
||||
// TODO: is this needed anywhere else?
|
||||
sym = ((UniqueType)(pool.pool[od])).type.tsym;
|
||||
} else {
|
||||
sym = (Symbol)(pool.pool[od]);
|
||||
}
|
||||
state.push(uninitializedObject(sym.erasure(types), cp-3));
|
||||
case new_: {
|
||||
Type t = (Type)data;
|
||||
state.push(uninitializedObject(t.tsym.erasure(types), cp-3));
|
||||
break;
|
||||
}
|
||||
case sipush:
|
||||
state.push(syms.intType);
|
||||
break;
|
||||
@ -1053,30 +1049,27 @@ public class Code {
|
||||
markDead();
|
||||
break;
|
||||
case putfield:
|
||||
state.pop(((Symbol)(pool.pool[od])).erasure(types));
|
||||
state.pop(((Symbol)data).erasure(types));
|
||||
state.pop(1); // object ref
|
||||
break;
|
||||
case getfield:
|
||||
state.pop(1); // object ref
|
||||
state.push(((Symbol)(pool.pool[od])).erasure(types));
|
||||
state.push(((Symbol)data).erasure(types));
|
||||
break;
|
||||
case checkcast: {
|
||||
state.pop(1); // object ref
|
||||
Object o = pool.pool[od];
|
||||
Type t = (o instanceof Symbol)
|
||||
? ((Symbol)o).erasure(types)
|
||||
: types.erasure((((UniqueType)o).type));
|
||||
Type t = types.erasure((Type)data);
|
||||
state.push(t);
|
||||
break; }
|
||||
case ldc2w:
|
||||
state.push(typeForPool(pool.pool[od]));
|
||||
state.push(types.constantType((LoadableConstant)data));
|
||||
break;
|
||||
case instanceof_:
|
||||
state.pop(1);
|
||||
state.push(syms.intType);
|
||||
break;
|
||||
case ldc2:
|
||||
state.push(typeForPool(pool.pool[od]));
|
||||
state.push(types.constantType((LoadableConstant)data));
|
||||
break;
|
||||
case jsr:
|
||||
break;
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package com.sun.tools.javac.jvm;
|
||||
|
||||
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
|
||||
import com.sun.tools.javac.tree.TreeInfo.PosKind;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
@ -88,9 +89,9 @@ public class Gen extends JCTree.Visitor {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Constant pool, reset by genClass.
|
||||
/** Constant pool writer, set by genClass.
|
||||
*/
|
||||
private final Pool pool;
|
||||
final PoolWriter poolWriter;
|
||||
|
||||
protected Gen(Context context) {
|
||||
context.put(genKey, this);
|
||||
@ -121,7 +122,7 @@ public class Gen extends JCTree.Visitor {
|
||||
genCrt = options.isSet(XJCOV);
|
||||
debugCode = options.isSet("debug.code");
|
||||
disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
|
||||
pool = new Pool(types);
|
||||
poolWriter = new PoolWriter(types, names);
|
||||
|
||||
// ignore cldc because we cannot have both stackmap formats
|
||||
this.stackMap = StackMapFormat.JSR202;
|
||||
@ -252,17 +253,17 @@ public class Gen extends JCTree.Visitor {
|
||||
* @param type The type for which a reference is inserted.
|
||||
*/
|
||||
int makeRef(DiagnosticPosition pos, Type type) {
|
||||
checkDimension(pos, type);
|
||||
if (type.isAnnotated()) {
|
||||
return pool.put((Object)type);
|
||||
} else {
|
||||
return pool.put(type.hasTag(CLASS) ? (Object)type.tsym : (Object)type);
|
||||
}
|
||||
return poolWriter.putClass(checkDimension(pos, type));
|
||||
}
|
||||
|
||||
/** Check if the given type is an array with too many dimensions.
|
||||
*/
|
||||
private void checkDimension(DiagnosticPosition pos, Type t) {
|
||||
private Type checkDimension(DiagnosticPosition pos, Type t) {
|
||||
checkDimensionInternal(pos, t);
|
||||
return t;
|
||||
}
|
||||
|
||||
private void checkDimensionInternal(DiagnosticPosition pos, Type t) {
|
||||
switch (t.getTag()) {
|
||||
case METHOD:
|
||||
checkDimension(pos, t.getReturnType());
|
||||
@ -516,7 +517,7 @@ public class Gen extends JCTree.Visitor {
|
||||
if (nerrs != 0 || // only complain about a long string once
|
||||
constValue == null ||
|
||||
!(constValue instanceof String) ||
|
||||
((String)constValue).length() < Pool.MAX_STRING_LENGTH)
|
||||
((String)constValue).length() < PoolWriter.MAX_STRING_LENGTH)
|
||||
return;
|
||||
log.error(pos, Errors.LimitString);
|
||||
nerrs++;
|
||||
@ -806,7 +807,7 @@ public class Gen extends JCTree.Visitor {
|
||||
@Override
|
||||
public void visitIdent(JCIdent tree) {
|
||||
if (tree.sym.owner instanceof ClassSymbol) {
|
||||
pool.put(tree.sym.owner);
|
||||
poolWriter.putClass((ClassSymbol)tree.sym.owner);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1007,8 +1008,8 @@ public class Gen extends JCTree.Visitor {
|
||||
: null,
|
||||
syms,
|
||||
types,
|
||||
pool);
|
||||
items = new Items(pool, code, syms, types);
|
||||
poolWriter);
|
||||
items = new Items(poolWriter, code, syms, types);
|
||||
if (code.debugCode) {
|
||||
System.err.println(meth + " for body " + tree);
|
||||
}
|
||||
@ -1886,7 +1887,7 @@ public class Gen extends JCTree.Visitor {
|
||||
Assert.check(tree.encl == null && tree.def == null);
|
||||
setTypeAnnotationPositions(tree.pos);
|
||||
|
||||
code.emitop2(new_, makeRef(tree.pos(), tree.type));
|
||||
code.emitop2(new_, checkDimension(tree.pos(), tree.type), PoolWriter::putClass);
|
||||
code.emitop0(dup);
|
||||
|
||||
// Generate code for all arguments, where the expected types are
|
||||
@ -2162,7 +2163,7 @@ public class Gen extends JCTree.Visitor {
|
||||
if (!tree.clazz.type.isPrimitive() &&
|
||||
!types.isSameType(tree.expr.type, tree.clazz.type) &&
|
||||
types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
|
||||
code.emitop2(checkcast, makeRef(tree.pos(), tree.clazz.type));
|
||||
code.emitop2(checkcast, checkDimension(tree.pos(), tree.clazz.type), PoolWriter::putClass);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2221,7 +2222,7 @@ public class Gen extends JCTree.Visitor {
|
||||
Symbol sym = tree.sym;
|
||||
|
||||
if (tree.name == names._class) {
|
||||
code.emitLdc(makeRef(tree.pos(), tree.selected.type));
|
||||
code.emitLdc((LoadableConstant)checkDimension(tree.pos(), tree.selected.type));
|
||||
result = items.makeStackItem(pt);
|
||||
return;
|
||||
}
|
||||
@ -2305,7 +2306,7 @@ public class Gen extends JCTree.Visitor {
|
||||
code.endScopes(limit);
|
||||
}
|
||||
|
||||
private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) {
|
||||
private void generateReferencesToPrunedTree(ClassSymbol classSymbol) {
|
||||
List<JCTree> prunedInfo = lower.prunedTree.get(classSymbol);
|
||||
if (prunedInfo != null) {
|
||||
for (JCTree prunedTree: prunedInfo) {
|
||||
@ -2331,12 +2332,10 @@ public class Gen extends JCTree.Visitor {
|
||||
ClassSymbol c = cdef.sym;
|
||||
this.toplevel = env.toplevel;
|
||||
this.endPosTable = toplevel.endPositions;
|
||||
c.pool = pool;
|
||||
pool.reset();
|
||||
/* method normalizeDefs() can add references to external classes into the constant pool
|
||||
*/
|
||||
cdef.defs = normalizeDefs(cdef.defs, c);
|
||||
generateReferencesToPrunedTree(c, pool);
|
||||
generateReferencesToPrunedTree(c);
|
||||
Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
|
||||
localEnv.toplevel = env.toplevel;
|
||||
localEnv.enclClass = cdef;
|
||||
@ -2344,7 +2343,7 @@ public class Gen extends JCTree.Visitor {
|
||||
for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
|
||||
genDef(l.head, localEnv);
|
||||
}
|
||||
if (pool.numEntries() > Pool.MAX_ENTRIES) {
|
||||
if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
|
||||
log.error(cdef.pos(), Errors.LimitPool);
|
||||
nerrs++;
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ import com.sun.tools.javac.code.*;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.Type.*;
|
||||
import com.sun.tools.javac.jvm.Code.*;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.util.Assert;
|
||||
|
||||
@ -50,9 +52,9 @@ import static com.sun.tools.javac.jvm.ByteCodes.*;
|
||||
*/
|
||||
public class Items {
|
||||
|
||||
/** The current constant pool.
|
||||
/** The current constant pool writer.
|
||||
*/
|
||||
Pool pool;
|
||||
PoolWriter poolWriter;
|
||||
|
||||
/** The current code buffer.
|
||||
*/
|
||||
@ -72,9 +74,9 @@ public class Items {
|
||||
private final Item superItem;
|
||||
private final Item[] stackItem = new Item[TypeCodeCount];
|
||||
|
||||
public Items(Pool pool, Code code, Symtab syms, Types types) {
|
||||
public Items(PoolWriter poolWriter, Code code, Symtab syms, Types types) {
|
||||
this.code = code;
|
||||
this.pool = pool;
|
||||
this.poolWriter = poolWriter;
|
||||
this.types = types;
|
||||
voidItem = new Item(VOIDcode) {
|
||||
public String toString() { return "void"; }
|
||||
@ -444,18 +446,18 @@ public class Items {
|
||||
}
|
||||
|
||||
Item load() {
|
||||
code.emitop2(getstatic, pool.put(member));
|
||||
code.emitop2(getstatic, member, PoolWriter::putMember);
|
||||
return stackItem[typecode];
|
||||
}
|
||||
|
||||
void store() {
|
||||
code.emitop2(putstatic, pool.put(member));
|
||||
code.emitop2(putstatic, member, PoolWriter::putMember);
|
||||
}
|
||||
|
||||
Item invoke() {
|
||||
MethodType mtype = (MethodType)member.erasure(types);
|
||||
int rescode = Code.typecode(mtype.restype);
|
||||
code.emitInvokestatic(pool.put(member), mtype);
|
||||
code.emitInvokestatic(member, mtype);
|
||||
return stackItem[rescode];
|
||||
}
|
||||
|
||||
@ -484,7 +486,7 @@ public class Items {
|
||||
// assert target.hasNativeInvokeDynamic();
|
||||
MethodType mtype = (MethodType)member.erasure(types);
|
||||
int rescode = Code.typecode(mtype.restype);
|
||||
code.emitInvokedynamic(pool.put(member), mtype);
|
||||
code.emitInvokedynamic((DynamicMethodSymbol)member, mtype);
|
||||
return stackItem[rescode];
|
||||
}
|
||||
|
||||
@ -512,23 +514,23 @@ public class Items {
|
||||
}
|
||||
|
||||
Item load() {
|
||||
code.emitop2(getfield, pool.put(member));
|
||||
code.emitop2(getfield, member, PoolWriter::putMember);
|
||||
return stackItem[typecode];
|
||||
}
|
||||
|
||||
void store() {
|
||||
code.emitop2(putfield, pool.put(member));
|
||||
code.emitop2(putfield, member, PoolWriter::putMember);
|
||||
}
|
||||
|
||||
Item invoke() {
|
||||
MethodType mtype = (MethodType)member.externalType(types);
|
||||
int rescode = Code.typecode(mtype.restype);
|
||||
if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) {
|
||||
code.emitInvokeinterface(pool.put(member), mtype);
|
||||
code.emitInvokeinterface(member, mtype);
|
||||
} else if (nonvirtual) {
|
||||
code.emitInvokespecial(pool.put(member), mtype);
|
||||
code.emitInvokespecial(member, mtype);
|
||||
} else {
|
||||
code.emitInvokevirtual(pool.put(member), mtype);
|
||||
code.emitInvokevirtual(member, mtype);
|
||||
}
|
||||
return stackItem[rescode];
|
||||
}
|
||||
@ -560,26 +562,50 @@ public class Items {
|
||||
|
||||
/** The literal's value.
|
||||
*/
|
||||
Object value;
|
||||
final LoadableConstant value;
|
||||
|
||||
ImmediateItem(Type type, Object value) {
|
||||
super(Code.typecode(type));
|
||||
this.value = value;
|
||||
switch (typecode) {
|
||||
case BYTEcode:
|
||||
case SHORTcode:
|
||||
case CHARcode:
|
||||
case INTcode:
|
||||
this.value = LoadableConstant.Int((int)value);
|
||||
break;
|
||||
case LONGcode:
|
||||
this.value = LoadableConstant.Long((long)value);
|
||||
break;
|
||||
case FLOATcode:
|
||||
this.value = LoadableConstant.Float((float)value);
|
||||
break;
|
||||
case DOUBLEcode:
|
||||
this.value = LoadableConstant.Double((double)value);
|
||||
break;
|
||||
case OBJECTcode:
|
||||
this.value = LoadableConstant.String((String)value);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("unsupported tag: " + typecode);
|
||||
}
|
||||
}
|
||||
|
||||
private void ldc() {
|
||||
int idx = pool.put(value);
|
||||
if (typecode == LONGcode || typecode == DOUBLEcode) {
|
||||
code.emitop2(ldc2w, idx);
|
||||
code.emitop2(ldc2w, value, PoolWriter::putConstant);
|
||||
} else {
|
||||
code.emitLdc(idx);
|
||||
code.emitLdc(value);
|
||||
}
|
||||
}
|
||||
|
||||
private Number numericValue() {
|
||||
return (Number)((BasicConstant)value).data;
|
||||
}
|
||||
|
||||
Item load() {
|
||||
switch (typecode) {
|
||||
case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
|
||||
int ival = ((Number)value).intValue();
|
||||
int ival = numericValue().intValue();
|
||||
if (-1 <= ival && ival <= 5)
|
||||
code.emitop0(iconst_0 + ival);
|
||||
else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE)
|
||||
@ -590,14 +616,14 @@ public class Items {
|
||||
ldc();
|
||||
break;
|
||||
case LONGcode:
|
||||
long lval = ((Number)value).longValue();
|
||||
long lval = numericValue().longValue();
|
||||
if (lval == 0 || lval == 1)
|
||||
code.emitop0(lconst_0 + (int)lval);
|
||||
else
|
||||
ldc();
|
||||
break;
|
||||
case FLOATcode:
|
||||
float fval = ((Number)value).floatValue();
|
||||
float fval = numericValue().floatValue();
|
||||
if (isPosZero(fval) || fval == 1.0 || fval == 2.0)
|
||||
code.emitop0(fconst_0 + (int)fval);
|
||||
else {
|
||||
@ -605,7 +631,7 @@ public class Items {
|
||||
}
|
||||
break;
|
||||
case DOUBLEcode:
|
||||
double dval = ((Number)value).doubleValue();
|
||||
double dval = numericValue().doubleValue();
|
||||
if (isPosZero(dval) || dval == 1.0)
|
||||
code.emitop0(dconst_0 + (int)dval);
|
||||
else
|
||||
@ -632,7 +658,7 @@ public class Items {
|
||||
}
|
||||
|
||||
CondItem mkCond() {
|
||||
int ival = ((Number)value).intValue();
|
||||
int ival = numericValue().intValue();
|
||||
return makeCondItem(ival != 0 ? goto_ : dontgoto);
|
||||
}
|
||||
|
||||
@ -647,31 +673,31 @@ public class Items {
|
||||
else
|
||||
return new ImmediateItem(
|
||||
syms.intType,
|
||||
((Number)value).intValue());
|
||||
numericValue().intValue());
|
||||
case LONGcode:
|
||||
return new ImmediateItem(
|
||||
syms.longType,
|
||||
((Number)value).longValue());
|
||||
numericValue().longValue());
|
||||
case FLOATcode:
|
||||
return new ImmediateItem(
|
||||
syms.floatType,
|
||||
((Number)value).floatValue());
|
||||
numericValue().floatValue());
|
||||
case DOUBLEcode:
|
||||
return new ImmediateItem(
|
||||
syms.doubleType,
|
||||
((Number)value).doubleValue());
|
||||
numericValue().doubleValue());
|
||||
case BYTEcode:
|
||||
return new ImmediateItem(
|
||||
syms.byteType,
|
||||
(int)(byte)((Number)value).intValue());
|
||||
(int)(byte)numericValue().intValue());
|
||||
case CHARcode:
|
||||
return new ImmediateItem(
|
||||
syms.charType,
|
||||
(int)(char)((Number)value).intValue());
|
||||
(int)(char)numericValue().intValue());
|
||||
case SHORTcode:
|
||||
return new ImmediateItem(
|
||||
syms.shortType,
|
||||
(int)(short)((Number)value).intValue());
|
||||
(int)(short)numericValue().intValue());
|
||||
default:
|
||||
return super.coerce(targetcode);
|
||||
}
|
||||
|
@ -24,6 +24,9 @@
|
||||
*/
|
||||
package com.sun.tools.javac.jvm;
|
||||
|
||||
import com.sun.tools.javac.util.ByteBuffer;
|
||||
import com.sun.tools.javac.util.Name.NameMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
@ -55,16 +58,15 @@ public class ModuleNameReader {
|
||||
|
||||
/** The buffer containing the currently read class file.
|
||||
*/
|
||||
private byte[] buf = new byte[INITIAL_BUFFER_SIZE];
|
||||
private ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE);
|
||||
|
||||
/** The current input pointer.
|
||||
*/
|
||||
private int bp;
|
||||
|
||||
/** For every constant pool entry, an index into buf where the
|
||||
* defining section of the entry is found.
|
||||
/** The constant pool reader.
|
||||
*/
|
||||
private int[] poolIdx;
|
||||
private PoolReader reader;
|
||||
|
||||
public ModuleNameReader() {
|
||||
}
|
||||
@ -83,7 +85,8 @@ public class ModuleNameReader {
|
||||
|
||||
public String readModuleName(InputStream in) throws IOException, BadClassFile {
|
||||
bp = 0;
|
||||
buf = readInputStream(buf, in);
|
||||
buf.reset();
|
||||
buf.appendStream(in);
|
||||
|
||||
int magic = nextInt();
|
||||
if (magic != JAVA_MAGIC)
|
||||
@ -94,7 +97,8 @@ public class ModuleNameReader {
|
||||
if (majorVersion < 53)
|
||||
throw new BadClassFile("bad major version number for module: " + majorVersion);
|
||||
|
||||
indexPool();
|
||||
reader = new PoolReader(buf);
|
||||
bp = reader.readPool(buf, bp);
|
||||
|
||||
int access_flags = nextChar();
|
||||
if (access_flags != 0x8000)
|
||||
@ -110,8 +114,8 @@ public class ModuleNameReader {
|
||||
for (int i = 0; i < attributes_count; i++) {
|
||||
int attr_name = nextChar();
|
||||
int attr_length = nextInt();
|
||||
if (getUtf8Value(attr_name, false).equals("Module") && attr_length > 2) {
|
||||
return getModuleName(nextChar());
|
||||
if (reader.peekName(attr_name, utf8Mapper(false)).equals("Module") && attr_length > 2) {
|
||||
return reader.peekModuleName(nextChar(), utf8Mapper(true));
|
||||
} else {
|
||||
// skip over unknown attributes
|
||||
bp += attr_length;
|
||||
@ -125,132 +129,26 @@ public class ModuleNameReader {
|
||||
throw new BadClassFile("invalid " + name + " for module: " + count);
|
||||
}
|
||||
|
||||
/** Extract a character at position bp from buf.
|
||||
*/
|
||||
char getChar(int bp) {
|
||||
return
|
||||
(char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
|
||||
}
|
||||
|
||||
/** Read a character.
|
||||
*/
|
||||
char nextChar() {
|
||||
return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
|
||||
char res = buf.getChar(bp);
|
||||
bp += 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Read an integer.
|
||||
*/
|
||||
int nextInt() {
|
||||
return
|
||||
((buf[bp++] & 0xFF) << 24) +
|
||||
((buf[bp++] & 0xFF) << 16) +
|
||||
((buf[bp++] & 0xFF) << 8) +
|
||||
(buf[bp++] & 0xFF);
|
||||
int res = buf.getInt(bp);
|
||||
bp += 4;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Index all constant pool entries, writing their start addresses into
|
||||
* poolIdx.
|
||||
*/
|
||||
void indexPool() throws BadClassFile {
|
||||
poolIdx = new int[nextChar()];
|
||||
int i = 1;
|
||||
while (i < poolIdx.length) {
|
||||
poolIdx[i++] = bp;
|
||||
byte tag = buf[bp++];
|
||||
switch (tag) {
|
||||
case CONSTANT_Utf8: case CONSTANT_Unicode: {
|
||||
int len = nextChar();
|
||||
bp = bp + len;
|
||||
break;
|
||||
}
|
||||
case CONSTANT_Class:
|
||||
case CONSTANT_String:
|
||||
case CONSTANT_MethodType:
|
||||
case CONSTANT_Module:
|
||||
case CONSTANT_Package:
|
||||
bp = bp + 2;
|
||||
break;
|
||||
case CONSTANT_MethodHandle:
|
||||
bp = bp + 3;
|
||||
break;
|
||||
case CONSTANT_Fieldref:
|
||||
case CONSTANT_Methodref:
|
||||
case CONSTANT_InterfaceMethodref:
|
||||
case CONSTANT_NameandType:
|
||||
case CONSTANT_Integer:
|
||||
case CONSTANT_Float:
|
||||
case CONSTANT_InvokeDynamic:
|
||||
bp = bp + 4;
|
||||
break;
|
||||
case CONSTANT_Long:
|
||||
case CONSTANT_Double:
|
||||
bp = bp + 8;
|
||||
i++;
|
||||
break;
|
||||
default:
|
||||
throw new BadClassFile("malformed constant pool");
|
||||
}
|
||||
}
|
||||
NameMapper<String> utf8Mapper(boolean internalize) {
|
||||
return internalize ?
|
||||
(buf, offset, len) -> new String(ClassFile.internalize(buf, offset, len)) :
|
||||
String::new;
|
||||
}
|
||||
|
||||
String getUtf8Value(int index, boolean internalize) throws BadClassFile {
|
||||
int utf8Index = poolIdx[index];
|
||||
if (buf[utf8Index] == CONSTANT_Utf8) {
|
||||
int len = getChar(utf8Index + 1);
|
||||
int start = utf8Index + 3;
|
||||
if (internalize) {
|
||||
return new String(ClassFile.internalize(buf, start, len));
|
||||
} else {
|
||||
return new String(buf, start, len);
|
||||
}
|
||||
}
|
||||
throw new BadClassFile("bad name at index " + index);
|
||||
}
|
||||
|
||||
String getModuleName(int index) throws BadClassFile {
|
||||
int infoIndex = poolIdx[index];
|
||||
if (buf[infoIndex] == CONSTANT_Module) {
|
||||
return getUtf8Value(getChar(infoIndex + 1), true);
|
||||
} else {
|
||||
throw new BadClassFile("bad module name at index " + index);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
|
||||
try {
|
||||
buf = ensureCapacity(buf, s.available());
|
||||
int r = s.read(buf);
|
||||
int bp = 0;
|
||||
while (r != -1) {
|
||||
bp += r;
|
||||
buf = ensureCapacity(buf, bp);
|
||||
r = s.read(buf, bp, buf.length - bp);
|
||||
}
|
||||
return buf;
|
||||
} finally {
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException e) {
|
||||
/* Ignore any errors, as this stream may have already
|
||||
* thrown a related exception which is the one that
|
||||
* should be reported.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ensureCapacity will increase the buffer as needed, taking note that
|
||||
* the new buffer will always be greater than the needed and never
|
||||
* exactly equal to the needed size or bp. If equal then the read (above)
|
||||
* will infinitely loop as buf.length - bp == 0.
|
||||
*/
|
||||
private static byte[] ensureCapacity(byte[] buf, int needed) {
|
||||
if (buf.length <= needed) {
|
||||
byte[] old = buf;
|
||||
buf = new byte[Integer.highestOneBit(needed) << 1];
|
||||
System.arraycopy(old, 0, buf, 0, old.length);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
@ -1,372 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.jvm;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.TypeTag;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.code.Types.UniqueType;
|
||||
|
||||
import com.sun.tools.javac.util.ArrayUtils;
|
||||
import com.sun.tools.javac.util.Assert;
|
||||
import com.sun.tools.javac.util.Filter;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.sun.tools.javac.util.DefinedBy;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
|
||||
import static com.sun.tools.javac.code.Kinds.*;
|
||||
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
||||
|
||||
/** An internal structure that corresponds to the constant pool of a classfile.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class Pool {
|
||||
|
||||
public static final int MAX_ENTRIES = 0xFFFF;
|
||||
public static final int MAX_STRING_LENGTH = 0xFFFF;
|
||||
|
||||
/** Index of next constant to be entered.
|
||||
*/
|
||||
int pp;
|
||||
|
||||
/** The initial pool buffer.
|
||||
*/
|
||||
Object[] pool;
|
||||
|
||||
/** A hashtable containing all constants in the pool.
|
||||
*/
|
||||
Map<Object,Integer> indices;
|
||||
|
||||
Types types;
|
||||
|
||||
/** Construct a pool with given number of elements and element array.
|
||||
*/
|
||||
public Pool(int pp, Object[] pool, Types types) {
|
||||
this.pp = pp;
|
||||
this.pool = pool;
|
||||
this.types = types;
|
||||
this.indices = new HashMap<>(pool.length);
|
||||
for (int i = 1; i < pp; i++) {
|
||||
if (pool[i] != null) indices.put(pool[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Construct an empty pool.
|
||||
*/
|
||||
public Pool(Types types) {
|
||||
this(1, new Object[64], types);
|
||||
}
|
||||
|
||||
/** Return the number of entries in the constant pool.
|
||||
*/
|
||||
public int numEntries() {
|
||||
return pp;
|
||||
}
|
||||
|
||||
/** Remove everything from this pool.
|
||||
*/
|
||||
public void reset() {
|
||||
pp = 1;
|
||||
indices.clear();
|
||||
}
|
||||
|
||||
/** Place an object in the pool, unless it is already there.
|
||||
* If object is a symbol also enter its owner unless the owner is a
|
||||
* package. Return the object's index in the pool.
|
||||
*/
|
||||
public int put(Object value) {
|
||||
value = makePoolValue(value);
|
||||
Assert.check(!(value instanceof Type.TypeVar));
|
||||
Assert.check(!(value instanceof Types.UniqueType &&
|
||||
((UniqueType) value).type instanceof Type.TypeVar));
|
||||
Integer index = indices.get(value);
|
||||
if (index == null) {
|
||||
index = pp;
|
||||
indices.put(value, index);
|
||||
pool = ArrayUtils.ensureCapacity(pool, pp);
|
||||
pool[pp++] = value;
|
||||
if (value instanceof Long || value instanceof Double) {
|
||||
pool = ArrayUtils.ensureCapacity(pool, pp);
|
||||
pool[pp++] = null;
|
||||
}
|
||||
}
|
||||
return index.intValue();
|
||||
}
|
||||
|
||||
Object makePoolValue(Object o) {
|
||||
if (o instanceof DynamicMethodSymbol) {
|
||||
return new DynamicMethod((DynamicMethodSymbol)o, types);
|
||||
} else if (o instanceof MethodSymbol) {
|
||||
return new Method((MethodSymbol)o, types);
|
||||
} else if (o instanceof VarSymbol) {
|
||||
return new Variable((VarSymbol)o, types);
|
||||
} else if (o instanceof Type) {
|
||||
Type t = (Type)o;
|
||||
// ClassRefs can come from ClassSymbols or from Types.
|
||||
// Return the symbol for these types to avoid duplicates
|
||||
// in the constant pool
|
||||
if (t.hasTag(TypeTag.CLASS))
|
||||
return t.tsym;
|
||||
else
|
||||
return new UniqueType(t, types);
|
||||
} else {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the given object's index in the pool,
|
||||
* or -1 if object is not in there.
|
||||
*/
|
||||
public int get(Object o) {
|
||||
Integer n = indices.get(o);
|
||||
return n == null ? -1 : n.intValue();
|
||||
}
|
||||
|
||||
static class Method extends DelegatedSymbol<MethodSymbol> {
|
||||
UniqueType uniqueType;
|
||||
Method(MethodSymbol m, Types types) {
|
||||
super(m);
|
||||
this.uniqueType = new UniqueType(m.type, types);
|
||||
}
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public boolean equals(Object any) {
|
||||
if (!(any instanceof Method)) return false;
|
||||
MethodSymbol o = ((Method)any).other;
|
||||
MethodSymbol m = this.other;
|
||||
return
|
||||
o.name == m.name &&
|
||||
o.owner == m.owner &&
|
||||
((Method)any).uniqueType.equals(uniqueType);
|
||||
}
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public int hashCode() {
|
||||
MethodSymbol m = this.other;
|
||||
return
|
||||
m.name.hashCode() * 33 +
|
||||
m.owner.hashCode() * 9 +
|
||||
uniqueType.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynamicMethod extends Method {
|
||||
public Object[] uniqueStaticArgs;
|
||||
|
||||
public DynamicMethod(DynamicMethodSymbol m, Types types) {
|
||||
super(m, types);
|
||||
uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types);
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public boolean equals(Object any) {
|
||||
return equalsImpl(any, true);
|
||||
}
|
||||
|
||||
protected boolean equalsImpl(Object any, boolean includeDynamicArgs) {
|
||||
if (includeDynamicArgs && !super.equals(any)) return false;
|
||||
if (!(any instanceof DynamicMethod)) return false;
|
||||
DynamicMethodSymbol dm1 = (DynamicMethodSymbol)other;
|
||||
DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)any).other;
|
||||
return dm1.bsm == dm2.bsm &&
|
||||
dm1.bsmKind == dm2.bsmKind &&
|
||||
Arrays.equals(uniqueStaticArgs,
|
||||
((DynamicMethod)any).uniqueStaticArgs);
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public int hashCode() {
|
||||
return hashCodeImpl(true);
|
||||
}
|
||||
|
||||
protected int hashCodeImpl(boolean includeDynamicArgs) {
|
||||
int hash = includeDynamicArgs ? super.hashCode() : 0;
|
||||
DynamicMethodSymbol dm = (DynamicMethodSymbol)other;
|
||||
hash += dm.bsmKind * 7 +
|
||||
dm.bsm.hashCode() * 11;
|
||||
for (int i = 0; i < dm.staticArgs.length; i++) {
|
||||
hash += (uniqueStaticArgs[i].hashCode() * 23);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
private Object[] getUniqueTypeArray(Object[] objects, Types types) {
|
||||
Object[] result = new Object[objects.length];
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (objects[i] instanceof Type) {
|
||||
result[i] = new UniqueType((Type)objects[i], types);
|
||||
} else {
|
||||
result[i] = objects[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static class BootstrapMethodsKey extends DynamicMethod {
|
||||
BootstrapMethodsKey(DynamicMethodSymbol m, Types types) {
|
||||
super(m, types);
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public boolean equals(Object any) {
|
||||
return equalsImpl(any, false);
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public int hashCode() {
|
||||
return hashCodeImpl(false);
|
||||
}
|
||||
|
||||
Object[] getUniqueArgs() {
|
||||
return uniqueStaticArgs;
|
||||
}
|
||||
}
|
||||
|
||||
static class BootstrapMethodsValue {
|
||||
final MethodHandle mh;
|
||||
final int index;
|
||||
|
||||
public BootstrapMethodsValue(MethodHandle mh, int index) {
|
||||
this.mh = mh;
|
||||
this.index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Variable extends DelegatedSymbol<VarSymbol> {
|
||||
UniqueType uniqueType;
|
||||
Variable(VarSymbol v, Types types) {
|
||||
super(v);
|
||||
this.uniqueType = new UniqueType(v.type, types);
|
||||
}
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public boolean equals(Object any) {
|
||||
if (!(any instanceof Variable)) return false;
|
||||
VarSymbol o = ((Variable)any).other;
|
||||
VarSymbol v = other;
|
||||
return
|
||||
o.name == v.name &&
|
||||
o.owner == v.owner &&
|
||||
((Variable)any).uniqueType.equals(uniqueType);
|
||||
}
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public int hashCode() {
|
||||
VarSymbol v = other;
|
||||
return
|
||||
v.name.hashCode() * 33 +
|
||||
v.owner.hashCode() * 9 +
|
||||
uniqueType.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MethodHandle {
|
||||
|
||||
/** Reference kind - see ClassFile */
|
||||
int refKind;
|
||||
|
||||
/** Reference symbol */
|
||||
Symbol refSym;
|
||||
|
||||
UniqueType uniqueType;
|
||||
|
||||
public MethodHandle(int refKind, Symbol refSym, Types types) {
|
||||
this.refKind = refKind;
|
||||
this.refSym = refSym;
|
||||
this.uniqueType = new UniqueType(this.refSym.type, types);
|
||||
checkConsistent();
|
||||
}
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof MethodHandle)) return false;
|
||||
MethodHandle mr = (MethodHandle) other;
|
||||
if (mr.refKind != refKind) return false;
|
||||
Symbol o = mr.refSym;
|
||||
return
|
||||
o.name == refSym.name &&
|
||||
o.owner == refSym.owner &&
|
||||
((MethodHandle)other).uniqueType.equals(uniqueType);
|
||||
}
|
||||
public int hashCode() {
|
||||
return
|
||||
refKind * 65 +
|
||||
refSym.name.hashCode() * 33 +
|
||||
refSym.owner.hashCode() * 9 +
|
||||
uniqueType.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check consistency of reference kind and symbol (see JVMS 4.4.8)
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
private void checkConsistent() {
|
||||
boolean staticOk = false;
|
||||
Kind expectedKind = null;
|
||||
Filter<Name> nameFilter = nonInitFilter;
|
||||
boolean interfaceOwner = false;
|
||||
switch (refKind) {
|
||||
case ClassFile.REF_getStatic:
|
||||
case ClassFile.REF_putStatic:
|
||||
staticOk = true;
|
||||
case ClassFile.REF_getField:
|
||||
case ClassFile.REF_putField:
|
||||
expectedKind = VAR;
|
||||
break;
|
||||
case ClassFile.REF_newInvokeSpecial:
|
||||
nameFilter = initFilter;
|
||||
expectedKind = MTH;
|
||||
break;
|
||||
case ClassFile.REF_invokeInterface:
|
||||
interfaceOwner = true;
|
||||
expectedKind = MTH;
|
||||
break;
|
||||
case ClassFile.REF_invokeStatic:
|
||||
interfaceOwner = true;
|
||||
staticOk = true;
|
||||
case ClassFile.REF_invokeVirtual:
|
||||
expectedKind = MTH;
|
||||
break;
|
||||
case ClassFile.REF_invokeSpecial:
|
||||
interfaceOwner = true;
|
||||
expectedKind = MTH;
|
||||
break;
|
||||
}
|
||||
Assert.check(!refSym.isStatic() || staticOk);
|
||||
Assert.check(refSym.kind == expectedKind);
|
||||
Assert.check(nameFilter.accepts(refSym.name));
|
||||
Assert.check(!refSym.owner.isInterface() || interfaceOwner);
|
||||
}
|
||||
//where
|
||||
Filter<Name> nonInitFilter = n -> (n != n.table.names.init && n != n.table.names.clinit);
|
||||
|
||||
Filter<Name> initFilter = n -> n == n.table.names.init;
|
||||
}
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.jvm;
|
||||
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.code.Types.UniqueType;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import com.sun.tools.javac.util.Pair;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* This interface models all javac entities that can be used to represent constant pool entries.
|
||||
* A pool constant entity must (i) be associated with a constant pool entry tag and have a function
|
||||
* which generates a key for the desired pool entry (so as to avoid duplicate entries when writing the
|
||||
* constant pool).
|
||||
*/
|
||||
public interface PoolConstant {
|
||||
|
||||
/**
|
||||
* The constant pool entry key.
|
||||
*/
|
||||
default Object poolKey(Types types) { return this; }
|
||||
|
||||
/**
|
||||
* The constant pool entry tag.
|
||||
*/
|
||||
int poolTag();
|
||||
|
||||
/**
|
||||
* The root of pool constants that can be loaded (e.g. with {@code ldc}, or appear as static
|
||||
* arguments to a bootstrap method.
|
||||
*/
|
||||
interface LoadableConstant extends PoolConstant {
|
||||
|
||||
/**
|
||||
* Create a pool constant describing a given {@code int} value.
|
||||
*/
|
||||
static LoadableConstant Int(int i) {
|
||||
return new BasicConstant(ClassFile.CONSTANT_Integer, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pool constant describing a given {@code float} value.
|
||||
*/
|
||||
static LoadableConstant Float(float f) {
|
||||
return new BasicConstant(ClassFile.CONSTANT_Float, f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pool constant describing a given {@code long} value.
|
||||
*/
|
||||
static LoadableConstant Long(long l) {
|
||||
return new BasicConstant(ClassFile.CONSTANT_Long, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pool constant describing a given {@code double} value.
|
||||
*/
|
||||
static LoadableConstant Double(double d) {
|
||||
return new BasicConstant(ClassFile.CONSTANT_Double, d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pool constant describing a given {@code String} value.
|
||||
*/
|
||||
static LoadableConstant String(String s) {
|
||||
return new BasicConstant(ClassFile.CONSTANT_String, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class models a pool constant of given basic type, one of {@code int}, {@code float},
|
||||
* {@code long}, {@code double} or {@code String}.
|
||||
*/
|
||||
class BasicConstant implements LoadableConstant {
|
||||
int tag;
|
||||
Object data;
|
||||
|
||||
private BasicConstant(int tag, Object data) {
|
||||
this.tag = tag;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poolKey(Types types) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This interface models a dynamic pool constant (either of kind {@code InvokeDynamic} or
|
||||
* {@code ConstantDynamic}). In addition to the functionalities provided by the base interface,
|
||||
* a dynamic pool constant must expose its dynamic type, bootstrap method and static argument list.
|
||||
* Finally, a dynamic constant must have a way to compute a bootstrap method key - that is,
|
||||
* a unique key for the bootstrap method entry it refers to, to avoid duplicates when writing
|
||||
* the {@code BootstrapMethods} attribute.
|
||||
*/
|
||||
interface Dynamic extends PoolConstant {
|
||||
|
||||
/**
|
||||
* The dynamic constant's dynamic type.
|
||||
*/
|
||||
PoolConstant dynamicType();
|
||||
|
||||
/**
|
||||
* The dynamic constant's static argument list.
|
||||
*/
|
||||
LoadableConstant[] staticArgs();
|
||||
|
||||
/**
|
||||
* The dynamic constant's bootstrap method.
|
||||
*/
|
||||
LoadableConstant bootstrapMethod();
|
||||
|
||||
default BsmKey bsmKey(Types types) {
|
||||
return new BsmKey(types, bootstrapMethod(), staticArgs());
|
||||
}
|
||||
|
||||
@Override
|
||||
default Object poolKey(Types types) {
|
||||
return new Pair<>(bsmKey(types), dynamicType().poolKey(types));
|
||||
}
|
||||
|
||||
/**
|
||||
* A class modelling a bootstrap method key.
|
||||
*/
|
||||
class BsmKey {
|
||||
/**
|
||||
* The key's bootstrap method constant.
|
||||
*/
|
||||
public final LoadableConstant bsm;
|
||||
|
||||
/**
|
||||
* The key's static argument list.
|
||||
*/
|
||||
public final LoadableConstant[] staticArgs;
|
||||
|
||||
private final Object bsmKey;
|
||||
private final List<?> staticArgKeys;
|
||||
|
||||
private BsmKey(Types types, LoadableConstant bsm, LoadableConstant[] staticArgs) {
|
||||
this.bsm = bsm;
|
||||
this.bsmKey = bsm.poolKey(types);
|
||||
this.staticArgs = staticArgs;
|
||||
this.staticArgKeys = Stream.of(staticArgs)
|
||||
.map(p -> p.poolKey(types))
|
||||
.collect(List.collector());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return bsmKey.hashCode() +
|
||||
staticArgKeys.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof BsmKey) {
|
||||
BsmKey other = (BsmKey)obj;
|
||||
return Objects.equals(bsmKey, other.bsmKey) &&
|
||||
Objects.equals(staticArgKeys, other.staticArgKeys);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A pool constant implememntation describing a name and type pool entry.
|
||||
*/
|
||||
final class NameAndType implements PoolConstant {
|
||||
|
||||
final Name name;
|
||||
final Type type;
|
||||
|
||||
NameAndType(Name name, Type type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
return ClassFile.CONSTANT_NameandType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object poolKey(Types types) {
|
||||
return new Pair<>(name, new UniqueType(type, types));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.jvm;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.PackageSymbol;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
|
||||
import com.sun.tools.javac.util.ByteBuffer;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import com.sun.tools.javac.util.Name.NameMapper;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Dynamic;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Fieldref;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Float;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Integer;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InterfaceMethodref;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_InvokeDynamic;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Long;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodHandle;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Methodref;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Module;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_NameandType;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Package;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Utf8;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.internalize;
|
||||
|
||||
/**
|
||||
* Pool interface towards {@code ClassReader}. Exposes methods to decode and read javac entities
|
||||
* from the constant pool.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class PoolReader {
|
||||
|
||||
private final ClassReader reader;
|
||||
private final ByteBuffer buf;
|
||||
private final Names names;
|
||||
private final Symtab syms;
|
||||
|
||||
private ImmutablePoolHelper pool;
|
||||
|
||||
PoolReader(ByteBuffer buf) {
|
||||
this(null, buf, null, null);
|
||||
}
|
||||
|
||||
PoolReader(ClassReader reader, Names names, Symtab syms) {
|
||||
this(reader, reader.buf, names, syms);
|
||||
}
|
||||
|
||||
PoolReader(ClassReader reader, ByteBuffer buf, Names names, Symtab syms) {
|
||||
this.reader = reader;
|
||||
this.buf = buf;
|
||||
this.names = names;
|
||||
this.syms = syms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a class symbol from the pool at given index.
|
||||
*/
|
||||
ClassSymbol getClass(int index) {
|
||||
return pool.readIfNeeded(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class name without resolving
|
||||
*/
|
||||
<Z> Z peekClassName(int index, NameMapper<Z> mapper) {
|
||||
return peekName(buf.getChar(pool.offset(index)), mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get package name without resolving
|
||||
*/
|
||||
<Z> Z peekPackageName(int index, NameMapper<Z> mapper) {
|
||||
return peekName(buf.getChar(pool.offset(index)), mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get module name without resolving
|
||||
*/
|
||||
<Z> Z peekModuleName(int index, NameMapper<Z> mapper) {
|
||||
return peekName(buf.getChar(pool.offset(index)), mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a module symbol from the pool at given index.
|
||||
*/
|
||||
ModuleSymbol getModule(int index) {
|
||||
return pool.readIfNeeded(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a module symbol from the pool at given index.
|
||||
*/
|
||||
PackageSymbol getPackage(int index) {
|
||||
return pool.readIfNeeded(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Peek a name from the pool at given index without resolving.
|
||||
*/
|
||||
<Z> Z peekName(int index, Name.NameMapper<Z> mapper) {
|
||||
return getUtf8(index, mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a name from the pool at given index.
|
||||
*/
|
||||
Name getName(int index) {
|
||||
return pool.readIfNeeded(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a type from the pool at given index.
|
||||
*/
|
||||
Type getType(int index) {
|
||||
return getName(index).map(reader::sigToType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a name and type pair from the pool at given index.
|
||||
*/
|
||||
NameAndType getNameAndType(int index) {
|
||||
return pool.readIfNeeded(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a class symbol from the pool at given index.
|
||||
*/
|
||||
Object getConstant(int index) {
|
||||
return pool.readIfNeeded(index);
|
||||
}
|
||||
|
||||
boolean hasTag(int index, int tag) {
|
||||
return pool.tag(index) == tag;
|
||||
}
|
||||
|
||||
private <Z> Z getUtf8(int index, NameMapper<Z> mapper) {
|
||||
int tag = pool.tag(index);
|
||||
if (tag == CONSTANT_Utf8) {
|
||||
int offset = pool.offset(index);
|
||||
int len = pool.poolbuf.getChar(offset);
|
||||
return mapper.map(pool.poolbuf.elems, offset + 2, len);
|
||||
} else {
|
||||
throw new AssertionError("Unexpected constant tag: " + tag);
|
||||
}
|
||||
}
|
||||
|
||||
private Object resolve(ByteBuffer poolbuf, int tag, int offset) {
|
||||
switch (tag) {
|
||||
case CONSTANT_Utf8: {
|
||||
int len = poolbuf.getChar(offset);
|
||||
return names.fromUtf(poolbuf.elems, offset + 2, len);
|
||||
}
|
||||
case CONSTANT_Class: {
|
||||
int index = poolbuf.getChar(offset);
|
||||
Name name = names.fromUtf(getName(index).map(ClassFile::internalize));
|
||||
return syms.enterClass(reader.currentModule, name);
|
||||
}
|
||||
case CONSTANT_NameandType: {
|
||||
Name name = getName(poolbuf.getChar(offset));
|
||||
Type type = getType(poolbuf.getChar(offset + 2));
|
||||
return new NameAndType(name, type);
|
||||
}
|
||||
case CONSTANT_Integer:
|
||||
return poolbuf.getInt(offset);
|
||||
case CONSTANT_Float:
|
||||
return poolbuf.getFloat(offset);
|
||||
case CONSTANT_Long:
|
||||
return poolbuf.getLong(offset);
|
||||
case CONSTANT_Double:
|
||||
return poolbuf.getDouble(offset);
|
||||
case CONSTANT_String:
|
||||
return getName(poolbuf.getChar(offset)).toString();
|
||||
case CONSTANT_Package: {
|
||||
Name name = getName(poolbuf.getChar(offset));
|
||||
return syms.enterPackage(reader.currentModule, names.fromUtf(internalize(name)));
|
||||
}
|
||||
case CONSTANT_Module: {
|
||||
Name name = getName(poolbuf.getChar(offset));
|
||||
return syms.enterModule(name);
|
||||
}
|
||||
default:
|
||||
throw new AssertionError("Unexpected constant tag: " + tag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse all constant pool entries, and keep track of their offsets. For performance and laziness
|
||||
* reasons, it would be unwise to eagerly turn all pool entries into corresponding javac
|
||||
* entities. First, not all entries are actually going to be read/used by javac; secondly,
|
||||
* there are cases where creating a symbol too early might result in issues (hence methods like
|
||||
* {@link PoolReader#peekClassName(int, NameMapper)}.
|
||||
*/
|
||||
int readPool(ByteBuffer poolbuf, int offset) {
|
||||
int poolSize = poolbuf.getChar(offset);
|
||||
int index = 1;
|
||||
offset += 2;
|
||||
int[] offsets = new int[poolSize];
|
||||
while (index < poolSize) {
|
||||
byte tag = poolbuf.getByte(offset++);
|
||||
offsets[index] = offset;
|
||||
switch (tag) {
|
||||
case CONSTANT_Utf8: {
|
||||
int len = poolbuf.getChar(offset);
|
||||
offset += 2 + len;
|
||||
break;
|
||||
}
|
||||
case CONSTANT_Class:
|
||||
case CONSTANT_String:
|
||||
case CONSTANT_Module:
|
||||
case CONSTANT_Package:
|
||||
case CONSTANT_MethodType:
|
||||
offset += 2;
|
||||
break;
|
||||
case CONSTANT_MethodHandle:
|
||||
offset += 3;
|
||||
break;
|
||||
case CONSTANT_Fieldref:
|
||||
case CONSTANT_Methodref:
|
||||
case CONSTANT_InterfaceMethodref:
|
||||
case CONSTANT_NameandType:
|
||||
case CONSTANT_Integer:
|
||||
case CONSTANT_Float:
|
||||
case CONSTANT_Dynamic:
|
||||
case CONSTANT_InvokeDynamic:
|
||||
offset += 4;
|
||||
break;
|
||||
case CONSTANT_Long:
|
||||
case CONSTANT_Double:
|
||||
offset += 8;
|
||||
break;
|
||||
default:
|
||||
throw reader.badClassFile("bad.const.pool.tag.at",
|
||||
Byte.toString(tag),
|
||||
Integer.toString(offset - 1));
|
||||
}
|
||||
index += sizeof(tag);
|
||||
}
|
||||
pool = new ImmutablePoolHelper(poolbuf, offsets);
|
||||
return offset;
|
||||
}
|
||||
|
||||
private int sizeof(int tag) {
|
||||
switch (tag) {
|
||||
case ClassFile.CONSTANT_Double: case ClassFile.CONSTANT_Long:
|
||||
return 2;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
class ImmutablePoolHelper {
|
||||
|
||||
final Object[] values;
|
||||
final int[] offsets;
|
||||
final ByteBuffer poolbuf;
|
||||
|
||||
public ImmutablePoolHelper(ByteBuffer poolbuf, int[] offsets) {
|
||||
this.offsets = offsets;
|
||||
this.values = new Object[offsets.length];
|
||||
this.poolbuf = poolbuf;
|
||||
}
|
||||
|
||||
private int checkIndex(int index) {
|
||||
if (index <= 0 || index >= offsets.length) {
|
||||
//pool index is outside valid range.
|
||||
throw reader.badClassFile("bad.const.pool.index", reader.currentClassFile,
|
||||
index, offsets.length);
|
||||
} else {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
int offset(int index) {
|
||||
return offsets[checkIndex(index)];
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<P> P readIfNeeded(int index) {
|
||||
Object v = values[checkIndex(index)];
|
||||
if (v != null) {
|
||||
return (P)v;
|
||||
} else {
|
||||
P p = (P)resolve(poolbuf, tag(index), offset(index));
|
||||
values[index] = p;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
int tag(int index) {
|
||||
return poolbuf.elems[offset(index) - 1];
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,506 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.jvm;
|
||||
|
||||
import com.sun.tools.javac.code.Kinds.Kind;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.PackageSymbol;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.jvm.ClassWriter.PoolOverflow;
|
||||
import com.sun.tools.javac.jvm.ClassWriter.StringOverflow;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.Dynamic;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.Dynamic.BsmKey;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
|
||||
import com.sun.tools.javac.util.ByteBuffer;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.sun.tools.javac.code.Kinds.Kind.TYP;
|
||||
import static com.sun.tools.javac.code.TypeTag.ARRAY;
|
||||
import static com.sun.tools.javac.code.TypeTag.CLASS;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_MethodType;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.externalize;
|
||||
|
||||
/**
|
||||
* Pool interface towards {@code ClassWriter}. Exposes methods to encode and write javac entities
|
||||
* into the constant pool.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public class PoolWriter {
|
||||
|
||||
/** Max number of constant pool entries. */
|
||||
public static final int MAX_ENTRIES = 0xFFFF;
|
||||
|
||||
/** Max number of char in a string constant. */
|
||||
public static final int MAX_STRING_LENGTH = 0xFFFF;
|
||||
|
||||
private static final int POOL_BUF_SIZE = 0x7fff;
|
||||
|
||||
private final Types types;
|
||||
|
||||
private final Names names;
|
||||
|
||||
/** Pool helper **/
|
||||
final WriteablePoolHelper pool;
|
||||
|
||||
/** Sole signature generator */
|
||||
final SharedSignatureGenerator signatureGen;
|
||||
|
||||
/** The inner classes to be written, as an ordered set (enclosing first). */
|
||||
LinkedHashSet<ClassSymbol> innerClasses = new LinkedHashSet<>();
|
||||
|
||||
/** The list of entries in the BootstrapMethods attribute. */
|
||||
Map<BsmKey, Integer> bootstrapMethods = new LinkedHashMap<>();
|
||||
|
||||
public PoolWriter(Types types, Names names) {
|
||||
this.types = types;
|
||||
this.names = names;
|
||||
this.signatureGen = new SharedSignatureGenerator(types);
|
||||
this.pool = new WriteablePoolHelper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a class symbol into the pool and return its index.
|
||||
*/
|
||||
int putClass(ClassSymbol csym) {
|
||||
return putClass(csym.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a type into the pool and return its index. The type could be either a class, a type variable
|
||||
* or an array type.
|
||||
*/
|
||||
int putClass(Type t) {
|
||||
return pool.writeIfNeeded(types.erasure(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a member reference into the constant pool. Valid members are either field or method symbols.
|
||||
*/
|
||||
int putMember(Symbol s) {
|
||||
return pool.writeIfNeeded(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a dynamic reference into the constant pool and return its index.
|
||||
*/
|
||||
int putDynamic(DynamicMethodSymbol d) {
|
||||
return pool.writeIfNeeded(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a field or method descriptor into the constant pool and return its index.
|
||||
*/
|
||||
int putDescriptor(Type t) {
|
||||
return putName(typeSig(types.erasure(t)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a field or method descriptor into the constant pool and return its index.
|
||||
*/
|
||||
int putDescriptor(Symbol s) {
|
||||
return putDescriptor(descriptorType(s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a signature (see {@code Signature} attribute in JVMS 4.4) into the constant pool and
|
||||
* return its index.
|
||||
*/
|
||||
int putSignature(Symbol s) {
|
||||
if (s.kind == TYP) {
|
||||
return putName(classSig(s.type));
|
||||
} else {
|
||||
return putName(typeSig(s.type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a constant value into the pool and return its index. Supported values are int, float, long,
|
||||
* double and String.
|
||||
*/
|
||||
int putConstant(Object o) {
|
||||
if (o instanceof Integer) {
|
||||
return putConstant(LoadableConstant.Int((int)o));
|
||||
} else if (o instanceof Float) {
|
||||
return putConstant(LoadableConstant.Float((float)o));
|
||||
} else if (o instanceof Long) {
|
||||
return putConstant(LoadableConstant.Long((long)o));
|
||||
} else if (o instanceof Double) {
|
||||
return putConstant(LoadableConstant.Double((double)o));
|
||||
} else if (o instanceof String) {
|
||||
return putConstant(LoadableConstant.String((String)o));
|
||||
} else {
|
||||
throw new AssertionError("unexpected constant: " + o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a constant into the pool and return its index.
|
||||
*/
|
||||
int putConstant(LoadableConstant c) {
|
||||
switch (c.poolTag()) {
|
||||
case CONSTANT_Class:
|
||||
return putClass((Type)c);
|
||||
case CONSTANT_MethodType:
|
||||
return pool.writeIfNeeded(types.erasure((Type)c));
|
||||
default:
|
||||
return pool.writeIfNeeded(c);
|
||||
}
|
||||
}
|
||||
|
||||
int putName(Name name) {
|
||||
return pool.writeIfNeeded(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a name and type pair into the pool and returns its index.
|
||||
*/
|
||||
int putNameAndType(Symbol s) {
|
||||
return pool.writeIfNeeded(new NameAndType(s.name, descriptorType(s)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a package entry into the pool and returns its index.
|
||||
*/
|
||||
int putPackage(PackageSymbol pkg) {
|
||||
return pool.writeIfNeeded(pkg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a module entry into the pool and returns its index.
|
||||
*/
|
||||
int putModule(ModuleSymbol mod) {
|
||||
return pool.writeIfNeeded(mod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter an inner class into the `innerClasses' set.
|
||||
*/
|
||||
void enterInner(ClassSymbol c) {
|
||||
if (c.type.isCompound()) {
|
||||
throw new AssertionError("Unexpected intersection type: " + c.type);
|
||||
}
|
||||
c.complete();
|
||||
if (c.owner.enclClass() != null && !innerClasses.contains(c)) {
|
||||
enterInner(c.owner.enclClass());
|
||||
innerClasses.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Utf8 entry representing a descriptor for given (member) symbol.
|
||||
*/
|
||||
private Type descriptorType(Symbol s) {
|
||||
return s.kind == Kind.MTH ? s.externalType(types) : s.erasure(types);
|
||||
}
|
||||
|
||||
private int makeBoostrapEntry(Dynamic dynamic) {
|
||||
BsmKey bsmKey = dynamic.bsmKey(types);
|
||||
|
||||
// Figure out the index for existing BSM; create a new BSM if no key
|
||||
Integer index = bootstrapMethods.get(bsmKey);
|
||||
if (index == null) {
|
||||
index = bootstrapMethods.size();
|
||||
bootstrapMethods.put(bsmKey, index);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write pool contents into given byte buffer.
|
||||
*/
|
||||
void writePool(OutputStream out) throws IOException, PoolOverflow {
|
||||
if (pool.overflowString != null) {
|
||||
throw new StringOverflow(pool.overflowString);
|
||||
}
|
||||
int size = size();
|
||||
if (size > MAX_ENTRIES) {
|
||||
throw new PoolOverflow();
|
||||
}
|
||||
out.write(size >> 8);
|
||||
out.write(size);
|
||||
out.write(pool.poolbuf.elems, 0, pool.poolbuf.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature Generation
|
||||
*/
|
||||
class SharedSignatureGenerator extends Types.SignatureGenerator {
|
||||
|
||||
/**
|
||||
* An output buffer for type signatures.
|
||||
*/
|
||||
ByteBuffer sigbuf = new ByteBuffer();
|
||||
|
||||
SharedSignatureGenerator(Types types) {
|
||||
super(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assemble signature of given type in string buffer.
|
||||
* Check for uninitialized types before calling the general case.
|
||||
*/
|
||||
@Override
|
||||
public void assembleSig(Type type) {
|
||||
switch (type.getTag()) {
|
||||
case UNINITIALIZED_THIS:
|
||||
case UNINITIALIZED_OBJECT:
|
||||
// we don't yet have a spec for uninitialized types in the
|
||||
// local variable table
|
||||
assembleSig(types.erasure(((UninitializedType)type).qtype));
|
||||
break;
|
||||
default:
|
||||
super.assembleSig(type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(char ch) {
|
||||
sigbuf.appendByte(ch);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(byte[] ba) {
|
||||
sigbuf.appendBytes(ba);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(Name name) {
|
||||
sigbuf.appendName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void classReference(ClassSymbol c) {
|
||||
enterInner(c);
|
||||
}
|
||||
|
||||
protected void reset() {
|
||||
sigbuf.reset();
|
||||
}
|
||||
|
||||
protected Name toName() {
|
||||
return sigbuf.toName(names);
|
||||
}
|
||||
}
|
||||
|
||||
class WriteablePoolHelper {
|
||||
|
||||
/** Pool entries. */
|
||||
private final Map<Object, Integer> keysToPos = new HashMap<>(64);
|
||||
|
||||
final ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE);
|
||||
|
||||
int currentIndex = 1;
|
||||
|
||||
ArrayDeque<PoolConstant> todo = new ArrayDeque<>();
|
||||
|
||||
String overflowString = null;
|
||||
|
||||
private <P extends PoolConstant> int writeIfNeeded(P p) {
|
||||
Object key = p.poolKey(types);
|
||||
Integer index = keysToPos.get(key);
|
||||
if (index == null) {
|
||||
keysToPos.put(key, index = currentIndex++);
|
||||
boolean first = todo.isEmpty();
|
||||
todo.addLast(p);
|
||||
if (first) {
|
||||
while (!todo.isEmpty()) {
|
||||
writeConstant(todo.peekFirst());
|
||||
todo.removeFirst();
|
||||
}
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void writeConstant(PoolConstant c) {
|
||||
int tag = c.poolTag();
|
||||
switch (tag) {
|
||||
case ClassFile.CONSTANT_Class: {
|
||||
Type ct = (Type)c;
|
||||
Name name = ct.hasTag(ARRAY) ?
|
||||
typeSig(ct) :
|
||||
names.fromUtf(externalize(ct.tsym.flatName()));
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendChar(putName(name));
|
||||
if (ct.hasTag(CLASS)) {
|
||||
enterInner((ClassSymbol)ct.tsym);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ClassFile.CONSTANT_Utf8: {
|
||||
Name name = (Name)c;
|
||||
poolbuf.appendByte(tag);
|
||||
byte[] bs = name.toUtf();
|
||||
poolbuf.appendChar(bs.length);
|
||||
poolbuf.appendBytes(bs, 0, bs.length);
|
||||
if (overflowString == null && bs.length > MAX_STRING_LENGTH) {
|
||||
//report error only once
|
||||
overflowString = new String(bs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ClassFile.CONSTANT_InterfaceMethodref:
|
||||
case ClassFile.CONSTANT_Methodref:
|
||||
case ClassFile.CONSTANT_Fieldref: {
|
||||
Symbol sym = (Symbol)c;
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendChar(putClass((ClassSymbol)sym.owner));
|
||||
poolbuf.appendChar(putNameAndType(sym));
|
||||
break;
|
||||
}
|
||||
case ClassFile.CONSTANT_Package: {
|
||||
PackageSymbol pkg = (PackageSymbol)c;
|
||||
Name pkgName = names.fromUtf(externalize(pkg.flatName()));
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendChar(putName(pkgName));
|
||||
break;
|
||||
}
|
||||
case ClassFile.CONSTANT_Module: {
|
||||
ModuleSymbol mod = (ModuleSymbol)c;
|
||||
int modName = putName(mod.name);
|
||||
poolbuf.appendByte(mod.poolTag());
|
||||
poolbuf.appendChar(modName);
|
||||
break;
|
||||
}
|
||||
case ClassFile.CONSTANT_Integer:
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendInt((int)((BasicConstant)c).data);
|
||||
break;
|
||||
case ClassFile.CONSTANT_Float:
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendFloat((float)((BasicConstant)c).data);
|
||||
break;
|
||||
case ClassFile.CONSTANT_Long:
|
||||
currentIndex++;
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendLong((long)((BasicConstant)c).data);
|
||||
break;
|
||||
case ClassFile.CONSTANT_Double:
|
||||
currentIndex++;
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendDouble((double)((BasicConstant)c).data);
|
||||
break;
|
||||
case ClassFile.CONSTANT_MethodHandle: {
|
||||
MethodHandleSymbol h = (MethodHandleSymbol)c;
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendByte(h.referenceKind());
|
||||
poolbuf.appendChar(putMember(h.baseSymbol()));
|
||||
break;
|
||||
}
|
||||
case ClassFile.CONSTANT_MethodType: {
|
||||
Type.MethodType mt = (Type.MethodType)c;
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendChar(putDescriptor(mt.baseType()));
|
||||
break;
|
||||
}
|
||||
case ClassFile.CONSTANT_String: {
|
||||
Name utf = names.fromString((String)((BasicConstant)c).data);
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendChar(putName(utf));
|
||||
break;
|
||||
}
|
||||
case ClassFile.CONSTANT_NameandType: {
|
||||
NameAndType nt = (NameAndType)c;
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendChar(putName(nt.name));
|
||||
poolbuf.appendChar(putDescriptor(nt.type));
|
||||
break;
|
||||
}
|
||||
case ClassFile.CONSTANT_InvokeDynamic: {
|
||||
DynamicMethodSymbol d = (DynamicMethodSymbol)c;
|
||||
poolbuf.appendByte(tag);
|
||||
poolbuf.appendChar(makeBoostrapEntry(d));
|
||||
poolbuf.appendChar(putNameAndType(d));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new AssertionError("Unexpected constant tag: " + tag);
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
keysToPos.clear();
|
||||
currentIndex = 1;
|
||||
todo.clear();
|
||||
overflowString = null;
|
||||
poolbuf.reset();
|
||||
}
|
||||
}
|
||||
|
||||
int size() {
|
||||
return pool.currentIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return signature of given type
|
||||
*/
|
||||
private Name typeSig(Type type) {
|
||||
signatureGen.reset();
|
||||
signatureGen.assembleSig(type);
|
||||
return signatureGen.toName();
|
||||
}
|
||||
|
||||
private Name classSig(Type t) {
|
||||
signatureGen.reset();
|
||||
List<Type> typarams = t.getTypeArguments();
|
||||
if (typarams.nonEmpty()) {
|
||||
signatureGen.assembleParamsSig(typarams);
|
||||
}
|
||||
signatureGen.assembleSig(types.supertype(t));
|
||||
for (Type i : types.interfaces(t))
|
||||
signatureGen.assembleSig(i);
|
||||
return signatureGen.toName();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
innerClasses.clear();
|
||||
bootstrapMethods.clear();
|
||||
pool.reset();
|
||||
}
|
||||
}
|
@ -26,7 +26,9 @@
|
||||
package com.sun.tools.javac.jvm;
|
||||
|
||||
import com.sun.tools.javac.code.*;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.comp.Resolve;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.TreeInfo;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
@ -222,7 +224,7 @@ public abstract class StringConcat {
|
||||
|
||||
private JCDiagnostic.DiagnosticPosition newStringBuilder(JCTree tree) {
|
||||
JCDiagnostic.DiagnosticPosition pos = tree.pos();
|
||||
gen.getCode().emitop2(new_, gen.makeRef(pos, syms.stringBuilderType));
|
||||
gen.getCode().emitop2(new_, gen.makeRef(pos, syms.stringBuilderType), syms.stringBuilderType);
|
||||
gen.getCode().emitop0(dup);
|
||||
gen.callMethod(pos, syms.stringBuilderType, names.init, List.nil(), false);
|
||||
return pos;
|
||||
@ -378,10 +380,9 @@ public abstract class StringConcat {
|
||||
|
||||
Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcat,
|
||||
syms.noSymbol,
|
||||
ClassFile.REF_invokeStatic,
|
||||
(Symbol.MethodSymbol)bsm,
|
||||
((MethodSymbol)bsm).asHandle(),
|
||||
indyType,
|
||||
List.nil().toArray());
|
||||
List.nil().toArray(new LoadableConstant[0]));
|
||||
|
||||
Items.Item item = gen.getItems().makeDynamicItem(dynSym);
|
||||
item.invoke();
|
||||
@ -416,7 +417,7 @@ public abstract class StringConcat {
|
||||
|
||||
StringBuilder recipe = new StringBuilder(t.size());
|
||||
ListBuffer<Type> dynamicArgs = new ListBuffer<>();
|
||||
ListBuffer<Object> staticArgs = new ListBuffer<>();
|
||||
ListBuffer<LoadableConstant> staticArgs = new ListBuffer<>();
|
||||
|
||||
for (JCTree arg : t) {
|
||||
Object constVal = arg.type.constValue();
|
||||
@ -431,7 +432,7 @@ public abstract class StringConcat {
|
||||
String a = arg.type.stringValue();
|
||||
if (a.indexOf(TAG_CONST) != -1 || a.indexOf(TAG_ARG) != -1) {
|
||||
recipe.append(TAG_CONST);
|
||||
staticArgs.add(a);
|
||||
staticArgs.add(LoadableConstant.String(a));
|
||||
} else {
|
||||
recipe.append(a);
|
||||
}
|
||||
@ -463,7 +464,7 @@ public abstract class StringConcat {
|
||||
}
|
||||
|
||||
/** Produce the actual invokedynamic call to StringConcatFactory */
|
||||
private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, String recipe, List<Object> staticArgs, List<Type> dynamicArgTypes) {
|
||||
private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, String recipe, List<LoadableConstant> staticArgs, List<Type> dynamicArgTypes) {
|
||||
Type.MethodType indyType = new Type.MethodType(dynamicArgTypes,
|
||||
type,
|
||||
List.nil(),
|
||||
@ -474,8 +475,8 @@ public abstract class StringConcat {
|
||||
make.at(pos);
|
||||
|
||||
ListBuffer<Type> constTypes = new ListBuffer<>();
|
||||
ListBuffer<Object> constants = new ListBuffer<>();
|
||||
for (Object t : staticArgs) {
|
||||
ListBuffer<LoadableConstant> constants = new ListBuffer<>();
|
||||
for (LoadableConstant t : staticArgs) {
|
||||
constants.add(t);
|
||||
constTypes.add(syms.stringType);
|
||||
}
|
||||
@ -495,10 +496,10 @@ public abstract class StringConcat {
|
||||
|
||||
Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcatWithConstants,
|
||||
syms.noSymbol,
|
||||
ClassFile.REF_invokeStatic,
|
||||
(Symbol.MethodSymbol)bsm,
|
||||
((MethodSymbol)bsm).asHandle(),
|
||||
indyType,
|
||||
List.<Object>of(recipe).appendList(constants).toArray());
|
||||
List.of(LoadableConstant.String(recipe))
|
||||
.appendList(constants).toArray(new LoadableConstant[constants.size()]));
|
||||
|
||||
Items.Item item = gen.getItems().makeDynamicItem(dynSym);
|
||||
item.invoke();
|
||||
|
@ -2164,6 +2164,11 @@ compiler.misc.bad.const.pool.entry=\
|
||||
bad constant pool entry in {0}\n\
|
||||
expected {1} at index {2}
|
||||
|
||||
# 0: file name, 1: number (constant pool index), 2: number (constant pool size)
|
||||
compiler.misc.bad.const.pool.index=\
|
||||
bad constant pool index in {0}\n\
|
||||
index {1} is not within pool size {2}.
|
||||
|
||||
# 0: file name, 1: message segment
|
||||
compiler.misc.bad.class.file.header=\
|
||||
bad class file: {0}\n\
|
||||
|
@ -147,6 +147,90 @@ public class ByteBuffer {
|
||||
appendBytes(name.getByteArray(), name.getByteOffset(), name.getByteLength());
|
||||
}
|
||||
|
||||
/** Append the content of a given input stream.
|
||||
*/
|
||||
public void appendStream(InputStream is) throws IOException {
|
||||
try {
|
||||
int start = length;
|
||||
int initialSize = is.available();
|
||||
elems = ArrayUtils.ensureCapacity(elems, length + initialSize);
|
||||
int r = is.read(elems, start, initialSize);
|
||||
int bp = start;
|
||||
while (r != -1) {
|
||||
bp += r;
|
||||
elems = ArrayUtils.ensureCapacity(elems, bp);
|
||||
r = is.read(elems, bp, elems.length - bp);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
/* Ignore any errors, as this stream may have already
|
||||
* thrown a related exception which is the one that
|
||||
* should be reported.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Extract an integer at position bp from elems.
|
||||
*/
|
||||
public int getInt(int bp) {
|
||||
return
|
||||
((elems[bp] & 0xFF) << 24) +
|
||||
((elems[bp+1] & 0xFF) << 16) +
|
||||
((elems[bp+2] & 0xFF) << 8) +
|
||||
(elems[bp+3] & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
/** Extract a long integer at position bp from elems.
|
||||
*/
|
||||
public long getLong(int bp) {
|
||||
DataInputStream elemsin =
|
||||
new DataInputStream(new ByteArrayInputStream(elems, bp, 8));
|
||||
try {
|
||||
return elemsin.readLong();
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Extract a float at position bp from elems.
|
||||
*/
|
||||
public float getFloat(int bp) {
|
||||
DataInputStream elemsin =
|
||||
new DataInputStream(new ByteArrayInputStream(elems, bp, 4));
|
||||
try {
|
||||
return elemsin.readFloat();
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Extract a double at position bp from elems.
|
||||
*/
|
||||
public double getDouble(int bp) {
|
||||
DataInputStream elemsin =
|
||||
new DataInputStream(new ByteArrayInputStream(elems, bp, 8));
|
||||
try {
|
||||
return elemsin.readDouble();
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Extract a character at position bp from elems.
|
||||
*/
|
||||
public char getChar(int bp) {
|
||||
return
|
||||
(char)(((elems[bp] & 0xFF) << 8) + (elems[bp+1] & 0xFF));
|
||||
}
|
||||
|
||||
public byte getByte(int bp) {
|
||||
return elems[bp];
|
||||
}
|
||||
|
||||
/** Reset to zero length.
|
||||
*/
|
||||
public void reset() {
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package com.sun.tools.javac.util;
|
||||
|
||||
import com.sun.tools.javac.jvm.ClassFile;
|
||||
import com.sun.tools.javac.jvm.PoolConstant;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
|
||||
/** An abstraction for internal compiler strings. They are stored in
|
||||
@ -36,7 +38,7 @@ import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
* This code and its internal interfaces are subject to change or
|
||||
* deletion without notice.</b>
|
||||
*/
|
||||
public abstract class Name implements javax.lang.model.element.Name {
|
||||
public abstract class Name implements javax.lang.model.element.Name, PoolConstant {
|
||||
|
||||
public final Table table;
|
||||
|
||||
@ -52,6 +54,11 @@ public abstract class Name implements javax.lang.model.element.Name {
|
||||
return toString().equals(cs.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int poolTag() {
|
||||
return ClassFile.CONSTANT_Utf8;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -188,6 +195,14 @@ public abstract class Name implements javax.lang.model.element.Name {
|
||||
*/
|
||||
public abstract int getByteOffset();
|
||||
|
||||
public interface NameMapper<X> {
|
||||
X map(byte[] bytes, int offset, int len);
|
||||
}
|
||||
|
||||
public <X> X map(NameMapper<X> mapper) {
|
||||
return mapper.map(getByteArray(), getByteOffset(), getByteLength());
|
||||
}
|
||||
|
||||
/** An abstraction for the hash table used to create unique Name instances.
|
||||
*/
|
||||
public static abstract class Table {
|
||||
|
@ -59,7 +59,7 @@ public class AnnotatedExtendsTest {
|
||||
.classes(classPath.toString())
|
||||
.run()
|
||||
.getOutput(Task.OutputKind.DIRECT);
|
||||
if (!javapOut.contains("0: #21(): CLASS_EXTENDS, type_index=65535"))
|
||||
if (!javapOut.contains("0: #22(): CLASS_EXTENDS, type_index=65535"))
|
||||
throw new AssertionError("Expected output missing: " + javapOut);
|
||||
}
|
||||
}
|
@ -74,14 +74,14 @@ public class BridgeShouldHaveNoInteriorAnnotationsTest
|
||||
// Expected output can't be directly encoded into NestedLambdasCastedTest !!!
|
||||
static class OutputExpectedOnceHolder {
|
||||
public String[] outputs = {
|
||||
"0: #61(): CAST, offset=1, type_index=0, location=[TYPE_ARGUMENT(0)]",
|
||||
"1: #61(): LOCAL_VARIABLE, {start_pc=5, length=2, index=1}, location=[TYPE_ARGUMENT(0)]",
|
||||
"0: #120(): CAST, offset=1, type_index=0, location=[TYPE_ARGUMENT(0)]",
|
||||
"1: #120(): LOCAL_VARIABLE, {start_pc=5, length=2, index=1}, location=[TYPE_ARGUMENT(0)]",
|
||||
};
|
||||
}
|
||||
|
||||
static class OutputExpectedTwiceHolder {
|
||||
public String[] outputs = {
|
||||
"0: #61(): METHOD_RETURN, location=[TYPE_ARGUMENT(0)]",
|
||||
"0: #120(): METHOD_RETURN, location=[TYPE_ARGUMENT(0)]",
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -53,10 +53,10 @@ public class NestedLambdasCastedTest {
|
||||
"private static strictfp void lambda$main$2();",
|
||||
"private static strictfp void lambda$main$1();",
|
||||
"private static strictfp void lambda$main$0();",
|
||||
"0: #62(#63=s#64): CAST, offset=5, type_index=0",
|
||||
"0: #62(#63=s#69): CAST, offset=5, type_index=0",
|
||||
"0: #62(#63=s#72): CAST, offset=5, type_index=0",
|
||||
"0: #62(#63=s#75): CAST, offset=5, type_index=0"
|
||||
"0: #111(#112=s#113): CAST, offset=5, type_index=0",
|
||||
"0: #111(#112=s#119): CAST, offset=5, type_index=0",
|
||||
"0: #111(#112=s#122): CAST, offset=5, type_index=0",
|
||||
"0: #111(#112=s#125): CAST, offset=5, type_index=0"
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@ compiler.err.unsupported.cross.fp.lit # Scanner: host system d
|
||||
compiler.misc.bad.class.signature # bad class file
|
||||
compiler.misc.bad.const.pool.tag # bad class file
|
||||
compiler.misc.bad.const.pool.tag.at # bad class file
|
||||
compiler.misc.bad.const.pool.index # bad class file
|
||||
compiler.misc.bad.constant.range # bad class file
|
||||
compiler.misc.bad.constant.value # bad class file
|
||||
compiler.misc.bad.enclosing.class # bad class file
|
||||
|
@ -61,6 +61,7 @@ import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
||||
@ -190,7 +191,7 @@ public class TestBootstrapMethodsCount {
|
||||
Symbol oldSym = ident.sym;
|
||||
if (!oldSym.isConstructor()) {
|
||||
ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name,
|
||||
oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]);
|
||||
oldSym.owner, bsm.asHandle(), oldSym.type, new LoadableConstant[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -60,26 +60,23 @@ import com.sun.tools.classfile.Instruction;
|
||||
import com.sun.tools.classfile.LineNumberTable_attribute;
|
||||
import com.sun.tools.classfile.Method;
|
||||
|
||||
import com.sun.tools.javac.api.JavacTaskImpl;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Type.ClassType;
|
||||
import com.sun.tools.javac.code.Type.MethodType;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.jvm.Pool;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
import combo.ComboParameter;
|
||||
import combo.ComboTask;
|
||||
import combo.ComboTestHelper;
|
||||
import combo.ComboInstance;
|
||||
import combo.ComboTask.Result;
|
||||
|
||||
import static com.sun.tools.javac.jvm.ClassFile.*;
|
||||
|
||||
public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
|
||||
|
||||
enum StaticArgumentKind implements ComboParameter {
|
||||
@ -168,21 +165,24 @@ public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
|
||||
|
||||
abstract boolean check(CPInfo cpInfo) throws Exception;
|
||||
|
||||
Object getValue(Symtab syms, Names names, Types types) {
|
||||
LoadableConstant getValue(Symtab syms) {
|
||||
switch (this) {
|
||||
case STRING:
|
||||
return LoadableConstant.String((String)value);
|
||||
case INTEGER:
|
||||
return LoadableConstant.Int((Integer)value);
|
||||
case LONG:
|
||||
return LoadableConstant.Long((Long)value);
|
||||
case FLOAT:
|
||||
return LoadableConstant.Float((Float)value);
|
||||
case DOUBLE:
|
||||
return value;
|
||||
return LoadableConstant.Double((Double)value);
|
||||
case CLASS:
|
||||
return syms.stringType.tsym;
|
||||
return (ClassType)syms.stringType;
|
||||
case METHOD_HANDLE:
|
||||
return new Pool.MethodHandle(REF_invokeVirtual,
|
||||
syms.arrayCloneMethod, types);
|
||||
return syms.arrayCloneMethod.asHandle();
|
||||
case METHOD_TYPE:
|
||||
return syms.arrayCloneMethod.type;
|
||||
return ((MethodType)syms.arrayCloneMethod.type);
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
@ -394,7 +394,7 @@ public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
|
||||
|
||||
class Indifier extends TreeScanner<Void, Void> implements TaskListener {
|
||||
|
||||
MethodSymbol bsm;
|
||||
MethodHandleSymbol bsm;
|
||||
Symtab syms;
|
||||
Names names;
|
||||
Types types;
|
||||
@ -424,12 +424,12 @@ public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
|
||||
JCIdent ident = (JCIdent)apply.meth;
|
||||
Symbol oldSym = ident.sym;
|
||||
if (!oldSym.isConstructor()) {
|
||||
Object[] staticArgs = new Object[arity.arity];
|
||||
LoadableConstant[] staticArgs = new LoadableConstant[arity.arity];
|
||||
for (int i = 0; i < arity.arity ; i++) {
|
||||
staticArgs[i] = saks[i].getValue(syms, names, types);
|
||||
staticArgs[i] = saks[i].getValue(syms);
|
||||
}
|
||||
ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name,
|
||||
oldSym.owner, REF_invokeStatic, bsm, oldSym.type, staticArgs);
|
||||
oldSym.owner, bsm, oldSym.type, staticArgs);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -438,7 +438,7 @@ public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
|
||||
public Void visitMethod(MethodTree node, Void p) {
|
||||
super.visitMethod(node, p);
|
||||
if (node.getName().toString().equals("bsm")) {
|
||||
bsm = ((JCMethodDecl)node).sym;
|
||||
bsm = ((JCMethodDecl)node).sym.asHandle();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.name.mismatch: mod/module-info, <error>))
|
||||
- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.bad.const.pool.index: module-info.class, 15, 10))
|
||||
1 error
|
||||
|
@ -90,8 +90,8 @@ public class CheckNestmateAttrs {
|
||||
"NestHost: class CheckNestmateAttrs",
|
||||
"0: aload_0",
|
||||
"1: getfield #1 // Field this$1:LCheckNestmateAttrs$Inner;",
|
||||
"4: getfield #3 // Field CheckNestmateAttrs$Inner.this$0:LCheckNestmateAttrs;",
|
||||
"7: invokevirtual #4 // Method CheckNestmateAttrs.test:()V",
|
||||
"4: getfield #13 // Field CheckNestmateAttrs$Inner.this$0:LCheckNestmateAttrs;",
|
||||
"7: invokevirtual #19 // Method CheckNestmateAttrs.test:()V",
|
||||
"10: return"
|
||||
});
|
||||
|
||||
|
@ -49,50 +49,50 @@ public class AnnoTest {
|
||||
|
||||
expect(out,
|
||||
"RuntimeVisibleAnnotations:\n" +
|
||||
" 0: #18(#19=B#20)\n" +
|
||||
" 0: #21(#22=B#23)\n" +
|
||||
" AnnoTest$ByteAnno(\n" +
|
||||
" value=(byte) 42\n" +
|
||||
" )\n" +
|
||||
" 1: #23(#19=S#24)\n" +
|
||||
" 1: #24(#22=S#25)\n" +
|
||||
" AnnoTest$ShortAnno(\n" +
|
||||
" value=(short) 3\n" +
|
||||
" )");
|
||||
expect(out,
|
||||
"RuntimeInvisibleAnnotations:\n" +
|
||||
" 0: #28(#19=[J#29,J#31,J#33,J#35,J#37])\n" +
|
||||
" 0: #27(#22=[J#28,J#30,J#32,J#34,J#36])\n" +
|
||||
" AnnoTest$ArrayAnno(\n" +
|
||||
" value=[1l,2l,3l,4l,5l]\n" +
|
||||
" )\n" +
|
||||
" 1: #41(#19=Z#42)\n" +
|
||||
" 1: #38(#22=Z#39)\n" +
|
||||
" AnnoTest$BooleanAnno(\n" +
|
||||
" value=false\n" +
|
||||
" )\n" +
|
||||
" 2: #45(#46=c#47)\n" +
|
||||
" 2: #40(#41=c#42)\n" +
|
||||
" AnnoTest$ClassAnno(\n" +
|
||||
" type=class Ljava/lang/Object;\n" +
|
||||
" )\n" +
|
||||
" 3: #50(#51=e#52.#53)\n" +
|
||||
" 3: #43(#44=e#45.#46)\n" +
|
||||
" AnnoTest$EnumAnno(\n" +
|
||||
" kind=Ljavax/lang/model/element/ElementKind;.PACKAGE\n" +
|
||||
" )\n" +
|
||||
" 4: #56(#19=I#57)\n" +
|
||||
" 4: #47(#22=I#48)\n" +
|
||||
" AnnoTest$IntAnno(\n" +
|
||||
" value=2\n" +
|
||||
" )\n" +
|
||||
" 5: #60()\n" +
|
||||
" 5: #49()\n" +
|
||||
" AnnoTest$IntDefaultAnno\n" +
|
||||
" 6: #63(#64=s#65)\n" +
|
||||
" 6: #50(#51=s#52)\n" +
|
||||
" AnnoTest$NameAnno(\n" +
|
||||
" name=\"NAME\"\n" +
|
||||
" )\n" +
|
||||
" 7: #68(#69=D#70,#72=F#73)\n" +
|
||||
" 7: #53(#54=D#55,#57=F#58)\n" +
|
||||
" AnnoTest$MultiAnno(\n" +
|
||||
" d=3.14159d\n" +
|
||||
" f=2.71828f\n" +
|
||||
" )\n" +
|
||||
" 8: #76()\n" +
|
||||
" 8: #59()\n" +
|
||||
" AnnoTest$SimpleAnno\n" +
|
||||
" 9: #79(#19=@#56(#19=I#80))\n" +
|
||||
" 9: #60(#22=@#47(#22=I#61))\n" +
|
||||
" AnnoTest$AnnoAnno(\n" +
|
||||
" value=@AnnoTest$IntAnno(\n" +
|
||||
" value=5\n" +
|
||||
@ -100,7 +100,7 @@ public class AnnoTest {
|
||||
" )");
|
||||
expect(out,
|
||||
"RuntimeInvisibleTypeAnnotations:\n" +
|
||||
" 0: #84(): CLASS_EXTENDS, type_index=0\n" +
|
||||
" 0: #63(): CLASS_EXTENDS, type_index=0\n" +
|
||||
" AnnoTest$TypeAnno");
|
||||
|
||||
if (errors > 0)
|
||||
|
@ -51,7 +51,7 @@ public class AnnotationDefaultNewlineTest {
|
||||
|
||||
private static final String ExpectedSubstring =
|
||||
" AnnotationDefault:\n" +
|
||||
" default_value: I#7\n";
|
||||
" default_value: I#9\n";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ToolBox tb = new ToolBox();
|
||||
|
@ -62,11 +62,11 @@ public class InvisibleParameterAnnotationsTest {
|
||||
" RuntimeVisibleParameterAnnotations:\n" +
|
||||
" parameter 0:\n" +
|
||||
" parameter 1:\n" +
|
||||
" 0: #16()\n" +
|
||||
" 0: #14()\n" +
|
||||
" Sample$VisAnno\n" +
|
||||
" RuntimeInvisibleParameterAnnotations:\n" +
|
||||
" parameter 0:\n" +
|
||||
" 0: #18()\n" +
|
||||
" 0: #16()\n" +
|
||||
" Sample$InvisAnno\n" +
|
||||
" parameter 1:";
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user