io.github.dmlloyd.classfile.impl.AbstractInstruction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jdk-classfile-backport Show documentation
Show all versions of jdk-classfile-backport Show documentation
An unofficial backport of the JDK Classfile API to Java 17
/*
* Copyright (c) 2022, 2024, 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 io.github.dmlloyd.classfile.impl;
import io.github.dmlloyd.classfile.Instruction;
import io.github.dmlloyd.classfile.Label;
import io.github.dmlloyd.classfile.Opcode;
import io.github.dmlloyd.classfile.TypeKind;
import io.github.dmlloyd.classfile.constantpool.*;
import io.github.dmlloyd.classfile.instruction.*;
import java.lang.constant.ConstantDesc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static java.util.Objects.requireNonNull;
public abstract sealed class AbstractInstruction
extends AbstractElement
implements Instruction {
private static final String
FMT_ArgumentConstant = "ArgumentConstant[OP=%s, val=%s]",
FMT_Branch = "Branch[OP=%s]",
FMT_Field = "Field[OP=%s, field=%s.%s:%s]",
FMT_Increment = "Increment[OP=%s, slot=%d, val=%d]",
FMT_Invoke = "Invoke[OP=%s, m=%s.%s%s]",
FMT_InvokeDynamic = "InvokeDynamic[OP=%s, bsm=%s %s]",
FMT_InvokeInterface = "InvokeInterface[OP=%s, m=%s.%s%s]",
FMT_Load = "Load[OP=%s, slot=%d]",
FMT_LoadConstant = "LoadConstant[OP=%s, val=%s]",
FMT_LookupSwitch = "LookupSwitch[OP=%s]",
FMT_NewMultiArray = "NewMultiArray[OP=%s, type=%s[%d]]",
FMT_NewObj = "NewObj[OP=%s, type=%s]",
FMT_NewPrimitiveArray = "NewPrimitiveArray[OP=%s, type=%s]",
FMT_NewRefArray = "NewRefArray[OP=%s, type=%s]",
FMT_Return = "Return[OP=%s]",
FMT_Store = "Store[OP=%s, slot=%d]",
FMT_TableSwitch = "TableSwitch[OP=%s]",
FMT_Throw = "Throw[OP=%s]",
FMT_TypeCheck = "TypeCheck[OP=%s, type=%s]",
FMT_Unbound = "%s[op=%s]",
FMT_Discontinued = "Discontinued[OP=%s]";
final Opcode op;
@Override
public Opcode opcode() {
return op;
}
@Override
public int sizeInBytes() {
// Note: only lookupswitch and tableswitch have variable sizes
return op.sizeIfFixed();
}
AbstractInstruction(Opcode op) {
this.op = op;
}
@Override
public abstract void writeTo(DirectCodeBuilder writer);
public abstract static sealed class BoundInstruction extends AbstractInstruction {
final CodeImpl code;
final int pos;
protected BoundInstruction(Opcode op, CodeImpl code, int pos) {
super(op);
this.code = code;
this.pos = pos;
}
protected Label offsetToLabel(int offset) {
return code.getLabel(pos - code.codeStart + offset);
}
@Override
public void writeTo(DirectCodeBuilder writer) {
// Override this if the instruction has any CP references or labels!
code.classReader.copyBytesTo(writer.bytecodesBufWriter, pos, op.sizeIfFixed());
}
}
public static final class BoundLoadInstruction
extends BoundInstruction implements LoadInstruction {
public BoundLoadInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public TypeKind typeKind() {
return BytecodeHelpers.loadType(op);
}
@Override
public String toString() {
return String.format(FMT_Load, this.opcode(), slot());
}
@Override
public int slot() {
return switch (sizeInBytes()) {
case 2 -> code.classReader.readU1(pos + 1);
case 4 -> code.classReader.readU2(pos + 2);
default -> throw new IllegalArgumentException("Unexpected op size: " + op.sizeIfFixed() + " -- " + op);
};
}
}
public static final class BoundStoreInstruction
extends BoundInstruction implements StoreInstruction {
public BoundStoreInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public TypeKind typeKind() {
return BytecodeHelpers.storeType(op);
}
@Override
public String toString() {
return String.format(FMT_Store, this.opcode(), slot());
}
@Override
public int slot() {
return switch (sizeInBytes()) {
case 2 -> code.classReader.readU1(pos + 1);
case 4 -> code.classReader.readU2(pos + 2);
default -> throw new IllegalArgumentException("Unexpected op size: " + sizeInBytes() + " -- " + op);
};
}
}
public static final class BoundIncrementInstruction
extends BoundInstruction implements IncrementInstruction {
public BoundIncrementInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public int slot() {
return sizeInBytes() == 6 ? code.classReader.readU2(pos + 2) : code.classReader.readU1(pos + 1);
}
@Override
public int constant() {
return sizeInBytes() == 6 ? code.classReader.readS2(pos + 4) : code.classReader.readS1(pos + 2);
}
@Override
public String toString() {
return String.format(FMT_Increment, this.opcode(), slot(), constant());
}
}
public static final class BoundBranchInstruction
extends BoundInstruction implements BranchInstruction {
public BoundBranchInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public Label target() {
return offsetToLabel(branchByteOffset());
}
public int branchByteOffset() {
return sizeInBytes() == 3
? code.classReader.readS2(pos + 1)
: code.classReader.readInt(pos + 1);
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeBranch(opcode(), target());
}
@Override
public String toString() {
return String.format(FMT_Branch, this.opcode());
}
}
public record SwitchCaseImpl(int caseValue, Label target)
implements SwitchCase {
public SwitchCaseImpl {
requireNonNull(target);
}
}
public static final class BoundLookupSwitchInstruction
extends BoundInstruction implements LookupSwitchInstruction {
// will always need size, cache everything to there
private final int afterPad;
private final int npairs;
private final int size;
BoundLookupSwitchInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
this.afterPad = code.codeStart + RawBytecodeHelper.align(pos + 1 - code.codeStart);
this.npairs = code.classReader.readInt(afterPad + 4);
if (npairs < 0 || npairs > code.codeLength >> 3) {
throw new IllegalArgumentException("Invalid lookupswitch npairs value: " + npairs);
}
this.size = afterPad + 8 + npairs * 8 - pos;
}
private int defaultOffset() {
return code.classReader.readInt(afterPad);
}
@Override
public int sizeInBytes() {
return size;
}
@Override
public List cases() {
var cases = new SwitchCase[npairs];
for (int i = 0, z = afterPad + 8; i < npairs; ++i, z += 8) {
cases[i] = SwitchCase.of(code.classReader.readInt(z), offsetToLabel(code.classReader.readInt(z + 4)));
}
return List.of(cases);
}
@Override
public Label defaultTarget() {
return offsetToLabel(defaultOffset());
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeLookupSwitch(defaultTarget(), cases());
}
@Override
public String toString() {
return String.format(FMT_LookupSwitch, this.opcode());
}
}
public static final class BoundTableSwitchInstruction
extends BoundInstruction implements TableSwitchInstruction {
private final int afterPad;
private final int low;
private final int high;
private final int size;
BoundTableSwitchInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
afterPad = code.codeStart + RawBytecodeHelper.align(pos + 1 - code.codeStart);
low = code.classReader.readInt(afterPad + 4);
high = code.classReader.readInt(afterPad + 8);
if (high < low || (long)high - low > code.codeLength >> 2) {
throw new IllegalArgumentException("Invalid tableswitch values low: " + low + " high: " + high);
}
int cnt = high - low + 1;
size = afterPad + 12 + cnt * 4 - pos;
}
@Override
public int sizeInBytes() {
return size;
}
@Override
public Label defaultTarget() {
return offsetToLabel(defaultOffset());
}
@Override
public int lowValue() {
return low;
}
@Override
public int highValue() {
return high;
}
@Override
public List cases() {
int low = lowValue();
int high = highValue();
int defOff = defaultOffset();
var cases = new ArrayList(high - low + 1);
for (int i = low, z = afterPad + 12; i <= high; ++i, z += 4) {
int off = code.classReader.readInt(z);
if (defOff != off) {
cases.add(SwitchCase.of(i, offsetToLabel(off)));
}
}
return Collections.unmodifiableList(cases);
}
private int defaultOffset() {
return code.classReader.readInt(afterPad);
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeTableSwitch(lowValue(), highValue(), defaultTarget(), cases());
}
@Override
public String toString() {
return String.format(FMT_TableSwitch, this.opcode());
}
}
public static final class BoundFieldInstruction
extends BoundInstruction implements FieldInstruction {
private FieldRefEntry fieldEntry;
public BoundFieldInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public FieldRefEntry field() {
if (fieldEntry == null)
fieldEntry = code.classReader.readEntry(pos + 1, FieldRefEntry.class);
return fieldEntry;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
if (writer.canWriteDirect(code.constantPool()))
super.writeTo(writer);
else
writer.writeFieldAccess(op, field());
}
@Override
public String toString() {
return String.format(FMT_Field, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue());
}
}
public static final class BoundInvokeInstruction
extends BoundInstruction implements InvokeInstruction {
MemberRefEntry methodEntry;
public BoundInvokeInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public MemberRefEntry method() {
if (methodEntry == null)
methodEntry = code.classReader.readEntry(pos + 1, MemberRefEntry.class);
return methodEntry;
}
@Override
public boolean isInterface() {
return method().tag() == PoolEntry.TAG_INTERFACE_METHODREF;
}
@Override
public int count() {
return 0;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
if (writer.canWriteDirect(code.constantPool()))
super.writeTo(writer);
else
writer.writeInvokeNormal(op, method());
}
@Override
public String toString() {
return String.format(FMT_Invoke, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue());
}
}
public static final class BoundInvokeInterfaceInstruction
extends BoundInstruction implements InvokeInstruction {
InterfaceMethodRefEntry methodEntry;
public BoundInvokeInterfaceInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public MemberRefEntry method() {
if (methodEntry == null)
methodEntry = code.classReader.readEntry(pos + 1, InterfaceMethodRefEntry.class);
return methodEntry;
}
@Override
public int count() {
return code.classReader.readU1(pos + 3);
}
@Override
public boolean isInterface() {
return true;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
if (writer.canWriteDirect(code.constantPool()))
super.writeTo(writer);
else
writer.writeInvokeInterface(op, (InterfaceMethodRefEntry) method(), count());
}
@Override
public String toString() {
return String.format(FMT_InvokeInterface, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue());
}
}
public static final class BoundInvokeDynamicInstruction
extends BoundInstruction implements InvokeDynamicInstruction {
InvokeDynamicEntry indyEntry;
BoundInvokeDynamicInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public InvokeDynamicEntry invokedynamic() {
if (indyEntry == null)
indyEntry = code.classReader.readEntry(pos + 1, InvokeDynamicEntry.class);
return indyEntry;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
if (writer.canWriteDirect(code.constantPool()))
super.writeTo(writer);
else
writer.writeInvokeDynamic(invokedynamic());
}
@Override
public String toString() {
return String.format(FMT_InvokeDynamic, this.opcode(), bootstrapMethod(), bootstrapArgs());
}
}
public static final class BoundNewObjectInstruction
extends BoundInstruction implements NewObjectInstruction {
ClassEntry classEntry;
BoundNewObjectInstruction(CodeImpl code, int pos) {
super(Opcode.NEW, code, pos);
}
@Override
public ClassEntry className() {
if (classEntry == null)
classEntry = code.classReader.readEntry(pos + 1, ClassEntry.class);
return classEntry;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
if (writer.canWriteDirect(code.constantPool()))
super.writeTo(writer);
else
writer.writeNewObject(className());
}
@Override
public String toString() {
return String.format(FMT_NewObj, this.opcode(), className().asInternalName());
}
}
public static final class BoundNewPrimitiveArrayInstruction
extends BoundInstruction implements NewPrimitiveArrayInstruction {
public BoundNewPrimitiveArrayInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public TypeKind typeKind() {
return TypeKind.fromNewarrayCode(code.classReader.readU1(pos + 1));
}
@Override
public String toString() {
return String.format(FMT_NewPrimitiveArray, this.opcode(), typeKind());
}
}
public static final class BoundNewReferenceArrayInstruction
extends BoundInstruction implements NewReferenceArrayInstruction {
public BoundNewReferenceArrayInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public ClassEntry componentType() {
return code.classReader.readEntry(pos + 1, ClassEntry.class);
}
@Override
public void writeTo(DirectCodeBuilder writer) {
if (writer.canWriteDirect(code.constantPool()))
super.writeTo(writer);
else
writer.writeNewReferenceArray(componentType());
}
@Override
public String toString() {
return String.format(FMT_NewRefArray, this.opcode(), componentType().asInternalName());
}
}
public static final class BoundNewMultidimensionalArrayInstruction
extends BoundInstruction implements NewMultiArrayInstruction {
public BoundNewMultidimensionalArrayInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public int dimensions() {
return code.classReader.readU1(pos + 3);
}
@Override
public ClassEntry arrayType() {
return code.classReader.readEntry(pos + 1, ClassEntry.class);
}
@Override
public void writeTo(DirectCodeBuilder writer) {
if (writer.canWriteDirect(code.constantPool()))
super.writeTo(writer);
else
writer.writeNewMultidimensionalArray(dimensions(), arrayType());
}
@Override
public String toString() {
return String.format(FMT_NewMultiArray, this.opcode(), arrayType().asInternalName(), dimensions());
}
}
public static final class BoundTypeCheckInstruction
extends BoundInstruction implements TypeCheckInstruction {
ClassEntry typeEntry;
public BoundTypeCheckInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public ClassEntry type() {
if (typeEntry == null)
typeEntry = code.classReader.readEntry(pos + 1, ClassEntry.class);
return typeEntry;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
if (writer.canWriteDirect(code.constantPool()))
super.writeTo(writer);
else
writer.writeTypeCheck(op, type());
}
@Override
public String toString() {
return String.format(FMT_TypeCheck, this.opcode(), type().asInternalName());
}
}
public static final class BoundArgumentConstantInstruction
extends BoundInstruction implements ConstantInstruction.ArgumentConstantInstruction {
public BoundArgumentConstantInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public Integer constantValue() {
return constantInt();
}
public int constantInt() {
return sizeInBytes() == 3 ? code.classReader.readS2(pos + 1) : code.classReader.readS1(pos + 1);
}
@Override
public String toString() {
return String.format(FMT_ArgumentConstant, this.opcode(), constantValue());
}
}
public static final class BoundLoadConstantInstruction
extends BoundInstruction implements ConstantInstruction.LoadConstantInstruction {
public BoundLoadConstantInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public LoadableConstantEntry constantEntry() {
return code.classReader.entryByIndex(op == Opcode.LDC
? code.classReader.readU1(pos + 1)
: code.classReader.readU2(pos + 1),
LoadableConstantEntry.class);
}
@Override
public ConstantDesc constantValue() {
return constantEntry().constantValue();
}
@Override
public void writeTo(DirectCodeBuilder writer) {
if (writer.canWriteDirect(code.constantPool()))
super.writeTo(writer);
else
// We have writer.canWriteDirect(constantEntry().constantPool()) == false
writer.writeAdaptLoadConstant(op, constantEntry());
}
@Override
public String toString() {
return String.format(FMT_LoadConstant, this.opcode(), constantValue());
}
}
public static final class BoundJsrInstruction
extends BoundInstruction implements DiscontinuedInstruction.JsrInstruction {
public BoundJsrInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public Label target() {
return offsetToLabel(branchByteOffset());
}
public int branchByteOffset() {
return sizeInBytes() == 3
? code.classReader.readS2(pos + 1)
: code.classReader.readInt(pos + 1);
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeBranch(opcode(), target());
}
@Override
public String toString() {
return String.format(FMT_Discontinued, this.opcode());
}
}
public static final class BoundRetInstruction
extends BoundInstruction implements DiscontinuedInstruction.RetInstruction {
public BoundRetInstruction(Opcode op, CodeImpl code, int pos) {
super(op, code, pos);
}
@Override
public String toString() {
return String.format(FMT_Discontinued, this.opcode());
}
@Override
public int slot() {
return switch (sizeInBytes()) {
case 2 -> code.classReader.readU1(pos + 1);
case 4 -> code.classReader.readU2(pos + 2);
default -> throw new IllegalArgumentException("Unexpected op size: " + op.sizeIfFixed() + " -- " + op);
};
}
}
public abstract static sealed class UnboundInstruction extends AbstractInstruction {
UnboundInstruction(Opcode op) {
super(op);
}
@Override
// Override this if there is anything more that just the bytecode
public void writeTo(DirectCodeBuilder writer) {
writer.writeBytecode(op);
}
@Override
public String toString() {
return String.format(FMT_Unbound, this.getClass().getSimpleName(), op);
}
}
public static final class UnboundLoadInstruction
extends UnboundInstruction implements LoadInstruction {
final int slot;
public UnboundLoadInstruction(Opcode op, int slot) {
super(op);
this.slot = slot;
}
@Override
public int slot() {
return slot;
}
@Override
public TypeKind typeKind() {
return BytecodeHelpers.loadType(op);
}
@Override
public void writeTo(DirectCodeBuilder writer) {
var op = this.op;
if (op.sizeIfFixed() == 1) {
writer.writeBytecode(op);
} else {
writer.writeLocalVar(op, slot);
}
}
@Override
public String toString() {
return String.format(FMT_Load, this.opcode(), slot());
}
}
public static final class UnboundStoreInstruction
extends UnboundInstruction implements StoreInstruction {
final int slot;
public UnboundStoreInstruction(Opcode op, int slot) {
super(op);
this.slot = slot;
}
@Override
public int slot() {
return slot;
}
@Override
public TypeKind typeKind() {
return BytecodeHelpers.storeType(op);
}
@Override
public void writeTo(DirectCodeBuilder writer) {
var op = this.op;
if (op.sizeIfFixed() == 1) {
writer.writeBytecode(op);
} else {
writer.writeLocalVar(op, slot);
}
}
@Override
public String toString() {
return String.format(FMT_Store, this.opcode(), slot());
}
}
public static final class UnboundIncrementInstruction
extends UnboundInstruction implements IncrementInstruction {
final int slot;
final int constant;
public UnboundIncrementInstruction(int slot, int constant) {
super(BytecodeHelpers.validateAndIsWideIinc(slot, constant)
? Opcode.IINC_W
: Opcode.IINC);
this.slot = slot;
this.constant = constant;
}
@Override
public int slot() {
return slot;
}
@Override
public int constant() {
return constant;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeIncrement(op == Opcode.IINC_W, slot, constant);
}
@Override
public String toString() {
return String.format(FMT_Increment, this.opcode(), slot(), constant());
}
}
public static final class UnboundBranchInstruction
extends UnboundInstruction implements BranchInstruction {
final Label target;
public UnboundBranchInstruction(Opcode op, Label target) {
super(op);
this.target = requireNonNull(target);
}
@Override
public Label target() {
return target;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeBranch(op, target);
}
@Override
public String toString() {
return String.format(FMT_Branch, this.opcode());
}
}
public static final class UnboundLookupSwitchInstruction
extends UnboundInstruction implements LookupSwitchInstruction {
private final Label defaultTarget;
private final List cases;
public UnboundLookupSwitchInstruction(Label defaultTarget, List cases) {
super(Opcode.LOOKUPSWITCH);
this.defaultTarget = requireNonNull(defaultTarget);
this.cases = List.copyOf(cases);
}
@Override
public List cases() {
return cases;
}
@Override
public Label defaultTarget() {
return defaultTarget;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeLookupSwitch(defaultTarget, cases);
}
@Override
public String toString() {
return String.format(FMT_LookupSwitch, this.opcode());
}
}
public static final class UnboundTableSwitchInstruction
extends UnboundInstruction implements TableSwitchInstruction {
private final int lowValue, highValue;
private final Label defaultTarget;
private final List cases;
public UnboundTableSwitchInstruction(int lowValue, int highValue, Label defaultTarget, List cases) {
super(Opcode.TABLESWITCH);
this.lowValue = lowValue;
this.highValue = highValue;
this.defaultTarget = requireNonNull(defaultTarget);
this.cases = List.copyOf(cases);
}
@Override
public int lowValue() {
return lowValue;
}
@Override
public int highValue() {
return highValue;
}
@Override
public Label defaultTarget() {
return defaultTarget;
}
@Override
public List cases() {
return cases;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeTableSwitch(lowValue, highValue, defaultTarget, cases);
}
@Override
public String toString() {
return String.format(FMT_TableSwitch, this.opcode());
}
}
public static final class UnboundReturnInstruction
extends UnboundInstruction implements ReturnInstruction {
public UnboundReturnInstruction(Opcode op) {
super(op);
}
@Override
public TypeKind typeKind() {
return BytecodeHelpers.returnType(op);
}
@Override
public String toString() {
return String.format(FMT_Return, this.opcode());
}
}
public static final class UnboundThrowInstruction
extends UnboundInstruction implements ThrowInstruction {
public UnboundThrowInstruction() {
super(Opcode.ATHROW);
}
@Override
public String toString() {
return String.format(FMT_Throw, this.opcode());
}
}
public static final class UnboundFieldInstruction
extends UnboundInstruction implements FieldInstruction {
final FieldRefEntry fieldEntry;
public UnboundFieldInstruction(Opcode op,
FieldRefEntry fieldEntry) {
super(op);
this.fieldEntry = requireNonNull(fieldEntry);
}
@Override
public FieldRefEntry field() {
return fieldEntry;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeFieldAccess(op, fieldEntry);
}
@Override
public String toString() {
return String.format(FMT_Field, this.opcode(), this.owner().asInternalName(), this.name().stringValue(), this.type().stringValue());
}
}
public static final class UnboundInvokeInstruction
extends UnboundInstruction implements InvokeInstruction {
final MemberRefEntry methodEntry;
public UnboundInvokeInstruction(Opcode op, MemberRefEntry methodEntry) {
super(op);
this.methodEntry = requireNonNull(methodEntry);
}
@Override
public MemberRefEntry method() {
return methodEntry;
}
@Override
public boolean isInterface() {
return op == Opcode.INVOKEINTERFACE || methodEntry instanceof InterfaceMethodRefEntry;
}
@Override
public int count() {
return op == Opcode.INVOKEINTERFACE
? Util.parameterSlots(Util.methodTypeSymbol(methodEntry.type())) + 1
: 0;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
if (op == Opcode.INVOKEINTERFACE)
writer.writeInvokeInterface(op, (InterfaceMethodRefEntry) method(), count());
else
writer.writeInvokeNormal(op, method());
}
@Override
public String toString() {
return String.format(FMT_Invoke, this.opcode(), owner().asInternalName(), name().stringValue(), type().stringValue());
}
}
public static final class UnboundInvokeDynamicInstruction
extends UnboundInstruction implements InvokeDynamicInstruction {
final InvokeDynamicEntry indyEntry;
public UnboundInvokeDynamicInstruction(InvokeDynamicEntry indyEntry) {
super(Opcode.INVOKEDYNAMIC);
this.indyEntry = requireNonNull(indyEntry);
}
@Override
public InvokeDynamicEntry invokedynamic() {
return indyEntry;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeInvokeDynamic(invokedynamic());
}
@Override
public String toString() {
return String.format(FMT_InvokeDynamic, this.opcode(), bootstrapMethod(), bootstrapArgs());
}
}
public static final class UnboundNewObjectInstruction
extends UnboundInstruction implements NewObjectInstruction {
final ClassEntry classEntry;
public UnboundNewObjectInstruction(ClassEntry classEntry) {
super(Opcode.NEW);
this.classEntry = requireNonNull(classEntry);
}
@Override
public ClassEntry className() {
return classEntry;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeNewObject(className());
}
@Override
public String toString() {
return String.format(FMT_NewObj, this.opcode(), className().asInternalName());
}
}
public static final class UnboundNewPrimitiveArrayInstruction
extends UnboundInstruction implements NewPrimitiveArrayInstruction {
final TypeKind typeKind;
public UnboundNewPrimitiveArrayInstruction(TypeKind typeKind) {
super(Opcode.NEWARRAY);
this.typeKind = requireNonNull(typeKind);
}
@Override
public TypeKind typeKind() {
return typeKind;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeNewPrimitiveArray(typeKind.newarrayCode());
}
@Override
public String toString() {
return String.format(FMT_NewPrimitiveArray, this.opcode(), typeKind());
}
}
public static final class UnboundNewReferenceArrayInstruction
extends UnboundInstruction implements NewReferenceArrayInstruction {
final ClassEntry componentTypeEntry;
public UnboundNewReferenceArrayInstruction(ClassEntry componentTypeEntry) {
super(Opcode.ANEWARRAY);
this.componentTypeEntry = requireNonNull(componentTypeEntry);
}
@Override
public ClassEntry componentType() {
return componentTypeEntry;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeNewReferenceArray(componentType());
}
@Override
public String toString() {
return String.format(FMT_NewRefArray, this.opcode(), componentType().asInternalName());
}
}
public static final class UnboundNewMultidimensionalArrayInstruction
extends UnboundInstruction implements NewMultiArrayInstruction {
final ClassEntry arrayTypeEntry;
final int dimensions;
public UnboundNewMultidimensionalArrayInstruction(ClassEntry arrayTypeEntry,
int dimensions) {
super(Opcode.MULTIANEWARRAY);
this.arrayTypeEntry = requireNonNull(arrayTypeEntry);
this.dimensions = dimensions;
}
@Override
public int dimensions() {
return dimensions;
}
@Override
public ClassEntry arrayType() {
return arrayTypeEntry;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeNewMultidimensionalArray(dimensions(), arrayType());
}
@Override
public String toString() {
return String.format(FMT_NewMultiArray, this.opcode(), arrayType().asInternalName(), dimensions());
}
}
public static final class UnboundArrayLoadInstruction
extends UnboundInstruction implements ArrayLoadInstruction {
public UnboundArrayLoadInstruction(Opcode op) {
super(op);
}
@Override
public TypeKind typeKind() {
return BytecodeHelpers.arrayLoadType(op);
}
}
public static final class UnboundArrayStoreInstruction
extends UnboundInstruction implements ArrayStoreInstruction {
public UnboundArrayStoreInstruction(Opcode op) {
super(op);
}
@Override
public TypeKind typeKind() {
return BytecodeHelpers.arrayStoreType(op);
}
}
public static final class UnboundTypeCheckInstruction
extends UnboundInstruction implements TypeCheckInstruction {
final ClassEntry typeEntry;
public UnboundTypeCheckInstruction(Opcode op, ClassEntry typeEntry) {
super(op);
this.typeEntry = requireNonNull(typeEntry);
}
@Override
public ClassEntry type() {
return typeEntry;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeTypeCheck(op, type());
}
@Override
public String toString() {
return String.format(FMT_TypeCheck, this.opcode(), type().asInternalName());
}
}
public static final class UnboundStackInstruction
extends UnboundInstruction implements StackInstruction {
public UnboundStackInstruction(Opcode op) {
super(op);
}
}
public static final class UnboundConvertInstruction
extends UnboundInstruction implements ConvertInstruction {
public UnboundConvertInstruction(Opcode op) {
super(op);
}
@Override
public TypeKind fromType() {
return BytecodeHelpers.convertFromType(op);
}
@Override
public TypeKind toType() {
return BytecodeHelpers.convertToType(op);
}
}
public static final class UnboundOperatorInstruction
extends UnboundInstruction implements OperatorInstruction {
public UnboundOperatorInstruction(Opcode op) {
super(op);
}
@Override
public TypeKind typeKind() {
return BytecodeHelpers.operatorOperandType(op);
}
}
public static final class UnboundIntrinsicConstantInstruction
extends UnboundInstruction implements ConstantInstruction.IntrinsicConstantInstruction {
public UnboundIntrinsicConstantInstruction(Opcode op) {
super(op);
}
@Override
public ConstantDesc constantValue() {
return BytecodeHelpers.intrinsicConstantValue(op);
}
}
public static final class UnboundArgumentConstantInstruction
extends UnboundInstruction implements ConstantInstruction.ArgumentConstantInstruction {
final int value;
public UnboundArgumentConstantInstruction(Opcode op, int value) {
super(op);
this.value = value;
}
@Override
public Integer constantValue() {
return value;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeArgumentConstant(op, value);
}
@Override
public String toString() {
return String.format(FMT_ArgumentConstant, this.opcode(), constantValue());
}
}
public static final class UnboundLoadConstantInstruction
extends UnboundInstruction implements ConstantInstruction.LoadConstantInstruction {
final LoadableConstantEntry constant;
public UnboundLoadConstantInstruction(Opcode op, LoadableConstantEntry constant) {
super(op);
this.constant = requireNonNull(constant);
}
@Override
public LoadableConstantEntry constantEntry() {
return constant;
}
@Override
public ConstantDesc constantValue() {
return constant.constantValue();
}
@Override
public void writeTo(DirectCodeBuilder writer) {
var constant = this.constant;
if (writer.canWriteDirect(constant.constantPool()))
// Allows writing ldc_w small index constants upon user request
writer.writeDirectLoadConstant(op, constant);
else
writer.writeAdaptLoadConstant(op, constant);
}
@Override
public String toString() {
return String.format(FMT_LoadConstant, this.opcode(), constantValue());
}
}
public static final class UnboundMonitorInstruction
extends UnboundInstruction implements MonitorInstruction {
public UnboundMonitorInstruction(Opcode op) {
super(op);
}
}
public static final class UnboundNopInstruction
extends UnboundInstruction implements NopInstruction {
public UnboundNopInstruction() {
super(Opcode.NOP);
}
}
public static final class UnboundJsrInstruction
extends UnboundInstruction implements DiscontinuedInstruction.JsrInstruction {
final Label target;
public UnboundJsrInstruction(Opcode op, Label target) {
super(op);
this.target = requireNonNull(target);
}
@Override
public Label target() {
return target;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeBranch(op, target);
}
@Override
public String toString() {
return String.format(FMT_Discontinued, this.opcode());
}
}
public static final class UnboundRetInstruction
extends UnboundInstruction implements DiscontinuedInstruction.RetInstruction {
final int slot;
public UnboundRetInstruction(Opcode op, int slot) {
super(op);
this.slot = slot;
}
@Override
public int slot() {
return slot;
}
@Override
public void writeTo(DirectCodeBuilder writer) {
writer.writeLocalVar(op, slot);
}
@Override
public String toString() {
return String.format(FMT_Discontinued, this.opcode());
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy