8306457: Classfile API components implementations should not be exposed
Reviewed-by: asotona
This commit is contained in:
parent
f4f5542f8d
commit
3c9ec26370
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2023, 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
|
||||
@ -19,79 +19,19 @@
|
||||
* 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 jdk.internal.classfile.components;
|
||||
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.constant.DirectMethodHandleDesc;
|
||||
import java.lang.constant.DynamicCallSiteDesc;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.lang.constant.MethodHandleDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import jdk.internal.classfile.Annotation;
|
||||
import jdk.internal.classfile.AnnotationElement;
|
||||
import jdk.internal.classfile.AnnotationValue;
|
||||
import jdk.internal.classfile.ClassBuilder;
|
||||
import jdk.internal.classfile.ClassElement;
|
||||
import jdk.internal.classfile.ClassModel;
|
||||
import jdk.internal.classfile.ClassSignature;
|
||||
import jdk.internal.classfile.ClassTransform;
|
||||
import jdk.internal.classfile.Classfile;
|
||||
import jdk.internal.classfile.CodeBuilder;
|
||||
import jdk.internal.classfile.CodeElement;
|
||||
import jdk.internal.classfile.CodeModel;
|
||||
import jdk.internal.classfile.CodeTransform;
|
||||
import jdk.internal.classfile.FieldBuilder;
|
||||
import jdk.internal.classfile.FieldElement;
|
||||
import jdk.internal.classfile.FieldModel;
|
||||
import jdk.internal.classfile.FieldTransform;
|
||||
import jdk.internal.classfile.Interfaces;
|
||||
import jdk.internal.classfile.MethodBuilder;
|
||||
import jdk.internal.classfile.MethodElement;
|
||||
import jdk.internal.classfile.impl.TemporaryConstantPool;
|
||||
import jdk.internal.classfile.instruction.FieldInstruction;
|
||||
import jdk.internal.classfile.instruction.InvokeDynamicInstruction;
|
||||
import jdk.internal.classfile.instruction.InvokeInstruction;
|
||||
import jdk.internal.classfile.instruction.NewMultiArrayInstruction;
|
||||
import jdk.internal.classfile.instruction.NewObjectInstruction;
|
||||
import jdk.internal.classfile.instruction.NewReferenceArrayInstruction;
|
||||
import jdk.internal.classfile.instruction.TypeCheckInstruction;
|
||||
import jdk.internal.classfile.MethodModel;
|
||||
import jdk.internal.classfile.MethodSignature;
|
||||
import jdk.internal.classfile.MethodTransform;
|
||||
import jdk.internal.classfile.Signature;
|
||||
import jdk.internal.classfile.Superclass;
|
||||
import jdk.internal.classfile.TypeAnnotation;
|
||||
import jdk.internal.classfile.attribute.AnnotationDefaultAttribute;
|
||||
import jdk.internal.classfile.attribute.EnclosingMethodAttribute;
|
||||
import jdk.internal.classfile.attribute.ExceptionsAttribute;
|
||||
import jdk.internal.classfile.attribute.InnerClassInfo;
|
||||
import jdk.internal.classfile.attribute.InnerClassesAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleProvideInfo;
|
||||
import jdk.internal.classfile.attribute.NestHostAttribute;
|
||||
import jdk.internal.classfile.attribute.NestMembersAttribute;
|
||||
import jdk.internal.classfile.attribute.PermittedSubclassesAttribute;
|
||||
import jdk.internal.classfile.attribute.RecordAttribute;
|
||||
import jdk.internal.classfile.attribute.RecordComponentInfo;
|
||||
import jdk.internal.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.SignatureAttribute;
|
||||
import jdk.internal.classfile.constantpool.Utf8Entry;
|
||||
import jdk.internal.classfile.instruction.ExceptionCatch;
|
||||
import jdk.internal.classfile.instruction.LocalVariable;
|
||||
import jdk.internal.classfile.instruction.LocalVariableType;
|
||||
import jdk.internal.classfile.impl.Util;
|
||||
import jdk.internal.classfile.instruction.ConstantInstruction.LoadConstantInstruction;
|
||||
import jdk.internal.classfile.impl.ClassRemapperImpl;
|
||||
|
||||
/**
|
||||
* {@code ClassRemapper} is a {@link ClassTransform}, {@link FieldTransform},
|
||||
@ -109,7 +49,7 @@ import jdk.internal.classfile.instruction.ConstantInstruction.LoadConstantInstru
|
||||
* Arrays of reference types are always decomposed, mapped as the base reference
|
||||
* types and composed back to arrays.
|
||||
*/
|
||||
public sealed interface ClassRemapper extends ClassTransform {
|
||||
public sealed interface ClassRemapper extends ClassTransform permits ClassRemapperImpl {
|
||||
|
||||
/**
|
||||
* Creates new instance of {@code ClassRemapper} instructed with a class map.
|
||||
@ -135,25 +75,22 @@ public sealed interface ClassRemapper extends ClassTransform {
|
||||
/**
|
||||
* Access method to internal class mapping function.
|
||||
* @param desc source class
|
||||
* @return class target class
|
||||
* @return target class
|
||||
*/
|
||||
ClassDesc map(ClassDesc desc);
|
||||
|
||||
/**
|
||||
* Returns this {@code ClassRemapper} as {@link FieldTransform} instance
|
||||
* @return this {@code ClassRemapper} as {@link FieldTransform} instance
|
||||
* {@return this {@code ClassRemapper} as {@link FieldTransform} instance}
|
||||
*/
|
||||
FieldTransform asFieldTransform();
|
||||
|
||||
/**
|
||||
* Returns this {@code ClassRemapper} as {@link MethodTransform} instance
|
||||
* @return this {@code ClassRemapper} as {@link MethodTransform} instance
|
||||
* {@return this {@code ClassRemapper} as {@link MethodTransform} instance}
|
||||
*/
|
||||
MethodTransform asMethodTransform();
|
||||
|
||||
/**
|
||||
* Returns this {@code ClassRemapper} as {@link CodeTransform} instance
|
||||
* @return this {@code ClassRemapper} as {@link CodeTransform} instance
|
||||
* {@return this {@code ClassRemapper} as {@link CodeTransform} instance}
|
||||
*/
|
||||
CodeTransform asCodeTransform();
|
||||
|
||||
@ -166,330 +103,4 @@ public sealed interface ClassRemapper extends ClassTransform {
|
||||
return Classfile.build(map(clm.thisClass().asSymbol()),
|
||||
clb -> clm.forEachElement(resolve(clb).consumer()));
|
||||
}
|
||||
|
||||
record ClassRemapperImpl(Function<ClassDesc, ClassDesc> mapFunction) implements ClassRemapper {
|
||||
|
||||
@Override
|
||||
public void accept(ClassBuilder clb, ClassElement cle) {
|
||||
switch (cle) {
|
||||
case FieldModel fm ->
|
||||
clb.withField(fm.fieldName().stringValue(), map(
|
||||
fm.fieldTypeSymbol()), fb ->
|
||||
fm.forEachElement(asFieldTransform().resolve(fb).consumer()));
|
||||
case MethodModel mm ->
|
||||
clb.withMethod(mm.methodName().stringValue(), mapMethodDesc(
|
||||
mm.methodTypeSymbol()), mm.flags().flagsMask(), mb ->
|
||||
mm.forEachElement(asMethodTransform().resolve(mb).consumer()));
|
||||
case Superclass sc ->
|
||||
clb.withSuperclass(map(sc.superclassEntry().asSymbol()));
|
||||
case Interfaces ins ->
|
||||
clb.withInterfaceSymbols(Util.mappedList(ins.interfaces(), in ->
|
||||
map(in.asSymbol())));
|
||||
case SignatureAttribute sa ->
|
||||
clb.with(SignatureAttribute.of(mapClassSignature(sa.asClassSignature())));
|
||||
case InnerClassesAttribute ica ->
|
||||
clb.with(InnerClassesAttribute.of(ica.classes().stream().map(ici ->
|
||||
InnerClassInfo.of(map(ici.innerClass().asSymbol()),
|
||||
ici.outerClass().map(oc -> map(oc.asSymbol())),
|
||||
ici.innerName().map(Utf8Entry::stringValue),
|
||||
ici.flagsMask())).toList()));
|
||||
case EnclosingMethodAttribute ema ->
|
||||
clb.with(EnclosingMethodAttribute.of(map(ema.enclosingClass().asSymbol()),
|
||||
ema.enclosingMethodName().map(Utf8Entry::stringValue),
|
||||
ema.enclosingMethodTypeSymbol().map(this::mapMethodDesc)));
|
||||
case RecordAttribute ra ->
|
||||
clb.with(RecordAttribute.of(ra.components().stream()
|
||||
.map(this::mapRecordComponent).toList()));
|
||||
case ModuleAttribute ma ->
|
||||
clb.with(ModuleAttribute.of(ma.moduleName(), ma.moduleFlagsMask(),
|
||||
ma.moduleVersion().orElse(null),
|
||||
ma.requires(), ma.exports(), ma.opens(),
|
||||
ma.uses().stream().map(ce ->
|
||||
clb.constantPool().classEntry(map(ce.asSymbol()))).toList(),
|
||||
ma.provides().stream().map(mp ->
|
||||
ModuleProvideInfo.of(map(mp.provides().asSymbol()),
|
||||
mp.providesWith().stream().map(pw ->
|
||||
map(pw.asSymbol())).toList())).toList()));
|
||||
case NestHostAttribute nha ->
|
||||
clb.with(NestHostAttribute.of(map(nha.nestHost().asSymbol())));
|
||||
case NestMembersAttribute nma ->
|
||||
clb.with(NestMembersAttribute.ofSymbols(nma.nestMembers().stream()
|
||||
.map(nm -> map(nm.asSymbol())).toList()));
|
||||
case PermittedSubclassesAttribute psa ->
|
||||
clb.with(PermittedSubclassesAttribute.ofSymbols(
|
||||
psa.permittedSubclasses().stream().map(ps ->
|
||||
map(ps.asSymbol())).toList()));
|
||||
case RuntimeVisibleAnnotationsAttribute aa ->
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleAnnotationsAttribute aa ->
|
||||
clb.with(RuntimeInvisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute aa ->
|
||||
clb.with(RuntimeVisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute aa ->
|
||||
clb.with(RuntimeInvisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
default ->
|
||||
clb.with(cle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldTransform asFieldTransform() {
|
||||
return (FieldBuilder fb, FieldElement fe) -> {
|
||||
switch (fe) {
|
||||
case SignatureAttribute sa ->
|
||||
fb.with(SignatureAttribute.of(
|
||||
mapSignature(sa.asTypeSignature())));
|
||||
case RuntimeVisibleAnnotationsAttribute aa ->
|
||||
fb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleAnnotationsAttribute aa ->
|
||||
fb.with(RuntimeInvisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute aa ->
|
||||
fb.with(RuntimeVisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute aa ->
|
||||
fb.with(RuntimeInvisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
default ->
|
||||
fb.with(fe);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTransform asMethodTransform() {
|
||||
return (MethodBuilder mb, MethodElement me) -> {
|
||||
switch (me) {
|
||||
case AnnotationDefaultAttribute ada ->
|
||||
mb.with(AnnotationDefaultAttribute.of(
|
||||
mapAnnotationValue(ada.defaultValue())));
|
||||
case CodeModel com ->
|
||||
mb.transformCode(com, asCodeTransform());
|
||||
case ExceptionsAttribute ea ->
|
||||
mb.with(ExceptionsAttribute.ofSymbols(
|
||||
ea.exceptions().stream().map(ce ->
|
||||
map(ce.asSymbol())).toList()));
|
||||
case SignatureAttribute sa ->
|
||||
mb.with(SignatureAttribute.of(
|
||||
mapMethodSignature(sa.asMethodSignature())));
|
||||
case RuntimeVisibleAnnotationsAttribute aa ->
|
||||
mb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleAnnotationsAttribute aa ->
|
||||
mb.with(RuntimeInvisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeVisibleParameterAnnotationsAttribute paa ->
|
||||
mb.with(RuntimeVisibleParameterAnnotationsAttribute.of(
|
||||
paa.parameterAnnotations().stream()
|
||||
.map(this::mapAnnotations).toList()));
|
||||
case RuntimeInvisibleParameterAnnotationsAttribute paa ->
|
||||
mb.with(RuntimeInvisibleParameterAnnotationsAttribute.of(
|
||||
paa.parameterAnnotations().stream()
|
||||
.map(this::mapAnnotations).toList()));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute aa ->
|
||||
mb.with(RuntimeVisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute aa ->
|
||||
mb.with(RuntimeInvisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
default ->
|
||||
mb.with(me);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeTransform asCodeTransform() {
|
||||
return (CodeBuilder cob, CodeElement coe) -> {
|
||||
switch (coe) {
|
||||
case FieldInstruction fai ->
|
||||
cob.fieldInstruction(fai.opcode(), map(fai.owner().asSymbol()),
|
||||
fai.name().stringValue(), map(fai.typeSymbol()));
|
||||
case InvokeInstruction ii ->
|
||||
cob.invokeInstruction(ii.opcode(), map(ii.owner().asSymbol()),
|
||||
ii.name().stringValue(), mapMethodDesc(ii.typeSymbol()),
|
||||
ii.isInterface());
|
||||
case InvokeDynamicInstruction idi ->
|
||||
cob.invokeDynamicInstruction(DynamicCallSiteDesc.of(
|
||||
idi.bootstrapMethod(), idi.name().stringValue(),
|
||||
mapMethodDesc(idi.typeSymbol()),
|
||||
idi.bootstrapArgs().stream().map(this::mapConstantValue).toArray(ConstantDesc[]::new)));
|
||||
case NewObjectInstruction c ->
|
||||
cob.newObjectInstruction(map(c.className().asSymbol()));
|
||||
case NewReferenceArrayInstruction c ->
|
||||
cob.anewarray(map(c.componentType().asSymbol()));
|
||||
case NewMultiArrayInstruction c ->
|
||||
cob.multianewarray(map(c.arrayType().asSymbol()), c.dimensions());
|
||||
case TypeCheckInstruction c ->
|
||||
cob.typeCheckInstruction(c.opcode(), map(c.type().asSymbol()));
|
||||
case ExceptionCatch c ->
|
||||
cob.exceptionCatch(c.tryStart(), c.tryEnd(), c.handler(),c.catchType()
|
||||
.map(d -> TemporaryConstantPool.INSTANCE.classEntry(map(d.asSymbol()))));
|
||||
case LocalVariable c ->
|
||||
cob.localVariable(c.slot(), c.name().stringValue(), map(c.typeSymbol()),
|
||||
c.startScope(), c.endScope());
|
||||
case LocalVariableType c ->
|
||||
cob.localVariableType(c.slot(), c.name().stringValue(),
|
||||
mapSignature(c.signatureSymbol()), c.startScope(), c.endScope());
|
||||
case LoadConstantInstruction ldc ->
|
||||
cob.constantInstruction(ldc.opcode(),
|
||||
mapConstantValue(ldc.constantValue()));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute aa ->
|
||||
cob.with(RuntimeVisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute aa ->
|
||||
cob.with(RuntimeInvisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
default ->
|
||||
cob.with(coe);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassDesc map(ClassDesc desc) {
|
||||
if (desc == null) return null;
|
||||
if (desc.isArray()) return map(desc.componentType()).arrayType();
|
||||
if (desc.isPrimitive()) return desc;
|
||||
return mapFunction.apply(desc);
|
||||
}
|
||||
|
||||
MethodTypeDesc mapMethodDesc(MethodTypeDesc desc) {
|
||||
return MethodTypeDesc.of(map(desc.returnType()),
|
||||
desc.parameterList().stream().map(this::map).toArray(ClassDesc[]::new));
|
||||
}
|
||||
|
||||
ClassSignature mapClassSignature(ClassSignature signature) {
|
||||
return ClassSignature.of(mapTypeParams(signature.typeParameters()),
|
||||
mapSignature(signature.superclassSignature()),
|
||||
signature.superinterfaceSignatures().stream()
|
||||
.map(this::mapSignature).toArray(Signature.RefTypeSig[]::new));
|
||||
}
|
||||
|
||||
MethodSignature mapMethodSignature(MethodSignature signature) {
|
||||
return MethodSignature.of(mapTypeParams(signature.typeParameters()),
|
||||
signature.throwableSignatures().stream().map(this::mapSignature).toList(),
|
||||
mapSignature(signature.result()),
|
||||
signature.arguments().stream()
|
||||
.map(this::mapSignature).toArray(Signature[]::new));
|
||||
}
|
||||
|
||||
RecordComponentInfo mapRecordComponent(RecordComponentInfo component) {
|
||||
return RecordComponentInfo.of(component.name().stringValue(),
|
||||
map(component.descriptorSymbol()),
|
||||
component.attributes().stream().map(atr ->
|
||||
switch (atr) {
|
||||
case SignatureAttribute sa ->
|
||||
SignatureAttribute.of(
|
||||
mapSignature(sa.asTypeSignature()));
|
||||
case RuntimeVisibleAnnotationsAttribute aa ->
|
||||
RuntimeVisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations()));
|
||||
case RuntimeInvisibleAnnotationsAttribute aa ->
|
||||
RuntimeInvisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations()));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute aa ->
|
||||
RuntimeVisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations()));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute aa ->
|
||||
RuntimeInvisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations()));
|
||||
default -> atr;
|
||||
}).toList());
|
||||
}
|
||||
|
||||
DirectMethodHandleDesc mapDirectMethodHandle(DirectMethodHandleDesc dmhd) {
|
||||
return switch (dmhd.kind()) {
|
||||
case GETTER, SETTER, STATIC_GETTER, STATIC_SETTER ->
|
||||
MethodHandleDesc.ofField(dmhd.kind(), map(dmhd.owner()),
|
||||
dmhd.methodName(),
|
||||
map(ClassDesc.ofDescriptor(dmhd.lookupDescriptor())));
|
||||
default ->
|
||||
MethodHandleDesc.ofMethod(dmhd.kind(), map(dmhd.owner()),
|
||||
dmhd.methodName(),
|
||||
mapMethodDesc(MethodTypeDesc.ofDescriptor(dmhd.lookupDescriptor())));
|
||||
};
|
||||
}
|
||||
|
||||
ConstantDesc mapConstantValue(ConstantDesc value) {
|
||||
return switch (value) {
|
||||
case ClassDesc cd ->
|
||||
map(cd);
|
||||
case DynamicConstantDesc<?> dcd ->
|
||||
mapDynamicConstant(dcd);
|
||||
case DirectMethodHandleDesc dmhd ->
|
||||
mapDirectMethodHandle(dmhd);
|
||||
case MethodTypeDesc mtd ->
|
||||
mapMethodDesc(mtd);
|
||||
default -> value;
|
||||
};
|
||||
}
|
||||
|
||||
DynamicConstantDesc<?> mapDynamicConstant(DynamicConstantDesc<?> dcd) {
|
||||
return DynamicConstantDesc.ofNamed(mapDirectMethodHandle(dcd.bootstrapMethod()),
|
||||
dcd.constantName(),
|
||||
map(dcd.constantType()),
|
||||
dcd.bootstrapArgsList().stream().map(this::mapConstantValue).toArray(ConstantDesc[]::new));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<S extends Signature> S mapSignature(S signature) {
|
||||
return (S) switch (signature) {
|
||||
case Signature.ArrayTypeSig ats ->
|
||||
Signature.ArrayTypeSig.of(mapSignature(ats.componentSignature()));
|
||||
case Signature.ClassTypeSig cts ->
|
||||
Signature.ClassTypeSig.of(
|
||||
cts.outerType().map(this::mapSignature).orElse(null),
|
||||
map(cts.classDesc()),
|
||||
cts.typeArgs().stream()
|
||||
.map(ta -> Signature.TypeArg.of(
|
||||
ta.wildcardIndicator(),
|
||||
ta.boundType().map(this::mapSignature)))
|
||||
.toArray(Signature.TypeArg[]::new));
|
||||
default -> signature;
|
||||
};
|
||||
}
|
||||
|
||||
List<Annotation> mapAnnotations(List<Annotation> annotations) {
|
||||
return annotations.stream().map(this::mapAnnotation).toList();
|
||||
}
|
||||
|
||||
Annotation mapAnnotation(Annotation a) {
|
||||
return Annotation.of(map(a.classSymbol()), a.elements().stream().map(el ->
|
||||
AnnotationElement.of(el.name(), mapAnnotationValue(el.value()))).toList());
|
||||
}
|
||||
|
||||
AnnotationValue mapAnnotationValue(AnnotationValue val) {
|
||||
return switch (val) {
|
||||
case AnnotationValue.OfAnnotation oa ->
|
||||
AnnotationValue.ofAnnotation(mapAnnotation(oa.annotation()));
|
||||
case AnnotationValue.OfArray oa ->
|
||||
AnnotationValue.ofArray(oa.values().stream().map(this::mapAnnotationValue).toList());
|
||||
case AnnotationValue.OfConstant oc -> oc;
|
||||
case AnnotationValue.OfClass oc ->
|
||||
AnnotationValue.ofClass(map(oc.classSymbol()));
|
||||
case AnnotationValue.OfEnum oe ->
|
||||
AnnotationValue.ofEnum(map(oe.classSymbol()), oe.constantName().stringValue());
|
||||
};
|
||||
}
|
||||
|
||||
List<TypeAnnotation> mapTypeAnnotations(List<TypeAnnotation> typeAnnotations) {
|
||||
return typeAnnotations.stream().map(a -> TypeAnnotation.of(a.targetInfo(),
|
||||
a.targetPath(), map(a.classSymbol()),
|
||||
a.elements().stream().map(el -> AnnotationElement.of(el.name(),
|
||||
mapAnnotationValue(el.value()))).toList())).toList();
|
||||
}
|
||||
|
||||
List<Signature.TypeParam> mapTypeParams(List<Signature.TypeParam> typeParams) {
|
||||
return typeParams.stream().map(tp -> Signature.TypeParam.of(tp.identifier(),
|
||||
tp.classBound().map(this::mapSignature),
|
||||
tp.interfaceBounds().stream()
|
||||
.map(this::mapSignature).toArray(Signature.RefTypeSig[]::new))).toList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2023, 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
|
||||
@ -19,25 +19,15 @@
|
||||
* 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 jdk.internal.classfile.components;
|
||||
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.lang.reflect.AccessFlag;
|
||||
import jdk.internal.classfile.AccessFlags;
|
||||
import jdk.internal.classfile.CodeBuilder;
|
||||
import jdk.internal.classfile.CodeElement;
|
||||
import jdk.internal.classfile.CodeTransform;
|
||||
import jdk.internal.classfile.Signature;
|
||||
import jdk.internal.classfile.instruction.IncrementInstruction;
|
||||
import jdk.internal.classfile.instruction.LoadInstruction;
|
||||
import jdk.internal.classfile.instruction.LocalVariable;
|
||||
import jdk.internal.classfile.instruction.StoreInstruction;
|
||||
import jdk.internal.classfile.TypeKind;
|
||||
import jdk.internal.classfile.instruction.LocalVariableType;
|
||||
import jdk.internal.classfile.impl.CodeLocalsShifterImpl;
|
||||
|
||||
/**
|
||||
* {@link CodeLocalsShifter} is a {@link CodeTransform} shifting locals to
|
||||
@ -45,11 +35,11 @@ import jdk.internal.classfile.instruction.LocalVariableType;
|
||||
* Locals pointing to the receiver or to method arguments slots are never shifted.
|
||||
* All locals pointing beyond the method arguments are re-indexed in order of appearance.
|
||||
*/
|
||||
public sealed interface CodeLocalsShifter extends CodeTransform {
|
||||
public sealed interface CodeLocalsShifter extends CodeTransform permits CodeLocalsShifterImpl {
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link CodeLocalsShifter}
|
||||
* with fixed local slots calculated from provided method information
|
||||
* with fixed local slots calculated from provided method information.
|
||||
* @param methodFlags flags of the method to construct {@link CodeLocalsShifter} for
|
||||
* @param methodDescriptor descriptor of the method to construct {@link CodeLocalsShifter} for
|
||||
* @return new instance of {@link CodeLocalsShifter}
|
||||
@ -60,65 +50,4 @@ public sealed interface CodeLocalsShifter extends CodeTransform {
|
||||
fixed += TypeKind.from(param).slotSize();
|
||||
return new CodeLocalsShifterImpl(fixed);
|
||||
}
|
||||
|
||||
final static class CodeLocalsShifterImpl implements CodeLocalsShifter {
|
||||
|
||||
private int[] locals = new int[0];
|
||||
private final int fixed;
|
||||
|
||||
private CodeLocalsShifterImpl(int fixed) {
|
||||
this.fixed = fixed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(CodeBuilder cob, CodeElement coe) {
|
||||
switch (coe) {
|
||||
case LoadInstruction li ->
|
||||
cob.loadInstruction(
|
||||
li.typeKind(),
|
||||
shift(cob, li.slot(), li.typeKind()));
|
||||
case StoreInstruction si ->
|
||||
cob.storeInstruction(
|
||||
si.typeKind(),
|
||||
shift(cob, si.slot(), si.typeKind()));
|
||||
case IncrementInstruction ii ->
|
||||
cob.incrementInstruction(
|
||||
shift(cob, ii.slot(), TypeKind.IntType),
|
||||
ii.constant());
|
||||
case LocalVariable lv ->
|
||||
cob.localVariable(
|
||||
shift(cob, lv.slot(), TypeKind.fromDescriptor(lv.type().stringValue())),
|
||||
lv.name(),
|
||||
lv.type(),
|
||||
lv.startScope(),
|
||||
lv.endScope());
|
||||
case LocalVariableType lvt ->
|
||||
cob.localVariableType(
|
||||
shift(cob, lvt.slot(),
|
||||
(lvt.signatureSymbol() instanceof Signature.BaseTypeSig bsig)
|
||||
? TypeKind.fromDescriptor(bsig.signatureString())
|
||||
: TypeKind.ReferenceType),
|
||||
lvt.name(),
|
||||
lvt.signature(),
|
||||
lvt.startScope(),
|
||||
lvt.endScope());
|
||||
default -> cob.with(coe);
|
||||
}
|
||||
}
|
||||
|
||||
private int shift(CodeBuilder cob, int slot, TypeKind tk) {
|
||||
if (tk == TypeKind.VoidType) throw new IllegalArgumentException("Illegal local void type");
|
||||
if (slot >= fixed) {
|
||||
int key = 2*slot - fixed + tk.slotSize() - 1;
|
||||
if (key >= locals.length) locals = Arrays.copyOf(locals, key + 20);
|
||||
slot = locals[key] - 1;
|
||||
if (slot < 0) {
|
||||
slot = cob.allocateLocal(tk);
|
||||
locals[key] = slot + 1;
|
||||
if (tk.slotSize() == 2) locals[key - 1] = slot + 1;
|
||||
}
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2023, 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
|
||||
@ -19,7 +19,6 @@
|
||||
* 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 jdk.internal.classfile.components;
|
||||
|
||||
@ -27,18 +26,9 @@ import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import jdk.internal.classfile.CodeBuilder;
|
||||
import jdk.internal.classfile.CodeElement;
|
||||
import jdk.internal.classfile.CodeTransform;
|
||||
import jdk.internal.classfile.instruction.BranchInstruction;
|
||||
import jdk.internal.classfile.instruction.LookupSwitchInstruction;
|
||||
import jdk.internal.classfile.instruction.SwitchCase;
|
||||
import jdk.internal.classfile.instruction.TableSwitchInstruction;
|
||||
import jdk.internal.classfile.Label;
|
||||
import jdk.internal.classfile.instruction.CharacterRange;
|
||||
import jdk.internal.classfile.instruction.ExceptionCatch;
|
||||
import jdk.internal.classfile.instruction.LabelTarget;
|
||||
import jdk.internal.classfile.instruction.LocalVariable;
|
||||
import jdk.internal.classfile.instruction.LocalVariableType;
|
||||
import jdk.internal.classfile.impl.CodeRelabelerImpl;
|
||||
|
||||
/**
|
||||
* A code relabeler is a {@link CodeTransform} replacing all occurrences
|
||||
@ -50,30 +40,30 @@ import jdk.internal.classfile.instruction.LocalVariableType;
|
||||
* Repeated injection of the same code block must be relabeled, so each instance of
|
||||
* {@link jdk.internal.classfile.Label} is bound in the target bytecode exactly once.
|
||||
*/
|
||||
public sealed interface CodeRelabeler extends CodeTransform {
|
||||
public sealed interface CodeRelabeler extends CodeTransform permits CodeRelabelerImpl {
|
||||
|
||||
/**
|
||||
* Creates new instance of CodeRelabeler
|
||||
* @return new instance of CodeRelabeler
|
||||
* Creates a new instance of CodeRelabeler.
|
||||
* @return a new instance of CodeRelabeler
|
||||
*/
|
||||
static CodeRelabeler of() {
|
||||
return of(new IdentityHashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new instance of CodeRelabeler storing the label mapping into the provided map
|
||||
* Creates a new instance of CodeRelabeler storing the label mapping into the provided map.
|
||||
* @param map label map actively used for relabeling
|
||||
* @return new instance of CodeRelabeler
|
||||
* @return a new instance of CodeRelabeler
|
||||
*/
|
||||
static CodeRelabeler of(Map<Label, Label> map) {
|
||||
return of((l, cob) -> map.computeIfAbsent(l, ll -> cob.newLabel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new instance of CodeRelabeler using provided {@link java.util.function.BiFunction}
|
||||
* Creates a new instance of CodeRelabeler using provided {@link java.util.function.BiFunction}
|
||||
* to re-label the code.
|
||||
* @param mapFunction
|
||||
* @return
|
||||
* @return a new instance of CodeRelabeler
|
||||
*/
|
||||
static CodeRelabeler of(BiFunction<Label, CodeBuilder, Label> mapFunction) {
|
||||
return new CodeRelabelerImpl(mapFunction);
|
||||
@ -86,70 +76,4 @@ public sealed interface CodeRelabeler extends CodeTransform {
|
||||
* @return target label
|
||||
*/
|
||||
Label relabel(Label label, CodeBuilder codeBuilder);
|
||||
|
||||
record CodeRelabelerImpl(BiFunction<Label, CodeBuilder, Label> mapFunction) implements CodeRelabeler {
|
||||
|
||||
@Override
|
||||
public Label relabel(Label label, CodeBuilder cob) {
|
||||
return mapFunction.apply(label, cob);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(CodeBuilder cob, CodeElement coe) {
|
||||
switch (coe) {
|
||||
case BranchInstruction bi ->
|
||||
cob.branchInstruction(
|
||||
bi.opcode(),
|
||||
relabel(bi.target(), cob));
|
||||
case LookupSwitchInstruction lsi ->
|
||||
cob.lookupSwitchInstruction(
|
||||
relabel(lsi.defaultTarget(), cob),
|
||||
lsi.cases().stream().map(c ->
|
||||
SwitchCase.of(
|
||||
c.caseValue(),
|
||||
relabel(c.target(), cob))).toList());
|
||||
case TableSwitchInstruction tsi ->
|
||||
cob.tableSwitchInstruction(
|
||||
tsi.lowValue(),
|
||||
tsi.highValue(),
|
||||
relabel(tsi.defaultTarget(), cob),
|
||||
tsi.cases().stream().map(c ->
|
||||
SwitchCase.of(
|
||||
c.caseValue(),
|
||||
relabel(c.target(), cob))).toList());
|
||||
case LabelTarget lt ->
|
||||
cob.labelBinding(
|
||||
relabel(lt.label(), cob));
|
||||
case ExceptionCatch ec ->
|
||||
cob.exceptionCatch(
|
||||
relabel(ec.tryStart(), cob),
|
||||
relabel(ec.tryEnd(), cob),
|
||||
relabel(ec.handler(), cob),
|
||||
ec.catchType());
|
||||
case LocalVariable lv ->
|
||||
cob.localVariable(
|
||||
lv.slot(),
|
||||
lv.name().stringValue(),
|
||||
lv.typeSymbol(),
|
||||
relabel(lv.startScope(), cob),
|
||||
relabel(lv.endScope(), cob));
|
||||
case LocalVariableType lvt ->
|
||||
cob.localVariableType(
|
||||
lvt.slot(),
|
||||
lvt.name().stringValue(),
|
||||
lvt.signatureSymbol(),
|
||||
relabel(lvt.startScope(), cob),
|
||||
relabel(lvt.endScope(), cob));
|
||||
case CharacterRange chr ->
|
||||
cob.characterRange(
|
||||
relabel(chr.startScope(), cob),
|
||||
relabel(chr.endScope(), cob),
|
||||
chr.characterRangeStart(),
|
||||
chr.characterRangeEnd(),
|
||||
chr.flags());
|
||||
default ->
|
||||
cob.with(coe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2023, 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
|
||||
@ -19,25 +19,15 @@
|
||||
* 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 jdk.internal.classfile.components;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import jdk.internal.classfile.CodeBuilder;
|
||||
import jdk.internal.classfile.CodeElement;
|
||||
import jdk.internal.classfile.CodeTransform;
|
||||
import jdk.internal.classfile.Label;
|
||||
import jdk.internal.classfile.Opcode;
|
||||
import jdk.internal.classfile.TypeKind;
|
||||
import jdk.internal.classfile.instruction.*;
|
||||
import jdk.internal.classfile.impl.CodeStackTrackerImpl;
|
||||
|
||||
/**
|
||||
* {@link CodeStackTracker} is a {@link CodeTransform} tracking stack content
|
||||
@ -57,10 +47,10 @@ import jdk.internal.classfile.instruction.*;
|
||||
* });
|
||||
* }
|
||||
*/
|
||||
public sealed interface CodeStackTracker extends CodeTransform {
|
||||
public sealed interface CodeStackTracker extends CodeTransform permits CodeStackTrackerImpl {
|
||||
|
||||
/**
|
||||
* Creates new instance of {@link CodeStackTracker} initialized with provided stack items
|
||||
* Creates new instance of {@link CodeStackTracker} initialized with provided stack items.
|
||||
* @param initialStack initial stack content
|
||||
* @return new instance of {@link CodeStackTracker}
|
||||
*/
|
||||
@ -72,7 +62,7 @@ public sealed interface CodeStackTracker extends CodeTransform {
|
||||
* Returns {@linkplain Collection} of {@linkplain TypeKind} representing current stack.
|
||||
* Returns an empty {@linkplain Optional} when the Stack content is unknown
|
||||
* (right after {@code xRETURN, ATHROW, GOTO, GOTO_W, LOOKUPSWITCH, TABLESWITCH} instructions).
|
||||
*
|
||||
* <p>
|
||||
* Temporary unknown stack content can be recovered by binding of a {@linkplain Label} used as
|
||||
* target of a branch instruction from existing code with known stack (forward branch target),
|
||||
* or by binding of a {@linkplain Label} defining an exception handler (exception handler code start).
|
||||
@ -84,291 +74,11 @@ public sealed interface CodeStackTracker extends CodeTransform {
|
||||
/**
|
||||
* Returns tracked max stack size.
|
||||
* Returns an empty {@linkplain Optional} when max stack size tracking has been lost.
|
||||
*
|
||||
* <p>
|
||||
* Max stack size tracking is permanently lost when a stack instruction appears
|
||||
* and the actual stack content is unknown.
|
||||
*
|
||||
* @return tracked max stack size, or an empty {@linkplain Optional} if tracking has been lost
|
||||
*/
|
||||
Optional<Integer> maxStackSize();
|
||||
|
||||
final static class CodeStackTrackerImpl implements CodeStackTracker {
|
||||
|
||||
private static record Item(TypeKind type, Item next) {
|
||||
}
|
||||
|
||||
private final class Stack extends AbstractCollection<TypeKind> {
|
||||
|
||||
private Item top;
|
||||
private int count, realSize;
|
||||
|
||||
Stack(Item top, int count, int realSize) {
|
||||
this.top = top;
|
||||
this.count = count;
|
||||
this.realSize = realSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<TypeKind> iterator() {
|
||||
return new Iterator<TypeKind>() {
|
||||
Item i = top;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeKind next() {
|
||||
if (i == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
var t = i.type;
|
||||
i = i.next;
|
||||
return t;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return count;
|
||||
}
|
||||
|
||||
private void push(TypeKind type) {
|
||||
top = new Item(type, top);
|
||||
realSize += type.slotSize();
|
||||
count++;
|
||||
if (maxSize != null && realSize > maxSize) maxSize = realSize;
|
||||
}
|
||||
|
||||
private TypeKind pop() {
|
||||
var t = top.type;
|
||||
realSize -= t.slotSize();
|
||||
count--;
|
||||
top = top.next;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
private Stack stack = new Stack(null, 0, 0);
|
||||
private Integer maxSize = 0;
|
||||
|
||||
CodeStackTrackerImpl(TypeKind... initialStack) {
|
||||
for (int i = initialStack.length - 1; i >= 0; i--)
|
||||
push(initialStack[i]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Collection<TypeKind>> stack() {
|
||||
return Optional.ofNullable(fork());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> maxStackSize() {
|
||||
return Optional.ofNullable(maxSize);
|
||||
}
|
||||
|
||||
private final Map<Label, Stack> map = new HashMap<>();
|
||||
|
||||
private void push(TypeKind type) {
|
||||
if (stack != null) {
|
||||
if (type != TypeKind.VoidType) stack.push(type);
|
||||
} else {
|
||||
maxSize = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void pop(int i) {
|
||||
if (stack != null) {
|
||||
while (i-- > 0) stack.pop();
|
||||
} else {
|
||||
maxSize = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Stack fork() {
|
||||
return stack == null ? null : new Stack(stack.top, stack.count, stack.realSize);
|
||||
}
|
||||
|
||||
private void withStack(Consumer<Stack> c) {
|
||||
if (stack != null) c.accept(stack);
|
||||
else maxSize = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(CodeBuilder cb, CodeElement el) {
|
||||
cb.with(el);
|
||||
switch (el) {
|
||||
case ArrayLoadInstruction i -> {
|
||||
pop(2);push(i.typeKind());
|
||||
}
|
||||
case ArrayStoreInstruction i ->
|
||||
pop(3);
|
||||
case BranchInstruction i -> {
|
||||
if (i.opcode() == Opcode.GOTO || i.opcode() == Opcode.GOTO_W) {
|
||||
map.put(i.target(), stack);
|
||||
stack = null;
|
||||
} else {
|
||||
pop(1);
|
||||
map.put(i.target(), fork());
|
||||
}
|
||||
}
|
||||
case ConstantInstruction i ->
|
||||
push(i.typeKind());
|
||||
case ConvertInstruction i -> {
|
||||
pop(1);push(i.toType());
|
||||
}
|
||||
case FieldInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case GETSTATIC ->
|
||||
push(TypeKind.fromDescriptor(i.type().stringValue()));
|
||||
case GETFIELD -> {
|
||||
pop(1);push(TypeKind.fromDescriptor(i.type().stringValue()));
|
||||
}
|
||||
case PUTSTATIC ->
|
||||
pop(1);
|
||||
case PUTFIELD ->
|
||||
pop(2);
|
||||
}
|
||||
}
|
||||
case InvokeDynamicInstruction i -> {
|
||||
var type = i.typeSymbol();
|
||||
pop(type.parameterCount());
|
||||
push(TypeKind.from(type.returnType()));
|
||||
}
|
||||
case InvokeInstruction i -> {
|
||||
var type = i.typeSymbol();
|
||||
pop(type.parameterCount());
|
||||
if (i.opcode() != Opcode.INVOKESTATIC) pop(1);
|
||||
push(TypeKind.from(type.returnType()));
|
||||
}
|
||||
case LoadInstruction i ->
|
||||
push(i.typeKind());
|
||||
case StoreInstruction i ->
|
||||
pop(1);
|
||||
case LookupSwitchInstruction i -> {
|
||||
map.put(i.defaultTarget(), stack);
|
||||
for (var c : i.cases()) map.put(c.target(), fork());
|
||||
stack = null;
|
||||
}
|
||||
case MonitorInstruction i ->
|
||||
pop(1);
|
||||
case NewMultiArrayInstruction i -> {
|
||||
pop(i.dimensions());push(TypeKind.ReferenceType);
|
||||
}
|
||||
case NewObjectInstruction i ->
|
||||
push(TypeKind.ReferenceType);
|
||||
case NewPrimitiveArrayInstruction i -> {
|
||||
pop(1);push(TypeKind.ReferenceType);
|
||||
}
|
||||
case NewReferenceArrayInstruction i -> {
|
||||
pop(1);push(TypeKind.ReferenceType);
|
||||
}
|
||||
case NopInstruction i -> {}
|
||||
case OperatorInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case ARRAYLENGTH, INEG, LNEG, FNEG, DNEG -> pop(1);
|
||||
default -> pop(2);
|
||||
}
|
||||
push(i.typeKind());
|
||||
}
|
||||
case ReturnInstruction i ->
|
||||
stack = null;
|
||||
case StackInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case POP -> pop(1);
|
||||
case POP2 -> withStack(s -> {
|
||||
if (s.pop().slotSize() == 1) s.pop();
|
||||
});
|
||||
case DUP -> withStack(s -> {
|
||||
var v = s.pop();s.push(v);s.push(v);
|
||||
});
|
||||
case DUP2 -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
if (v1.slotSize() == 1) {
|
||||
var v2 = s.pop();
|
||||
s.push(v2);s.push(v1);
|
||||
s.push(v2);s.push(v1);
|
||||
} else {
|
||||
s.push(v1);s.push(v1);
|
||||
}
|
||||
});
|
||||
case DUP_X1 -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
var v2 = s.pop();
|
||||
s.push(v1);s.push(v2);s.push(v1);
|
||||
});
|
||||
case DUP_X2 -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
var v2 = s.pop();
|
||||
if (v2.slotSize() == 1) {
|
||||
var v3 = s.pop();
|
||||
s.push(v1);s.push(v3);s.push(v2);s.push(v1);
|
||||
} else {
|
||||
s.push(v1);s.push(v2);s.push(v1);
|
||||
}
|
||||
});
|
||||
case DUP2_X1 -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
var v2 = s.pop();
|
||||
if (v1.slotSize() == 1) {
|
||||
var v3 = s.pop();
|
||||
s.push(v2);s.push(v1);s.push(v3);s.push(v2);s.push(v1);
|
||||
} else {
|
||||
s.push(v1);s.push(v2);s.push(v1);
|
||||
}
|
||||
});
|
||||
case DUP2_X2 -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
var v2 = s.pop();
|
||||
if (v1.slotSize() == 1) {
|
||||
var v3 = s.pop();
|
||||
if (v3.slotSize() == 1) {
|
||||
var v4 = s.pop();
|
||||
s.push(v2);s.push(v1);s.push(v4);s.push(v3);s.push(v2);s.push(v1);
|
||||
} else {
|
||||
s.push(v2);s.push(v1);s.push(v3);s.push(v2);s.push(v1);
|
||||
}
|
||||
} else {
|
||||
if (v2.slotSize() == 1) {
|
||||
var v3 = s.pop();
|
||||
s.push(v1);s.push(v3);s.push(v2);s.push(v1);
|
||||
} else {
|
||||
s.push(v1);s.push(v2);s.push(v1);
|
||||
}
|
||||
}
|
||||
});
|
||||
case SWAP -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
var v2 = s.pop();
|
||||
s.push(v1);s.push(v2);
|
||||
});
|
||||
}
|
||||
}
|
||||
case TableSwitchInstruction i -> {
|
||||
map.put(i.defaultTarget(), stack);
|
||||
for (var c : i.cases()) map.put(c.target(), fork());
|
||||
stack = null;
|
||||
}
|
||||
case ThrowInstruction i ->
|
||||
stack = null;
|
||||
case TypeCheckInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case CHECKCAST -> {
|
||||
pop(1);push(TypeKind.ReferenceType);
|
||||
}
|
||||
case INSTANCEOF -> {
|
||||
pop(1);push(TypeKind.IntType);
|
||||
}
|
||||
}
|
||||
}
|
||||
case ExceptionCatch i ->
|
||||
map.put(i.handler(), new Stack(new Item(TypeKind.ReferenceType, null), 1, 1));
|
||||
case LabelTarget i ->
|
||||
stack = map.getOrDefault(i.label(), stack);
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,416 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*
|
||||
* 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 jdk.internal.classfile.impl;
|
||||
|
||||
import jdk.internal.classfile.Annotation;
|
||||
import jdk.internal.classfile.AnnotationElement;
|
||||
import jdk.internal.classfile.AnnotationValue;
|
||||
import jdk.internal.classfile.ClassBuilder;
|
||||
import jdk.internal.classfile.ClassElement;
|
||||
import jdk.internal.classfile.ClassSignature;
|
||||
import jdk.internal.classfile.CodeBuilder;
|
||||
import jdk.internal.classfile.CodeElement;
|
||||
import jdk.internal.classfile.CodeModel;
|
||||
import jdk.internal.classfile.CodeTransform;
|
||||
import jdk.internal.classfile.FieldBuilder;
|
||||
import jdk.internal.classfile.FieldElement;
|
||||
import jdk.internal.classfile.FieldModel;
|
||||
import jdk.internal.classfile.FieldTransform;
|
||||
import jdk.internal.classfile.Interfaces;
|
||||
import jdk.internal.classfile.MethodBuilder;
|
||||
import jdk.internal.classfile.MethodElement;
|
||||
import jdk.internal.classfile.MethodModel;
|
||||
import jdk.internal.classfile.MethodSignature;
|
||||
import jdk.internal.classfile.MethodTransform;
|
||||
import jdk.internal.classfile.Signature;
|
||||
import jdk.internal.classfile.Superclass;
|
||||
import jdk.internal.classfile.TypeAnnotation;
|
||||
import jdk.internal.classfile.attribute.AnnotationDefaultAttribute;
|
||||
import jdk.internal.classfile.attribute.EnclosingMethodAttribute;
|
||||
import jdk.internal.classfile.attribute.ExceptionsAttribute;
|
||||
import jdk.internal.classfile.attribute.InnerClassInfo;
|
||||
import jdk.internal.classfile.attribute.InnerClassesAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleAttribute;
|
||||
import jdk.internal.classfile.attribute.ModuleProvideInfo;
|
||||
import jdk.internal.classfile.attribute.NestHostAttribute;
|
||||
import jdk.internal.classfile.attribute.NestMembersAttribute;
|
||||
import jdk.internal.classfile.attribute.PermittedSubclassesAttribute;
|
||||
import jdk.internal.classfile.attribute.RecordAttribute;
|
||||
import jdk.internal.classfile.attribute.RecordComponentInfo;
|
||||
import jdk.internal.classfile.attribute.RuntimeInvisibleAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
|
||||
import jdk.internal.classfile.attribute.SignatureAttribute;
|
||||
import jdk.internal.classfile.components.ClassRemapper;
|
||||
import jdk.internal.classfile.constantpool.Utf8Entry;
|
||||
import jdk.internal.classfile.instruction.ConstantInstruction.LoadConstantInstruction;
|
||||
import jdk.internal.classfile.instruction.ExceptionCatch;
|
||||
import jdk.internal.classfile.instruction.FieldInstruction;
|
||||
import jdk.internal.classfile.instruction.InvokeDynamicInstruction;
|
||||
import jdk.internal.classfile.instruction.InvokeInstruction;
|
||||
import jdk.internal.classfile.instruction.LocalVariable;
|
||||
import jdk.internal.classfile.instruction.LocalVariableType;
|
||||
import jdk.internal.classfile.instruction.NewMultiArrayInstruction;
|
||||
import jdk.internal.classfile.instruction.NewObjectInstruction;
|
||||
import jdk.internal.classfile.instruction.NewReferenceArrayInstruction;
|
||||
import jdk.internal.classfile.instruction.TypeCheckInstruction;
|
||||
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.constant.DirectMethodHandleDesc;
|
||||
import java.lang.constant.DynamicCallSiteDesc;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.lang.constant.MethodHandleDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public record ClassRemapperImpl(Function<ClassDesc, ClassDesc> mapFunction) implements ClassRemapper {
|
||||
|
||||
@Override
|
||||
public void accept(ClassBuilder clb, ClassElement cle) {
|
||||
switch (cle) {
|
||||
case FieldModel fm ->
|
||||
clb.withField(fm.fieldName().stringValue(), map(
|
||||
fm.fieldTypeSymbol()), fb ->
|
||||
fm.forEachElement(asFieldTransform().resolve(fb).consumer()));
|
||||
case MethodModel mm ->
|
||||
clb.withMethod(mm.methodName().stringValue(), mapMethodDesc(
|
||||
mm.methodTypeSymbol()), mm.flags().flagsMask(), mb ->
|
||||
mm.forEachElement(asMethodTransform().resolve(mb).consumer()));
|
||||
case Superclass sc ->
|
||||
clb.withSuperclass(map(sc.superclassEntry().asSymbol()));
|
||||
case Interfaces ins ->
|
||||
clb.withInterfaceSymbols(Util.mappedList(ins.interfaces(), in ->
|
||||
map(in.asSymbol())));
|
||||
case SignatureAttribute sa ->
|
||||
clb.with(SignatureAttribute.of(mapClassSignature(sa.asClassSignature())));
|
||||
case InnerClassesAttribute ica ->
|
||||
clb.with(InnerClassesAttribute.of(ica.classes().stream().map(ici ->
|
||||
InnerClassInfo.of(map(ici.innerClass().asSymbol()),
|
||||
ici.outerClass().map(oc -> map(oc.asSymbol())),
|
||||
ici.innerName().map(Utf8Entry::stringValue),
|
||||
ici.flagsMask())).toList()));
|
||||
case EnclosingMethodAttribute ema ->
|
||||
clb.with(EnclosingMethodAttribute.of(map(ema.enclosingClass().asSymbol()),
|
||||
ema.enclosingMethodName().map(Utf8Entry::stringValue),
|
||||
ema.enclosingMethodTypeSymbol().map(this::mapMethodDesc)));
|
||||
case RecordAttribute ra ->
|
||||
clb.with(RecordAttribute.of(ra.components().stream()
|
||||
.map(this::mapRecordComponent).toList()));
|
||||
case ModuleAttribute ma ->
|
||||
clb.with(ModuleAttribute.of(ma.moduleName(), ma.moduleFlagsMask(),
|
||||
ma.moduleVersion().orElse(null),
|
||||
ma.requires(), ma.exports(), ma.opens(),
|
||||
ma.uses().stream().map(ce ->
|
||||
clb.constantPool().classEntry(map(ce.asSymbol()))).toList(),
|
||||
ma.provides().stream().map(mp ->
|
||||
ModuleProvideInfo.of(map(mp.provides().asSymbol()),
|
||||
mp.providesWith().stream().map(pw ->
|
||||
map(pw.asSymbol())).toList())).toList()));
|
||||
case NestHostAttribute nha ->
|
||||
clb.with(NestHostAttribute.of(map(nha.nestHost().asSymbol())));
|
||||
case NestMembersAttribute nma ->
|
||||
clb.with(NestMembersAttribute.ofSymbols(nma.nestMembers().stream()
|
||||
.map(nm -> map(nm.asSymbol())).toList()));
|
||||
case PermittedSubclassesAttribute psa ->
|
||||
clb.with(PermittedSubclassesAttribute.ofSymbols(
|
||||
psa.permittedSubclasses().stream().map(ps ->
|
||||
map(ps.asSymbol())).toList()));
|
||||
case RuntimeVisibleAnnotationsAttribute aa ->
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleAnnotationsAttribute aa ->
|
||||
clb.with(RuntimeInvisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute aa ->
|
||||
clb.with(RuntimeVisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute aa ->
|
||||
clb.with(RuntimeInvisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
default ->
|
||||
clb.with(cle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldTransform asFieldTransform() {
|
||||
return (FieldBuilder fb, FieldElement fe) -> {
|
||||
switch (fe) {
|
||||
case SignatureAttribute sa ->
|
||||
fb.with(SignatureAttribute.of(
|
||||
mapSignature(sa.asTypeSignature())));
|
||||
case RuntimeVisibleAnnotationsAttribute aa ->
|
||||
fb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleAnnotationsAttribute aa ->
|
||||
fb.with(RuntimeInvisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute aa ->
|
||||
fb.with(RuntimeVisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute aa ->
|
||||
fb.with(RuntimeInvisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
default ->
|
||||
fb.with(fe);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodTransform asMethodTransform() {
|
||||
return (MethodBuilder mb, MethodElement me) -> {
|
||||
switch (me) {
|
||||
case AnnotationDefaultAttribute ada ->
|
||||
mb.with(AnnotationDefaultAttribute.of(
|
||||
mapAnnotationValue(ada.defaultValue())));
|
||||
case CodeModel com ->
|
||||
mb.transformCode(com, asCodeTransform());
|
||||
case ExceptionsAttribute ea ->
|
||||
mb.with(ExceptionsAttribute.ofSymbols(
|
||||
ea.exceptions().stream().map(ce ->
|
||||
map(ce.asSymbol())).toList()));
|
||||
case SignatureAttribute sa ->
|
||||
mb.with(SignatureAttribute.of(
|
||||
mapMethodSignature(sa.asMethodSignature())));
|
||||
case RuntimeVisibleAnnotationsAttribute aa ->
|
||||
mb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleAnnotationsAttribute aa ->
|
||||
mb.with(RuntimeInvisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations())));
|
||||
case RuntimeVisibleParameterAnnotationsAttribute paa ->
|
||||
mb.with(RuntimeVisibleParameterAnnotationsAttribute.of(
|
||||
paa.parameterAnnotations().stream()
|
||||
.map(this::mapAnnotations).toList()));
|
||||
case RuntimeInvisibleParameterAnnotationsAttribute paa ->
|
||||
mb.with(RuntimeInvisibleParameterAnnotationsAttribute.of(
|
||||
paa.parameterAnnotations().stream()
|
||||
.map(this::mapAnnotations).toList()));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute aa ->
|
||||
mb.with(RuntimeVisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute aa ->
|
||||
mb.with(RuntimeInvisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
default ->
|
||||
mb.with(me);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeTransform asCodeTransform() {
|
||||
return (CodeBuilder cob, CodeElement coe) -> {
|
||||
switch (coe) {
|
||||
case FieldInstruction fai ->
|
||||
cob.fieldInstruction(fai.opcode(), map(fai.owner().asSymbol()),
|
||||
fai.name().stringValue(), map(fai.typeSymbol()));
|
||||
case InvokeInstruction ii ->
|
||||
cob.invokeInstruction(ii.opcode(), map(ii.owner().asSymbol()),
|
||||
ii.name().stringValue(), mapMethodDesc(ii.typeSymbol()),
|
||||
ii.isInterface());
|
||||
case InvokeDynamicInstruction idi ->
|
||||
cob.invokeDynamicInstruction(DynamicCallSiteDesc.of(
|
||||
idi.bootstrapMethod(), idi.name().stringValue(),
|
||||
mapMethodDesc(idi.typeSymbol()),
|
||||
idi.bootstrapArgs().stream().map(this::mapConstantValue).toArray(ConstantDesc[]::new)));
|
||||
case NewObjectInstruction c ->
|
||||
cob.newObjectInstruction(map(c.className().asSymbol()));
|
||||
case NewReferenceArrayInstruction c ->
|
||||
cob.anewarray(map(c.componentType().asSymbol()));
|
||||
case NewMultiArrayInstruction c ->
|
||||
cob.multianewarray(map(c.arrayType().asSymbol()), c.dimensions());
|
||||
case TypeCheckInstruction c ->
|
||||
cob.typeCheckInstruction(c.opcode(), map(c.type().asSymbol()));
|
||||
case ExceptionCatch c ->
|
||||
cob.exceptionCatch(c.tryStart(), c.tryEnd(), c.handler(),c.catchType()
|
||||
.map(d -> TemporaryConstantPool.INSTANCE.classEntry(map(d.asSymbol()))));
|
||||
case LocalVariable c ->
|
||||
cob.localVariable(c.slot(), c.name().stringValue(), map(c.typeSymbol()),
|
||||
c.startScope(), c.endScope());
|
||||
case LocalVariableType c ->
|
||||
cob.localVariableType(c.slot(), c.name().stringValue(),
|
||||
mapSignature(c.signatureSymbol()), c.startScope(), c.endScope());
|
||||
case LoadConstantInstruction ldc ->
|
||||
cob.constantInstruction(ldc.opcode(),
|
||||
mapConstantValue(ldc.constantValue()));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute aa ->
|
||||
cob.with(RuntimeVisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute aa ->
|
||||
cob.with(RuntimeInvisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations())));
|
||||
default ->
|
||||
cob.with(coe);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassDesc map(ClassDesc desc) {
|
||||
if (desc == null) return null;
|
||||
if (desc.isArray()) return map(desc.componentType()).arrayType();
|
||||
if (desc.isPrimitive()) return desc;
|
||||
return mapFunction.apply(desc);
|
||||
}
|
||||
|
||||
MethodTypeDesc mapMethodDesc(MethodTypeDesc desc) {
|
||||
return MethodTypeDesc.of(map(desc.returnType()),
|
||||
desc.parameterList().stream().map(this::map).toArray(ClassDesc[]::new));
|
||||
}
|
||||
|
||||
ClassSignature mapClassSignature(ClassSignature signature) {
|
||||
return ClassSignature.of(mapTypeParams(signature.typeParameters()),
|
||||
mapSignature(signature.superclassSignature()),
|
||||
signature.superinterfaceSignatures().stream()
|
||||
.map(this::mapSignature).toArray(Signature.RefTypeSig[]::new));
|
||||
}
|
||||
|
||||
MethodSignature mapMethodSignature(MethodSignature signature) {
|
||||
return MethodSignature.of(mapTypeParams(signature.typeParameters()),
|
||||
signature.throwableSignatures().stream().map(this::mapSignature).toList(),
|
||||
mapSignature(signature.result()),
|
||||
signature.arguments().stream()
|
||||
.map(this::mapSignature).toArray(Signature[]::new));
|
||||
}
|
||||
|
||||
RecordComponentInfo mapRecordComponent(RecordComponentInfo component) {
|
||||
return RecordComponentInfo.of(component.name().stringValue(),
|
||||
map(component.descriptorSymbol()),
|
||||
component.attributes().stream().map(atr ->
|
||||
switch (atr) {
|
||||
case SignatureAttribute sa ->
|
||||
SignatureAttribute.of(
|
||||
mapSignature(sa.asTypeSignature()));
|
||||
case RuntimeVisibleAnnotationsAttribute aa ->
|
||||
RuntimeVisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations()));
|
||||
case RuntimeInvisibleAnnotationsAttribute aa ->
|
||||
RuntimeInvisibleAnnotationsAttribute.of(
|
||||
mapAnnotations(aa.annotations()));
|
||||
case RuntimeVisibleTypeAnnotationsAttribute aa ->
|
||||
RuntimeVisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations()));
|
||||
case RuntimeInvisibleTypeAnnotationsAttribute aa ->
|
||||
RuntimeInvisibleTypeAnnotationsAttribute.of(
|
||||
mapTypeAnnotations(aa.annotations()));
|
||||
default -> atr;
|
||||
}).toList());
|
||||
}
|
||||
|
||||
DirectMethodHandleDesc mapDirectMethodHandle(DirectMethodHandleDesc dmhd) {
|
||||
return switch (dmhd.kind()) {
|
||||
case GETTER, SETTER, STATIC_GETTER, STATIC_SETTER ->
|
||||
MethodHandleDesc.ofField(dmhd.kind(), map(dmhd.owner()),
|
||||
dmhd.methodName(),
|
||||
map(ClassDesc.ofDescriptor(dmhd.lookupDescriptor())));
|
||||
default ->
|
||||
MethodHandleDesc.ofMethod(dmhd.kind(), map(dmhd.owner()),
|
||||
dmhd.methodName(),
|
||||
mapMethodDesc(MethodTypeDesc.ofDescriptor(dmhd.lookupDescriptor())));
|
||||
};
|
||||
}
|
||||
|
||||
ConstantDesc mapConstantValue(ConstantDesc value) {
|
||||
return switch (value) {
|
||||
case ClassDesc cd ->
|
||||
map(cd);
|
||||
case DynamicConstantDesc<?> dcd ->
|
||||
mapDynamicConstant(dcd);
|
||||
case DirectMethodHandleDesc dmhd ->
|
||||
mapDirectMethodHandle(dmhd);
|
||||
case MethodTypeDesc mtd ->
|
||||
mapMethodDesc(mtd);
|
||||
default -> value;
|
||||
};
|
||||
}
|
||||
|
||||
DynamicConstantDesc<?> mapDynamicConstant(DynamicConstantDesc<?> dcd) {
|
||||
return DynamicConstantDesc.ofNamed(mapDirectMethodHandle(dcd.bootstrapMethod()),
|
||||
dcd.constantName(),
|
||||
map(dcd.constantType()),
|
||||
dcd.bootstrapArgsList().stream().map(this::mapConstantValue).toArray(ConstantDesc[]::new));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<S extends Signature> S mapSignature(S signature) {
|
||||
return (S) switch (signature) {
|
||||
case Signature.ArrayTypeSig ats ->
|
||||
Signature.ArrayTypeSig.of(mapSignature(ats.componentSignature()));
|
||||
case Signature.ClassTypeSig cts ->
|
||||
Signature.ClassTypeSig.of(
|
||||
cts.outerType().map(this::mapSignature).orElse(null),
|
||||
map(cts.classDesc()),
|
||||
cts.typeArgs().stream()
|
||||
.map(ta -> Signature.TypeArg.of(
|
||||
ta.wildcardIndicator(),
|
||||
ta.boundType().map(this::mapSignature)))
|
||||
.toArray(Signature.TypeArg[]::new));
|
||||
default -> signature;
|
||||
};
|
||||
}
|
||||
|
||||
List<Annotation> mapAnnotations(List<Annotation> annotations) {
|
||||
return annotations.stream().map(this::mapAnnotation).toList();
|
||||
}
|
||||
|
||||
Annotation mapAnnotation(Annotation a) {
|
||||
return Annotation.of(map(a.classSymbol()), a.elements().stream().map(el ->
|
||||
AnnotationElement.of(el.name(), mapAnnotationValue(el.value()))).toList());
|
||||
}
|
||||
|
||||
AnnotationValue mapAnnotationValue(AnnotationValue val) {
|
||||
return switch (val) {
|
||||
case AnnotationValue.OfAnnotation oa ->
|
||||
AnnotationValue.ofAnnotation(mapAnnotation(oa.annotation()));
|
||||
case AnnotationValue.OfArray oa ->
|
||||
AnnotationValue.ofArray(oa.values().stream().map(this::mapAnnotationValue).toList());
|
||||
case AnnotationValue.OfConstant oc -> oc;
|
||||
case AnnotationValue.OfClass oc ->
|
||||
AnnotationValue.ofClass(map(oc.classSymbol()));
|
||||
case AnnotationValue.OfEnum oe ->
|
||||
AnnotationValue.ofEnum(map(oe.classSymbol()), oe.constantName().stringValue());
|
||||
};
|
||||
}
|
||||
|
||||
List<TypeAnnotation> mapTypeAnnotations(List<TypeAnnotation> typeAnnotations) {
|
||||
return typeAnnotations.stream().map(a -> TypeAnnotation.of(a.targetInfo(),
|
||||
a.targetPath(), map(a.classSymbol()),
|
||||
a.elements().stream().map(el -> AnnotationElement.of(el.name(),
|
||||
mapAnnotationValue(el.value()))).toList())).toList();
|
||||
}
|
||||
|
||||
List<Signature.TypeParam> mapTypeParams(List<Signature.TypeParam> typeParams) {
|
||||
return typeParams.stream().map(tp -> Signature.TypeParam.of(tp.identifier(),
|
||||
tp.classBound().map(this::mapSignature),
|
||||
tp.interfaceBounds().stream()
|
||||
.map(this::mapSignature).toArray(Signature.RefTypeSig[]::new))).toList();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*
|
||||
* 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 jdk.internal.classfile.impl;
|
||||
|
||||
import jdk.internal.classfile.CodeBuilder;
|
||||
import jdk.internal.classfile.CodeElement;
|
||||
import jdk.internal.classfile.Signature;
|
||||
import jdk.internal.classfile.TypeKind;
|
||||
import jdk.internal.classfile.components.CodeLocalsShifter;
|
||||
import jdk.internal.classfile.instruction.IncrementInstruction;
|
||||
import jdk.internal.classfile.instruction.LoadInstruction;
|
||||
import jdk.internal.classfile.instruction.LocalVariable;
|
||||
import jdk.internal.classfile.instruction.LocalVariableType;
|
||||
import jdk.internal.classfile.instruction.StoreInstruction;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public final class CodeLocalsShifterImpl implements CodeLocalsShifter {
|
||||
|
||||
private int[] locals = new int[0];
|
||||
private final int fixed;
|
||||
|
||||
public CodeLocalsShifterImpl(int fixed) {
|
||||
this.fixed = fixed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(CodeBuilder cob, CodeElement coe) {
|
||||
switch (coe) {
|
||||
case LoadInstruction li ->
|
||||
cob.loadInstruction(
|
||||
li.typeKind(),
|
||||
shift(cob, li.slot(), li.typeKind()));
|
||||
case StoreInstruction si ->
|
||||
cob.storeInstruction(
|
||||
si.typeKind(),
|
||||
shift(cob, si.slot(), si.typeKind()));
|
||||
case IncrementInstruction ii ->
|
||||
cob.incrementInstruction(
|
||||
shift(cob, ii.slot(), TypeKind.IntType),
|
||||
ii.constant());
|
||||
case LocalVariable lv ->
|
||||
cob.localVariable(
|
||||
shift(cob, lv.slot(), TypeKind.fromDescriptor(lv.type().stringValue())),
|
||||
lv.name(),
|
||||
lv.type(),
|
||||
lv.startScope(),
|
||||
lv.endScope());
|
||||
case LocalVariableType lvt ->
|
||||
cob.localVariableType(
|
||||
shift(cob, lvt.slot(),
|
||||
(lvt.signatureSymbol() instanceof Signature.BaseTypeSig bsig)
|
||||
? TypeKind.fromDescriptor(bsig.signatureString())
|
||||
: TypeKind.ReferenceType),
|
||||
lvt.name(),
|
||||
lvt.signature(),
|
||||
lvt.startScope(),
|
||||
lvt.endScope());
|
||||
default -> cob.with(coe);
|
||||
}
|
||||
}
|
||||
|
||||
private int shift(CodeBuilder cob, int slot, TypeKind tk) {
|
||||
if (tk == TypeKind.VoidType) throw new IllegalArgumentException("Illegal local void type");
|
||||
if (slot >= fixed) {
|
||||
int key = 2*slot - fixed + tk.slotSize() - 1;
|
||||
if (key >= locals.length) locals = Arrays.copyOf(locals, key + 20);
|
||||
slot = locals[key] - 1;
|
||||
if (slot < 0) {
|
||||
slot = cob.allocateLocal(tk);
|
||||
locals[key] = slot + 1;
|
||||
if (tk.slotSize() == 2) locals[key - 1] = slot + 1;
|
||||
}
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*
|
||||
* 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 jdk.internal.classfile.impl;
|
||||
|
||||
import jdk.internal.classfile.CodeBuilder;
|
||||
import jdk.internal.classfile.CodeElement;
|
||||
import jdk.internal.classfile.Label;
|
||||
import jdk.internal.classfile.components.CodeRelabeler;
|
||||
import jdk.internal.classfile.instruction.BranchInstruction;
|
||||
import jdk.internal.classfile.instruction.CharacterRange;
|
||||
import jdk.internal.classfile.instruction.ExceptionCatch;
|
||||
import jdk.internal.classfile.instruction.LabelTarget;
|
||||
import jdk.internal.classfile.instruction.LocalVariable;
|
||||
import jdk.internal.classfile.instruction.LocalVariableType;
|
||||
import jdk.internal.classfile.instruction.LookupSwitchInstruction;
|
||||
import jdk.internal.classfile.instruction.SwitchCase;
|
||||
import jdk.internal.classfile.instruction.TableSwitchInstruction;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public record CodeRelabelerImpl(BiFunction<Label, CodeBuilder, Label> mapFunction) implements CodeRelabeler {
|
||||
|
||||
@Override
|
||||
public Label relabel(Label label, CodeBuilder cob) {
|
||||
return mapFunction.apply(label, cob);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(CodeBuilder cob, CodeElement coe) {
|
||||
switch (coe) {
|
||||
case BranchInstruction bi ->
|
||||
cob.branchInstruction(
|
||||
bi.opcode(),
|
||||
relabel(bi.target(), cob));
|
||||
case LookupSwitchInstruction lsi ->
|
||||
cob.lookupSwitchInstruction(
|
||||
relabel(lsi.defaultTarget(), cob),
|
||||
lsi.cases().stream().map(c ->
|
||||
SwitchCase.of(
|
||||
c.caseValue(),
|
||||
relabel(c.target(), cob))).toList());
|
||||
case TableSwitchInstruction tsi ->
|
||||
cob.tableSwitchInstruction(
|
||||
tsi.lowValue(),
|
||||
tsi.highValue(),
|
||||
relabel(tsi.defaultTarget(), cob),
|
||||
tsi.cases().stream().map(c ->
|
||||
SwitchCase.of(
|
||||
c.caseValue(),
|
||||
relabel(c.target(), cob))).toList());
|
||||
case LabelTarget lt ->
|
||||
cob.labelBinding(
|
||||
relabel(lt.label(), cob));
|
||||
case ExceptionCatch ec ->
|
||||
cob.exceptionCatch(
|
||||
relabel(ec.tryStart(), cob),
|
||||
relabel(ec.tryEnd(), cob),
|
||||
relabel(ec.handler(), cob),
|
||||
ec.catchType());
|
||||
case LocalVariable lv ->
|
||||
cob.localVariable(
|
||||
lv.slot(),
|
||||
lv.name().stringValue(),
|
||||
lv.typeSymbol(),
|
||||
relabel(lv.startScope(), cob),
|
||||
relabel(lv.endScope(), cob));
|
||||
case LocalVariableType lvt ->
|
||||
cob.localVariableType(
|
||||
lvt.slot(),
|
||||
lvt.name().stringValue(),
|
||||
lvt.signatureSymbol(),
|
||||
relabel(lvt.startScope(), cob),
|
||||
relabel(lvt.endScope(), cob));
|
||||
case CharacterRange chr ->
|
||||
cob.characterRange(
|
||||
relabel(chr.startScope(), cob),
|
||||
relabel(chr.endScope(), cob),
|
||||
chr.characterRangeStart(),
|
||||
chr.characterRangeEnd(),
|
||||
chr.flags());
|
||||
default ->
|
||||
cob.with(coe);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,344 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*
|
||||
* 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 jdk.internal.classfile.impl;
|
||||
|
||||
import jdk.internal.classfile.CodeBuilder;
|
||||
import jdk.internal.classfile.CodeElement;
|
||||
import jdk.internal.classfile.Label;
|
||||
import jdk.internal.classfile.Opcode;
|
||||
import jdk.internal.classfile.TypeKind;
|
||||
import jdk.internal.classfile.components.CodeStackTracker;
|
||||
import jdk.internal.classfile.instruction.ArrayLoadInstruction;
|
||||
import jdk.internal.classfile.instruction.ArrayStoreInstruction;
|
||||
import jdk.internal.classfile.instruction.BranchInstruction;
|
||||
import jdk.internal.classfile.instruction.ConstantInstruction;
|
||||
import jdk.internal.classfile.instruction.ConvertInstruction;
|
||||
import jdk.internal.classfile.instruction.ExceptionCatch;
|
||||
import jdk.internal.classfile.instruction.FieldInstruction;
|
||||
import jdk.internal.classfile.instruction.InvokeDynamicInstruction;
|
||||
import jdk.internal.classfile.instruction.InvokeInstruction;
|
||||
import jdk.internal.classfile.instruction.LabelTarget;
|
||||
import jdk.internal.classfile.instruction.LoadInstruction;
|
||||
import jdk.internal.classfile.instruction.LookupSwitchInstruction;
|
||||
import jdk.internal.classfile.instruction.MonitorInstruction;
|
||||
import jdk.internal.classfile.instruction.NewMultiArrayInstruction;
|
||||
import jdk.internal.classfile.instruction.NewObjectInstruction;
|
||||
import jdk.internal.classfile.instruction.NewPrimitiveArrayInstruction;
|
||||
import jdk.internal.classfile.instruction.NewReferenceArrayInstruction;
|
||||
import jdk.internal.classfile.instruction.NopInstruction;
|
||||
import jdk.internal.classfile.instruction.OperatorInstruction;
|
||||
import jdk.internal.classfile.instruction.ReturnInstruction;
|
||||
import jdk.internal.classfile.instruction.StackInstruction;
|
||||
import jdk.internal.classfile.instruction.StoreInstruction;
|
||||
import jdk.internal.classfile.instruction.TableSwitchInstruction;
|
||||
import jdk.internal.classfile.instruction.ThrowInstruction;
|
||||
import jdk.internal.classfile.instruction.TypeCheckInstruction;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class CodeStackTrackerImpl implements CodeStackTracker {
|
||||
|
||||
private static record Item(TypeKind type, Item next) {
|
||||
}
|
||||
|
||||
private final class Stack extends AbstractCollection<TypeKind> {
|
||||
|
||||
private Item top;
|
||||
private int count, realSize;
|
||||
|
||||
Stack(Item top, int count, int realSize) {
|
||||
this.top = top;
|
||||
this.count = count;
|
||||
this.realSize = realSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<TypeKind> iterator() {
|
||||
return new Iterator<TypeKind>() {
|
||||
Item i = top;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeKind next() {
|
||||
if (i == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
var t = i.type;
|
||||
i = i.next;
|
||||
return t;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return count;
|
||||
}
|
||||
|
||||
private void push(TypeKind type) {
|
||||
top = new Item(type, top);
|
||||
realSize += type.slotSize();
|
||||
count++;
|
||||
if (maxSize != null && realSize > maxSize) maxSize = realSize;
|
||||
}
|
||||
|
||||
private TypeKind pop() {
|
||||
var t = top.type;
|
||||
realSize -= t.slotSize();
|
||||
count--;
|
||||
top = top.next;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
private Stack stack = new Stack(null, 0, 0);
|
||||
private Integer maxSize = 0;
|
||||
|
||||
public CodeStackTrackerImpl(TypeKind... initialStack) {
|
||||
for (int i = initialStack.length - 1; i >= 0; i--)
|
||||
push(initialStack[i]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Collection<TypeKind>> stack() {
|
||||
return Optional.ofNullable(fork());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> maxStackSize() {
|
||||
return Optional.ofNullable(maxSize);
|
||||
}
|
||||
|
||||
private final Map<Label, Stack> map = new HashMap<>();
|
||||
|
||||
private void push(TypeKind type) {
|
||||
if (stack != null) {
|
||||
if (type != TypeKind.VoidType) stack.push(type);
|
||||
} else {
|
||||
maxSize = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void pop(int i) {
|
||||
if (stack != null) {
|
||||
while (i-- > 0) stack.pop();
|
||||
} else {
|
||||
maxSize = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Stack fork() {
|
||||
return stack == null ? null : new Stack(stack.top, stack.count, stack.realSize);
|
||||
}
|
||||
|
||||
private void withStack(Consumer<Stack> c) {
|
||||
if (stack != null) c.accept(stack);
|
||||
else maxSize = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(CodeBuilder cb, CodeElement el) {
|
||||
cb.with(el);
|
||||
switch (el) {
|
||||
case ArrayLoadInstruction i -> {
|
||||
pop(2);push(i.typeKind());
|
||||
}
|
||||
case ArrayStoreInstruction i ->
|
||||
pop(3);
|
||||
case BranchInstruction i -> {
|
||||
if (i.opcode() == Opcode.GOTO || i.opcode() == Opcode.GOTO_W) {
|
||||
map.put(i.target(), stack);
|
||||
stack = null;
|
||||
} else {
|
||||
pop(1);
|
||||
map.put(i.target(), fork());
|
||||
}
|
||||
}
|
||||
case ConstantInstruction i ->
|
||||
push(i.typeKind());
|
||||
case ConvertInstruction i -> {
|
||||
pop(1);push(i.toType());
|
||||
}
|
||||
case FieldInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case GETSTATIC ->
|
||||
push(TypeKind.fromDescriptor(i.type().stringValue()));
|
||||
case GETFIELD -> {
|
||||
pop(1);push(TypeKind.fromDescriptor(i.type().stringValue()));
|
||||
}
|
||||
case PUTSTATIC ->
|
||||
pop(1);
|
||||
case PUTFIELD ->
|
||||
pop(2);
|
||||
}
|
||||
}
|
||||
case InvokeDynamicInstruction i -> {
|
||||
var type = i.typeSymbol();
|
||||
pop(type.parameterCount());
|
||||
push(TypeKind.from(type.returnType()));
|
||||
}
|
||||
case InvokeInstruction i -> {
|
||||
var type = i.typeSymbol();
|
||||
pop(type.parameterCount());
|
||||
if (i.opcode() != Opcode.INVOKESTATIC) pop(1);
|
||||
push(TypeKind.from(type.returnType()));
|
||||
}
|
||||
case LoadInstruction i ->
|
||||
push(i.typeKind());
|
||||
case StoreInstruction i ->
|
||||
pop(1);
|
||||
case LookupSwitchInstruction i -> {
|
||||
map.put(i.defaultTarget(), stack);
|
||||
for (var c : i.cases()) map.put(c.target(), fork());
|
||||
stack = null;
|
||||
}
|
||||
case MonitorInstruction i ->
|
||||
pop(1);
|
||||
case NewMultiArrayInstruction i -> {
|
||||
pop(i.dimensions());push(TypeKind.ReferenceType);
|
||||
}
|
||||
case NewObjectInstruction i ->
|
||||
push(TypeKind.ReferenceType);
|
||||
case NewPrimitiveArrayInstruction i -> {
|
||||
pop(1);push(TypeKind.ReferenceType);
|
||||
}
|
||||
case NewReferenceArrayInstruction i -> {
|
||||
pop(1);push(TypeKind.ReferenceType);
|
||||
}
|
||||
case NopInstruction i -> {}
|
||||
case OperatorInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case ARRAYLENGTH, INEG, LNEG, FNEG, DNEG -> pop(1);
|
||||
default -> pop(2);
|
||||
}
|
||||
push(i.typeKind());
|
||||
}
|
||||
case ReturnInstruction i ->
|
||||
stack = null;
|
||||
case StackInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case POP -> pop(1);
|
||||
case POP2 -> withStack(s -> {
|
||||
if (s.pop().slotSize() == 1) s.pop();
|
||||
});
|
||||
case DUP -> withStack(s -> {
|
||||
var v = s.pop();s.push(v);s.push(v);
|
||||
});
|
||||
case DUP2 -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
if (v1.slotSize() == 1) {
|
||||
var v2 = s.pop();
|
||||
s.push(v2);s.push(v1);
|
||||
s.push(v2);s.push(v1);
|
||||
} else {
|
||||
s.push(v1);s.push(v1);
|
||||
}
|
||||
});
|
||||
case DUP_X1 -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
var v2 = s.pop();
|
||||
s.push(v1);s.push(v2);s.push(v1);
|
||||
});
|
||||
case DUP_X2 -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
var v2 = s.pop();
|
||||
if (v2.slotSize() == 1) {
|
||||
var v3 = s.pop();
|
||||
s.push(v1);s.push(v3);s.push(v2);s.push(v1);
|
||||
} else {
|
||||
s.push(v1);s.push(v2);s.push(v1);
|
||||
}
|
||||
});
|
||||
case DUP2_X1 -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
var v2 = s.pop();
|
||||
if (v1.slotSize() == 1) {
|
||||
var v3 = s.pop();
|
||||
s.push(v2);s.push(v1);s.push(v3);s.push(v2);s.push(v1);
|
||||
} else {
|
||||
s.push(v1);s.push(v2);s.push(v1);
|
||||
}
|
||||
});
|
||||
case DUP2_X2 -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
var v2 = s.pop();
|
||||
if (v1.slotSize() == 1) {
|
||||
var v3 = s.pop();
|
||||
if (v3.slotSize() == 1) {
|
||||
var v4 = s.pop();
|
||||
s.push(v2);s.push(v1);s.push(v4);s.push(v3);s.push(v2);s.push(v1);
|
||||
} else {
|
||||
s.push(v2);s.push(v1);s.push(v3);s.push(v2);s.push(v1);
|
||||
}
|
||||
} else {
|
||||
if (v2.slotSize() == 1) {
|
||||
var v3 = s.pop();
|
||||
s.push(v1);s.push(v3);s.push(v2);s.push(v1);
|
||||
} else {
|
||||
s.push(v1);s.push(v2);s.push(v1);
|
||||
}
|
||||
}
|
||||
});
|
||||
case SWAP -> withStack(s -> {
|
||||
var v1 = s.pop();
|
||||
var v2 = s.pop();
|
||||
s.push(v1);s.push(v2);
|
||||
});
|
||||
}
|
||||
}
|
||||
case TableSwitchInstruction i -> {
|
||||
map.put(i.defaultTarget(), stack);
|
||||
for (var c : i.cases()) map.put(c.target(), fork());
|
||||
stack = null;
|
||||
}
|
||||
case ThrowInstruction i ->
|
||||
stack = null;
|
||||
case TypeCheckInstruction i -> {
|
||||
switch (i.opcode()) {
|
||||
case CHECKCAST -> {
|
||||
pop(1);push(TypeKind.ReferenceType);
|
||||
}
|
||||
case INSTANCEOF -> {
|
||||
pop(1);push(TypeKind.IntType);
|
||||
}
|
||||
}
|
||||
}
|
||||
case ExceptionCatch i ->
|
||||
map.put(i.handler(), new Stack(new Item(TypeKind.ReferenceType, null), 1, 1));
|
||||
case LabelTarget i ->
|
||||
stack = map.getOrDefault(i.label(), stack);
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user