jdk/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java
2025-01-15 02:04:01 +00:00

195 lines
8.1 KiB
Java

/*
* Copyright (c) 2023, 2025, 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 java.lang.classfile.instruction;
import java.lang.classfile.*;
import java.lang.classfile.attribute.StackMapTableAttribute;
import jdk.internal.classfile.impl.AbstractInstruction;
import jdk.internal.classfile.impl.BytecodeHelpers;
import jdk.internal.classfile.impl.Util;
/**
* Marker interface for instruction discontinued from the {@code code} array of
* a {@code Code} attribute. Delivered as a {@link CodeElement} when traversing
* the elements of a {@link CodeModel}.
*
* @apiNote
* While most instructions have convenience factory methods in {@link
* CodeBuilder}, discontinued instructions can only be supplied to code builders
* explicitly with {@link CodeBuilder#with CodeBuilder::with} to discourage
* their use.
*
* @jvms 4.9.1 Static Constraints
* @sealedGraph
* @since 24
*/
public sealed interface DiscontinuedInstruction extends Instruction {
/**
* Models jump subroutine instructions discontinued from the {@code code}
* array of a {@code Code} attribute since class file major version {@value
* ClassFile#JAVA_7_VERSION} (JVMS {@jvms 4.9.1}). Corresponding opcodes
* have a {@linkplain Opcode#kind() kind} of {@link Opcode.Kind#DISCONTINUED_JSR}.
* Delivered as a {@link CodeElement} when traversing the elements of a
* {@link CodeModel}.
* <p>
* A jump subroutine instruction is composite:
* {@snippet lang=text :
* // @link substring="JsrInstruction" target="#of(Label)" :
* JsrInstruction(Label target) // @link substring="target" target="#target()"
* }
* <p>
* Due to physical restrictions, {@link Opcode#JSR jsr} instructions cannot
* encode labels too far away in the list of code elements. In such cases,
* the {@link ClassFile.ShortJumpsOption} controls how an invalid {@code jsr}
* instruction model is written by a {@link CodeBuilder}.
* <p>
* Jump subroutine instructions push a {@link TypeKind##returnAddress
* returnAddress} value to the operand stack, and {@link StoreInstruction
* astore} series of instructions can then store this value to a local
* variable slot.
*
* @apiNote
* Jump subroutine instructions are discontinued to enforce verification by
* type checking (JVMS {@jvms 4.10.1}) using the {@link StackMapTableAttribute
* StackMapTable} attribute.
*
* @see Opcode.Kind#DISCONTINUED_JSR
* @see StackMapTableAttribute
* @since 24
*/
sealed interface JsrInstruction extends DiscontinuedInstruction
permits AbstractInstruction.BoundJsrInstruction,
AbstractInstruction.UnboundJsrInstruction {
/**
* {@return the target of the jump subroutine instruction}
*/
Label target();
/**
* {@return a jump subroutine instruction}
*
* @apiNote
* The explicit {@code op} argument allows creating {@link Opcode#JSR_W
* jsr_w} instructions to avoid short jumps.
*
* @param op the opcode for the specific type of jump subroutine instruction,
* which must be of kind {@link Opcode.Kind#DISCONTINUED_JSR}
* @param target target label of the subroutine
* @throws IllegalArgumentException if the opcode kind is not
* {@link Opcode.Kind#DISCONTINUED_JSR}.
*/
static JsrInstruction of(Opcode op, Label target) {
Util.checkKind(op, Opcode.Kind.DISCONTINUED_JSR);
return new AbstractInstruction.UnboundJsrInstruction(op, target);
}
/**
* {@return a jump subroutine instruction}
*
* @param target target label of the subroutine
*/
static JsrInstruction of(Label target) {
return of(Opcode.JSR, target);
}
}
/**
* Models return from subroutine instructions discontinued from the {@code
* code} array of a {@code Code} attribute since class file major version
* {@value ClassFile#JAVA_7_VERSION} (JVMS {@jvms 4.9.1}).
* Corresponding opcodes have a {@linkplain Opcode#kind() kind} of
* {@link Opcode.Kind#DISCONTINUED_RET}. Delivered as a {@link CodeElement}
* when traversing the elements of a {@link CodeModel}.
* <p>
* A return from subroutine instruction is composite:
* {@snippet lang=text :
* // @link substring="RetInstruction" target="#of(int)" :
* RetInstruction(int slot) // @link substring="slot" target="#slot()"
* }
* where {@code slot} must be within {@code [0, 65535]}.
* <p>
* {@link StoreInstruction astore} series of instructions store a {@link
* TypeKind##returnAddress returnAddress} value to a local variable slot,
* making the slot usable by a return from subroutine instruction.
*
* @apiNote
* Return from subroutine instructions are discontinued to enforce
* verification by type checking (JVMS {@jvms 4.10.1}) using the {@link
* StackMapTableAttribute StackMapTable} attribute.
*
* @jvms 6.5.ret <em>ret</em>
* @see Opcode.Kind#DISCONTINUED_RET
* @see StackMapTableAttribute
* @since 24
*/
sealed interface RetInstruction extends DiscontinuedInstruction
permits AbstractInstruction.BoundRetInstruction,
AbstractInstruction.UnboundRetInstruction {
/**
* {@return the local variable slot with return address}
* The value is within {@code [0, 65535]}.
*/
int slot();
/**
* {@return a return from subroutine instruction}
* <p>
* {@code slot} must be in the closed range of {@code [0, 255]} for
* {@link Opcode#RET ret}, or within {@code [0, 65535]} for {@link
* Opcode#RET_W wide ret}.
*
* @apiNote
* The explicit {@code op} argument allows creating {@code wide ret}
* instructions with {@code slot} in the range of regular {@code ret}
* instructions.
*
* @param op the opcode for the specific type of return from subroutine instruction,
* which must be of kind {@link Opcode.Kind#DISCONTINUED_RET}
* @param slot the local variable slot to load return address from
* @throws IllegalArgumentException if the opcode kind is not
* {@link Opcode.Kind#DISCONTINUED_RET} or if {@code slot} is out of range
*/
static RetInstruction of(Opcode op, int slot) {
BytecodeHelpers.validateRet(op, slot);
return new AbstractInstruction.UnboundRetInstruction(op, slot);
}
/**
* {@return a return from subroutine instruction}
* <p>
* {@code slot} must be within {@code [0, 65535]}.
*
* @param slot the local variable slot to load return address from
* @throws IllegalArgumentException if {@code slot} is out of range
*/
static RetInstruction of(int slot) {
return of(slot < 256 ? Opcode.RET : Opcode.RET_W, slot);
}
}
}