/*
* Copyright (c) 2012, 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 com.oracle.max.vm.ext.t1x;
import static com.oracle.max.vm.ext.t1x.T1XTemplateTag.*;
import static com.sun.max.vm.MaxineVM.*;
import static com.sun.max.vm.stack.JVMSFrameLayout.*;
import java.util.*;
import com.oracle.max.asm.*;
import com.oracle.max.vm.ext.t1x.T1XTemplate.Arg;
import com.oracle.max.vm.ext.t1x.T1XTemplate.ObjectLiteral;
import com.oracle.max.vm.ext.t1x.T1XTemplate.SafepointsBuilder;
import com.oracle.max.vm.ext.t1x.T1XTemplate.Sig;
import com.sun.cri.bytecode.*;
import com.sun.cri.ci.*;
import com.sun.cri.ci.CiTargetMethod.CodeAnnotation;
import com.sun.max.annotate.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.*;
import com.sun.max.vm.actor.*;
import com.sun.max.vm.actor.holder.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.classfile.*;
import com.sun.max.vm.classfile.constant.*;
import com.sun.max.vm.compiler.*;
import com.sun.max.vm.compiler.target.*;
import com.sun.max.vm.intrinsics.*;
import com.sun.max.vm.profile.*;
import com.sun.max.vm.runtime.*;
import com.sun.max.vm.stack.*;
import com.sun.max.vm.type.*;
import com.sun.max.vm.verifier.*;
/**
* T1X per-compilation information.
* <p>
* This class is designed such that a single instance can be re-used for
* separate compilations.
*/
public abstract class T1XCompilation {
// Static info
protected static final AdapterGenerator adapterGenerator = AdapterGenerator.forCallee(null, CallEntryPoint.BASELINE_ENTRY_POINT);
protected static final CiRegister scratch = vm().registerConfigs.standard.getScratchRegister();
protected static final CiRegister scratch2 = vm().registerConfigs.standard.getReturnRegister(CiKind.Int);
protected static final CiRegister sp = vm().registerConfigs.bytecodeTemplate.getRegisterForRole(VMRegister.ABI_SP);
protected static final CiRegister fp = vm().registerConfigs.bytecodeTemplate.getRegisterForRole(VMRegister.ABI_FP);
protected static final CiValue SP = sp.asValue();
protected static final CiValue FP = fp.asValue();
private static final int WORDS_PER_SLOT = JVMS_SLOT_SIZE / Word.size();
protected static final int HALFWORD_OFFSET_IN_WORD = JVMSFrameLayout.offsetWithinWord(Kind.INT);
protected static final CiAddress[] SP_WORD_ADDRESSES_CACHE = new CiAddress[4];
protected static final CiAddress[] SP_LONG_ADDRESSES_CACHE = new CiAddress[4];
protected static final CiAddress[] SP_INT_ADDRESSES_CACHE = new CiAddress[4];
protected static final int FP_SLOTS_CACHE_START_OFFSET = -(20 * JVMS_SLOT_SIZE);
protected static final int FP_SLOTS_CACHE_END_OFFSET = 40 * JVMS_SLOT_SIZE;
protected static final CiAddress[] FP_SLOTS_CACHE = new CiAddress[(FP_SLOTS_CACHE_END_OFFSET - FP_SLOTS_CACHE_START_OFFSET) / JVMS_SLOT_SIZE];
static {
for (int i = 0; i < SP_WORD_ADDRESSES_CACHE.length; i++) {
SP_WORD_ADDRESSES_CACHE[i] = new CiAddress(WordUtil.archKind(), SP, i * JVMS_SLOT_SIZE);
}
for (int i = 0; i < SP_LONG_ADDRESSES_CACHE.length; i++) {
SP_LONG_ADDRESSES_CACHE[i] = new CiAddress(CiKind.Long, SP, (i + 1) * JVMS_SLOT_SIZE);
}
for (int i = 0; i < SP_INT_ADDRESSES_CACHE.length; i++) {
SP_INT_ADDRESSES_CACHE[i] = new CiAddress(CiKind.Int, SP, (i * JVMS_SLOT_SIZE) + HALFWORD_OFFSET_IN_WORD);
}
int offset = FP_SLOTS_CACHE_START_OFFSET;
for (int i = 0; i < FP_SLOTS_CACHE.length; i++) {
FP_SLOTS_CACHE[i] = new CiAddress(CiKind.Int, FP, offset);
offset += JVMS_SLOT_SIZE;
}
}
/**
* Gets the effective address of a word-sized operand stack slot.
*
* @param index an operand stack index where 0 is the top slot, 1 is the slot below it etc
* @return the effective address of the operand stack slot at index {@code index} from the top stack slot. This
* value can be used for a word-sized access to the operand stack.
*/
protected static CiAddress spWord(int index) {
assert index >= 0;
if (index < SP_WORD_ADDRESSES_CACHE.length) {
return SP_WORD_ADDRESSES_CACHE[index];
}
return new CiAddress(WordUtil.archKind(), SP, index * JVMS_SLOT_SIZE);
}
/**
* Gets the effective address of an int-sized operand stack slot.
*
* @param index an operand stack index where 0 is the top slot, 1 is the slot below it etc
* @return the effective address of the operand stack slot at index {@code index} from the top stack slot. This
* value can be used for a int-sized access to the operand stack.
*/
protected static CiAddress spInt(int index) {
assert index >= 0;
if (index < SP_INT_ADDRESSES_CACHE.length) {
return SP_INT_ADDRESSES_CACHE[index];
}
return new CiAddress(CiKind.Int, SP, (index * JVMS_SLOT_SIZE) + HALFWORD_OFFSET_IN_WORD);
}
/**
* Gets the effective address of a long or double operand stack slot.
*
* @param index an operand stack index where 0 is the top slot, 1 is the slot below it etc
* @return the effective address of the operand stack slot at index {@code index} from the top stack slot. This
* value can be used for accessing a long or double value on the operand stack.
*/
protected static CiAddress spLong(int index) {
assert index >= 0;
if (index < SP_LONG_ADDRESSES_CACHE.length) {
return SP_LONG_ADDRESSES_CACHE[index];
}
// The value is in the first JVMS slot hence 'index + 1'
return new CiAddress(CiKind.Long, SP, (index + 1) * JVMS_SLOT_SIZE);
}
protected static CiAddress localSlot(int offset) {
assert offset % JVMS_SLOT_SIZE == 0;
int cacheIndex = (offset - FP_SLOTS_CACHE_START_OFFSET) / JVMS_SLOT_SIZE;
if (cacheIndex >= 0 && cacheIndex < FP_SLOTS_CACHE.length) {
return FP_SLOTS_CACHE[cacheIndex];
}
return new CiAddress(CiKind.Int, FP, offset);
}
/**
* The minimum value to which {@link T1XOptions#TraceBytecodeParserLevel} must be set to trace
* the bytecode instructions as they are parsed.
*/
public static final int TRACELEVEL_INSTRUCTIONS = 1;
// Fields holding info/data structures reused across all compilations
/**
* The buffer to which the assembler writes its output.
*/
protected Buffer buf;
/**
* The compiler context.
*/
protected final T1X compiler;
/**
* Object used to aggregate all the stops for the compiled code.
*/
protected final SafepointsBuilder safepointsBuilder = new SafepointsBuilder();
/**
* The set of object literals.
*/
protected final ArrayList<Object> objectLiterals;
/**
* Code annotations for disassembly jump tables (lazily initialized).
*/
protected ArrayList<CodeAnnotation> codeAnnotations;
// Fields holding per-compilation info
/**
* The method being compiled.
*/
protected ClassMethodActor method;
protected CodeAttribute codeAttribute;
/**
* Index for the method protection sentinel (for code eviction) in the reference literals array.
*/
protected int protectionLiteralIndex;
/**
* The last bytecode compiled.
*/
int prevOpcode;
/**
* Access to the bytecode being compiled.
*/
protected BytecodeStream stream;
/**
* Frame info for the method being compiled.
*/
protected JVMSFrameLayout frame;
/**
* The local variable index for a copy of the receiver object locked by a non-static synchronized method.
*/
protected int synchronizedReceiver = -1;
/**
* The first code position in the range covered by the exception handler synthesized for a synchronized method.
*/
int syncHandlerStartPos = -1;
/**
* The code position one past the range covered by the exception handler synthesized for a synchronized method.
*/
int syncHandlerEndPos = -1;
/**
* The first code position where the {@link #synchronizedReceiver} must be in the reference map.
*/
int syncRefMapStartPos = -1;
/**
* The code position one past where the {@link #synchronizedReceiver} must be in the reference map.
*/
int syncRefMapEndPos = -1;
/**
* The code position of the exception handler synthesized for a synchronized method.
*/
int syncMethodHandlerPos = -1;
/**
* Constant pool of the method being compiled.
*/
protected ConstantPool cp;
/**
* The bytecode indexes of the basic blocks.
*/
boolean[] blockBCIs;
/**
* The number of blocks in the method.
*/
int numberOfBlocks;
/**
* The BCIs of the exception handlers.
*/
boolean[] handlerBCIs;
/**
* The exception handlers.
*/
CiExceptionHandler[] handlers;
protected MethodProfile.Builder methodProfileBuilder;
/**
* The template currently being emitted.
*/
protected T1XTemplate template;
/**
* Bit map of which arguments for the current template have been initialized.
*/
private int initializedArgs;
/**
* Map of BCIs to target code positions. Entries in the table corresponding to the start of a bytecode instruction
* hold the position in the code buffer where the first byte of the template was emitted. This map
* includes an entry for the BCI one byte past the end of the bytecode array. This is useful
* for determining the end of the code emitted for the last bytecode instruction. That is, the value at
* {@code bciToPos[bciToPos.length - 1]} is the target code position at which the epilogue starts
* (0 denotes absence of an epilogue).
*/
protected int[] bciToPos;
Adapter adapter;
/**
* When {@code true} denote a compilation for deoptimzation.
*/
private boolean isDeopt;
/**
* Creates a compilation object.
*/
public T1XCompilation(T1X compiler) {
this.compiler = compiler;
this.objectLiterals = new ArrayList<Object>();
}
/**
* Initializes all the per-compilation fields.
*
* @param method the method about to be compiled
*/
protected void initCompile(ClassMethodActor method, CodeAttribute codeAttribute) {
assert this.method == null;
assert buf.position() == 0;
assert objectLiterals.isEmpty();
this.method = method;
this.codeAttribute = codeAttribute;
cp = codeAttribute.cp;
byte[] code = codeAttribute.code();
stream = new BytecodeStream(code);
protectionLiteralIndex = -1;
bciToPos = new int[code.length + 1];
blockBCIs = new boolean[code.length];
methodProfileBuilder = MethodInstrumentation.createMethodProfile(method);
startBlock(0);
initFrame(method, codeAttribute);
initHandlers(method, code);
}
static void startTimer(T1XTimer timer) {
if (T1XOptions.PrintTimers) {
timer.start();
}
}
static void stopTimer(T1XTimer timer) {
if (T1XOptions.PrintTimers) {
timer.stop();
}
}
void initHandlers(ClassMethodActor method, byte[] code) {
handlers = codeAttribute.exceptionHandlers();
if (handlers.length != 0) {
handlerBCIs = new boolean[code.length];
for (CiExceptionHandler handler : handlers) {
handlerBCIs[handler.handlerBCI()] = true;
}
} else {
handlerBCIs = null;
}
}
/**
* Initializes {@link #frame} and {@link #synchronizedReceiver}.
*/
protected abstract void initFrame(ClassMethodActor method, CodeAttribute codeAttribute);
/**
* Cleans up all the per-compilation fields.
*/
protected void cleanup() {
method = null;
codeAttribute = null;
frame = null;
bciToPos = null;
blockBCIs = null;
numberOfBlocks = 0;
stream = null;
handlerBCIs = null;
handlers = null;
syncHandlerStartPos = -1;
syncHandlerEndPos = -1;
syncRefMapStartPos = -1;
syncRefMapEndPos = -1;
synchronizedReceiver = -1;
syncMethodHandlerPos = -1;
cp = null;
buf.reset();
objectLiterals.clear();
if (codeAnnotations != null) {
codeAnnotations.clear();
}
adapter = null;
safepointsBuilder.reset(false);
methodProfileBuilder = null;
template = null;
initializedArgs = 0;
}
/**
* Thrown to indicate that {@link Bytecodes#JSR} or {@link Bytecodes#RET}
* was encountered when compiling a method.
*/
@SuppressWarnings("serial")
class UnsupportedSubroutineException extends RuntimeException {
final int bci;
final int opcode;
public UnsupportedSubroutineException(int opcode, int bci) {
super(Bytecodes.nameOf(opcode) + "@" + bci + " in " + method);
this.bci = bci;
this.opcode = opcode;
}
}
/**
* Translates the bytecode of a given method into a {@link T1XTargetMethod}.
*/
public T1XTargetMethod compile(ClassMethodActor method, boolean isDeopt, boolean install) {
try {
this.isDeopt = isDeopt;
return compile1(method, method.codeAttribute(), install);
} catch (UnsupportedSubroutineException e) {
T1XMetrics.MethodsWithSubroutines++;
if (T1XOptions.PrintJsrRetRewrites) {
Log.println("T1X rewriting bytecode of " + method + " to inline subroutine indicated by " + Bytecodes.nameOf(e.opcode) + " at bci " + e.bci);
}
TypeInferencingVerifier verifier = new TypeInferencingVerifier(method.holder());
CodeAttribute codeAttribute = verifier.verify(method, this.codeAttribute);
cleanup();
return compile1(method, codeAttribute, install);
}
}
private T1XTargetMethod compile1(ClassMethodActor method, CodeAttribute codeAttribute, boolean install) {
startTimer(T1XTimer.PRE_COMPILE);
try {
initCompile(method, codeAttribute);
} finally {
stopTimer(T1XTimer.PRE_COMPILE);
}
startTimer(T1XTimer.COMPILE);
try {
compile2(method);
} finally {
stopTimer(T1XTimer.COMPILE);
}
startTimer(T1XTimer.FIXUP);
try {
int endPos = buf.position();
fixup();
buf.setPosition(endPos);
} finally {
stopTimer(T1XTimer.FIXUP);
}
startTimer(T1XTimer.INSTALL);
try {
return newT1XTargetMethod(this, install);
} finally {
stopTimer(T1XTimer.INSTALL);
}
}
void compile2(ClassMethodActor method) throws InternalError {
adapter = emitPrologue();
emitUnprotectMethod();
do_profileMethodEntry();
do_methodTraceEntry();
do_synchronizedMethodAcquire();
int bci = 0;
int endBCI = stream.endBCI();
while (bci < endBCI) {
int opcode = stream.currentBC();
processBytecode(opcode);
stream.next();
bci = stream.currentBCI();
}
int epiloguePos = buf.position();
do_synchronizedMethodHandler(method, endBCI);
if (epiloguePos != buf.position()) {
bciToPos[endBCI] = epiloguePos;
}
}
/**
* Create a new (subclass) of {@link T1XTargetMethod}.
* @param comp
* @param install
*/
protected T1XTargetMethod newT1XTargetMethod(T1XCompilation comp, boolean install) {
return new T1XTargetMethod(this, install);
}
protected abstract void emitUnprotectMethod();
protected void startBlock(int bci) {
if (!blockBCIs[bci]) {
numberOfBlocks++;
blockBCIs[bci] = true;
}
}
protected void beginBytecode(int representativeOpcode) {
int bci = stream.currentBCI();
int pos = buf.position();
bciToPos[bci] = pos;
if (Bytecodes.isBlockEnd(prevOpcode)) {
startBlock(bci);
if (handlerBCIs != null) {
if (handlerBCIs[bci]) {
emitLoadException(bci);
}
}
}
prevOpcode = representativeOpcode;
}
/**
* Returns the template to use for {@code tag}.
* By default, returns the template in the associated {@link #compiler compiler}
* templates array, but may be overridden by a subclass to make the behavior
* more context sensitive.
* @param tag
*/
protected T1XTemplate getTemplate(T1XTemplateTag tag) {
return compiler.templates[tag.ordinal()];
}
protected void start(T1XTemplateTag tag) {
T1XTemplate template = getTemplate(tag);
assert template != null : "template for tag " + tag + " is null";
start(template);
}
/**
* Starts the process of emitting a template.
* This includes emitting code to copy any arguments from the stack to the
* relevant parameter locations.
* <p>
* A call to this method must be matched with a call to {@link #finish()} or {@link #finish(ClassMethodActor, boolean)}
* once the code for initializing the non-stack-based template parameters has been emitted.
*
* @param tag denotes the template to emit
*/
protected void start(T1XTemplate startTemplate) {
assert template == null;
this.template = startTemplate;
initializedArgs = 0;
Sig sig = template.sig;
if (sig.stackArgs != 0) {
for (int i = 0; i < sig.in.length; i++) {
Arg a = sig.in[i];
if (a.isStack()) {
initializedArgs |= 1 << i;
switch (a.kind.asEnum) {
case INT:
peekInt(a.reg, a.slot);
break;
case FLOAT:
peekFloat(a.reg, a.slot);
break;
case LONG:
peekLong(a.reg, a.slot);
break;
case DOUBLE:
peekDouble(a.reg, a.slot);
break;
case WORD:
peekWord(a.reg, a.slot);
break;
case REFERENCE:
peekObject(a.reg, a.slot);
break;
default:
assert false;
}
}
}
}
}
/**
* Completes the process of emitting the current template.
*/
protected void finish() {
assert template != null;
assert assertArgsAreInitialized();
emitAndRecordSafepoints(template);
// Adjust the stack to model the net effect of the template including
// the slot for the value pushed (if any) by the template.
Sig sig = template.sig;
if (sig.stackDelta < 0) {
decStack(-sig.stackDelta);
} else if (sig.stackDelta > 0) {
incStack(sig.stackDelta);
}
// The stack parameters to an invoke are popped by the callee so they should not also be
// popped as part of the stack adjustment above.
assert sig.stackArgs == 0 || template.tag == null || !Bytecodes.isInvoke(template.tag.opcode) : template + ": invoke templates should not use @" + Slot.class.getSimpleName() + " annotation";
// Push the result of the template (if any)
if (sig.out.isStack()) {
Arg out = sig.out;
switch (out.kind.asEnum) {
case INT:
pokeInt(out.reg, out.slot);
break;
case FLOAT:
pokeFloat(out.reg, out.slot);
break;
case LONG:
pokeLong(out.reg, out.slot);
break;
case DOUBLE:
pokeDouble(out.reg, out.slot);
break;
case WORD:
pokeWord(out.reg, out.slot);
break;
case REFERENCE:
pokeObject(out.reg, out.slot);
break;
default:
assert false : out.kind;
}
}
template = null;
initializedArgs = 0;
}
/**
* Asserts that a given argument of the current template has not yet been initialized
* and then records the fact that it is now initialized.
*/
private boolean assertInitializeArg(Arg a, int n) {
int argBit = 1 << n;
if ((initializedArgs & argBit) != 0) {
throw new AssertionError(template + ": parameter " + n + " (\"" + a.name + "\") is already initialized");
}
initializedArgs |= argBit;
return true;
}
/**
* Asserts that all the arguments of the current template have been initialized.
*/
private boolean assertArgsAreInitialized() {
int allArgs = (1 << template.sig.in.length) - 1;
int initArgs = initializedArgs;
if (initArgs != allArgs) {
StringBuilder sb = new StringBuilder(template + ": uninitialized arguments: ");
String sep = "";
for (int i = 0; i < 32 && allArgs != 0; i++) {
if ((initArgs & 1) == 0) {
sb.append(sep).append(template.sig.in[i].name);
sep = ", ";
}
allArgs >>= 1;
initArgs >>= 1;
}
throw new InternalError(sb.toString());
}
return true;
}
/**
* Factored out to support JVMTI exception catch events by override.
*/
protected void emitLoadException(int bci) {
emit(LOAD_EXCEPTION);
}
/**
* Emits a template including the setup of stack-based parameters and pushing of the result (if any).
*/
protected void emit(T1XTemplateTag tag) {
start(tag);
finish();
}
@Override
public String toString() {
String s = getClass().getSimpleName() + "[" + Thread.currentThread().getName() + "]";
ClassMethodActor method = this.method;
if (method != null) {
s += ": " + method;
}
return s;
}
/**
* Copies the code from a given template into the code buffer and updates the set of safepoints for the method being
* translated with those derived from the template.
*
* @param template the compiled code to emit
*/
protected void emitAndRecordSafepoints(T1XTemplate template) {
if (template.safepoints.length != 0) {
int bci = stream.currentBCI();
safepointsBuilder.add(template, buf.position(), bci == stream.endBCI() ? -1 : bci);
}
if (template.objectLiterals != null) {
for (ObjectLiteral literal : template.objectLiterals) {
int index = objectLiterals.size();
objectLiterals.add(literal.value);
for (int pos : literal.patchPosns) {
int patchPos = pos + buf.position();
addObjectLiteralPatch(index, patchPos);
}
}
}
buf.emitBytes(template.code, 0, template.code.length);
}
/**
* Records a patch site for a load of an object literal.
*
* @param index the index in {@link #objectLiterals} of the object
* @param patchPos the position in the generated code that must be {@linkplain T1XCompilation#fixup() patched}
*/
protected abstract void addObjectLiteralPatch(int index, int patchPos);
protected abstract Adapter emitPrologue();
protected abstract void emitEpilogue();
protected int localSlotOffset(int localIndex, Kind kind) {
return frame.localVariableOffset(localIndex) + JVMSFrameLayout.offsetInStackSlot(kind);
}
/**
* JVMTI access to local variables.
*/
public static int localSlotOffset(JVMSFrameLayout frame, int localIndex, Kind kind) {
return frame.localVariableOffset(localIndex) + JVMSFrameLayout.offsetInStackSlot(kind);
}
protected abstract void loadInt(CiRegister dst, int index);
protected abstract void loadLong(CiRegister dst, int index);
protected abstract void loadWord(CiRegister dst, int index);
protected abstract void loadObject(CiRegister dst, int index);
protected abstract void storeInt(CiRegister src, int index);
protected abstract void storeLong(CiRegister src, int index);
protected abstract void storeWord(CiRegister src, int index);
protected abstract void storeObject(CiRegister src, int index);
/**
* Emits code for a branch.
*
* @param opcode
* @param targetBCI
* @param bci
*/
protected abstract void branch(int opcode, int targetBCI, int bci);
/**
* Gets the kind used to select an INVOKE... bytecode template.
*/
protected abstract Kind invokeKind(SignatureDescriptor signature);
/**
* Gets the index of the {@link Slot slot} containing the receiver for
* a non-static call.
*
* @param signature the signature of the call
*/
protected static int receiverStackIndex(SignatureDescriptor signature) {
int index = 0;
for (int i = 0; i < signature.numberOfParameters(); i++) {
Kind kind = signature.parameterDescriptorAt(i).toKind();
index += kind.stackSlots;
}
return index;
}
/**
* Fixes up the code locations that need to be patched.
*/
protected abstract void fixup();
/**
* Emits code to assign the value in {@code src} to {@code dst}.
*/
protected abstract void assignObjectReg(CiRegister dst, CiRegister src);
/**
* Emits code to assign the value in {@code src} to {@code dst}.
*/
protected abstract void assignWordReg(CiRegister dst, CiRegister src);
/**
* Emits code to assign {@code value} to {@code dst}.
*/
protected abstract void assignInt(CiRegister dst, int value);
/**
* Emits code to assign {@code value} to {@code dst}.
*/
protected abstract void assignLong(CiRegister dst, long value);
/**
* Emits code to assign {@code value} to {@code dst}.
*/
protected abstract void assignObject(CiRegister dst, Object value);
/**
* Emits code to assign {@code value} to {@code dst}.
*/
protected abstract void assignFloat(CiRegister dst, float value);
/**
* Emits code to assign {@code value} to {@code dst}.
*/
protected abstract void assignDouble(CiRegister dst, double value);
/**
* Emits code to decrement the operand stack pointer by {@code n} slots.
*/
protected abstract void decStack(int n);
/**
* Emits code to increment the operand stack pointer by {@code n} slots.
*/
protected abstract void incStack(int n);
/**
* Emits code to adjust the value in {@code reg} by {@code delta}.
*/
protected abstract void adjustReg(CiRegister reg, int delta);
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} to register {@code dst}.
*/
protected abstract void peekObject(CiRegister dst, int i);
/**
* Emits code to copy the value in register {@code src} to the {@code i}'th {@linkplain Slot slot}.
*/
protected abstract void pokeObject(CiRegister src, int i);
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} to register {@code dst}.
*/
protected abstract void peekWord(CiRegister dst, int i);
/**
* Emits code to copy the value in register {@code src} to the {@code i}'th {@linkplain Slot slot}.
*/
protected abstract void pokeWord(CiRegister src, int i);
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} to register {@code dst}.
*/
protected abstract void peekInt(CiRegister dst, int i);
/**
* Emits code to copy the value in register {@code src} to the {@code i}'th {@linkplain Slot slot}.
*/
protected abstract void pokeInt(CiRegister src, int i);
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} to register {@code dst}.
*/
protected abstract void peekLong(CiRegister dst, int i);
/**
* Emits code to copy the value in register {@code src} to the {@code i}'th {@linkplain Slot slot}.
*/
protected abstract void pokeLong(CiRegister src, int i);
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} to register {@code dst}.
*/
protected abstract void peekDouble(CiRegister dst, int i);
/**
* Emits code to copy the value in register {@code src} to the {@code i}'th {@linkplain Slot slot}.
*/
protected abstract void pokeDouble(CiRegister src, int i);
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} to register {@code dst}.
*/
protected abstract void peekFloat(CiRegister dst, int i);
/**
* Emits code to copy the value in register {@code src} to the {@code i}'th {@linkplain Slot slot}.
*/
protected abstract void pokeFloat(CiRegister src, int i);
/**
* Emits code to trap if the value in register {@code src} is 0.
*/
protected abstract void nullCheck(CiRegister src);
/**
* Emits a direct call instruction whose immediate operand (denoting the absolute or relative offset to the target) will be patched later.
*
* @return the {@linkplain Safepoints safepoint} for the call
*/
protected abstract int callDirect();
/**
* Emits an indirect call instruction.
*
* @param target the register holding the address of the call target
* @param receiverStackIndex the index of the receiver which must be copied from the stack to the receiver register
* used by the optimizing compiler. This is required so that dynamic trampolines can find the receiver in
* the expected register. If {@code receiverStackIndex == -1}, then the copy is not emitted as
* {@code target} is guaranteed to not be the address of a trampoline.
* @return the {@linkplain Safepoints safepoint} for the call
*/
protected abstract int callIndirect(CiRegister target, int receiverStackIndex);
/**
* Gets the register for a given parameter of the current template.
* When assertions are enabled, this method also checks the index, name and kind
* of the parameter and ensures it is not being initialized more than once.
*
* @param n the index of the parameter
* @param name the expected name of the parameter
* @param kind the expected kind of the parameter
* @return the register for parameter {@code n} of the current template.
*/
@INLINE
protected final CiRegister reg(int n, String name, Kind kind) {
assert n >= 0 && n < template.sig.in.length : template + ": parameter " + n + " is out of bounds";
Arg a = template.sig.in[n];
assert assertInitializeArg(a, n);
assert a.kind == kind : template + ": expected " + a.kind + " value for parameter " + n + " (\"" + a.name + "\"), not " + kind;
assert a.name.equals(name) : template + ": expected name of parameter " + n + " to be \"" + a.name + "\", not \"" + name + "\"";
return a.reg;
}
/**
* Emits code to copy the value in {@code src} to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final void assignObjectReg(int n, String name, CiRegister src) {
assignObjectReg(reg(n, name, Kind.REFERENCE), src);
}
/**
* Emits code to copy the value in {@code src} to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final void assignWordReg(int n, String name, CiRegister src) {
assignWordReg(reg(n, name, Kind.WORD), src);
}
/**
* Emits code to assign {@code value} to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final protected void assignObject(int n, String name, Object value) {
assignObject(reg(n, name, Kind.REFERENCE), value);
}
/**
* Emits code to assign {@code value} to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final protected void assignInt(int n, String name, int value) {
assignInt(reg(n, name, Kind.INT), value);
}
/**
* Emits code to assign {@code value} to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final protected void assignFloat(int n, String name, float value) {
assignFloat(reg(n, name, Kind.FLOAT), value);
}
/**
* Emits code to assign {@code value} to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final protected void assignLong(int n, String name, long value) {
assignLong(reg(n, name, Kind.LONG), value);
}
/**
* Emits code to assign {@code value} to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final protected void assignDouble(int n, String name, double value) {
assignDouble(reg(n, name, Kind.DOUBLE), value);
}
/**
* Emits code to copy the value from index {@code i} of the local variables array
* to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final protected void loadInt(int n, String name, int i) {
loadInt(reg(n, name, Kind.INT), i);
}
/**
* Emits code to copy the value from index {@code i} of the local variables array
* to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final protected void loadObject(int n, String name, int i) {
loadObject(reg(n, name, Kind.REFERENCE), i);
}
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} of the operand stack
* to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
protected final void peekObject(int n, String name, int i) {
peekObject(reg(n, name, Kind.REFERENCE), i);
}
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} of the operand stack
* to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final void peekInt(int n, String name, int i) {
peekInt(reg(n, name, Kind.INT), i);
}
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} of the operand stack
* to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final void peekFloat(int n, String name, int i) {
peekFloat(reg(n, name, Kind.FLOAT), i);
}
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} of the operand stack
* to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final void peekDouble(int n, String name, int i) {
peekDouble(reg(n, name, Kind.DOUBLE), i);
}
/**
* Emits code to copy the value in the {@code i}'th {@linkplain Slot slot} of the operand stack
* to parameter {@code n} of the current template.
*
* @param name the expected name of the parameter
*/
final void peekLong(int n, String name, int i) {
peekLong(reg(n, name, Kind.LONG), i);
}
private String errorSuffix() {
int opcode = stream.currentBC();
String name = Bytecodes.nameOf(opcode);
return " [bci=" + stream.currentBCI() + ", opcode=" + opcode + "(" + name + ")]";
}
protected void processBytecode(int opcode) throws InternalError {
beginBytecode(opcode);
switch (opcode) {
// Checkstyle: stop
case Bytecodes.NOP : bciToPos[stream.currentBCI()] = buf.position(); break;
case Bytecodes.AALOAD : do_aaload(); break;
case Bytecodes.AASTORE : do_aastore(); break;
case Bytecodes.ACONST_NULL : do_oconst(null); break;
case Bytecodes.ARRAYLENGTH : do_arraylength(); break;
case Bytecodes.ATHROW : do_athrow(); break;
case Bytecodes.BALOAD : do_baload(); break;
case Bytecodes.BASTORE : do_bastore(); break;
case Bytecodes.CALOAD : do_caload(); break;
case Bytecodes.CASTORE : do_castore(); break;
case Bytecodes.D2F : do_d2f(); break;
case Bytecodes.D2I : do_d2i(); break;
case Bytecodes.D2L : do_d2l(); break;
case Bytecodes.DADD : do_dadd(); break;
case Bytecodes.DALOAD : do_daload(); break;
case Bytecodes.DASTORE : do_dastore(); break;
case Bytecodes.DCMPG : do_dcmpg(); break;
case Bytecodes.DCMPL : do_dcmpl(); break;
case Bytecodes.DDIV : do_ddiv(); break;
case Bytecodes.DMUL : do_dmul(); break;
case Bytecodes.DREM : do_drem(); break;
case Bytecodes.DSUB : do_dsub(); break;
case Bytecodes.DUP : do_dup(); break;
case Bytecodes.DUP2 : do_dup2(); break;
case Bytecodes.DUP2_X1 : do_dup2_x1(); break;
case Bytecodes.DUP2_X2 : do_dup2_x2(); break;
case Bytecodes.DUP_X1 : do_dup_x1(); break;
case Bytecodes.DUP_X2 : do_dup_x2(); break;
case Bytecodes.F2D : do_f2d(); break;
case Bytecodes.F2I : do_f2i(); break;
case Bytecodes.F2L : do_f2l(); break;
case Bytecodes.FADD : do_fadd(); break;
case Bytecodes.FALOAD : do_faload(); break;
case Bytecodes.FASTORE : do_fastore(); break;
case Bytecodes.FCMPG : do_fcmpg(); break;
case Bytecodes.FCMPL : do_fcmpl(); break;
case Bytecodes.FDIV : do_fdiv(); break;
case Bytecodes.FMUL : do_fmul(); break;
case Bytecodes.FREM : do_frem(); break;
case Bytecodes.FSUB : do_fsub(); break;
case Bytecodes.I2B : do_i2b(); break;
case Bytecodes.I2C : do_i2c(); break;
case Bytecodes.I2D : do_i2d(); break;
case Bytecodes.I2F : do_i2f(); break;
case Bytecodes.I2L : do_i2l(); break;
case Bytecodes.I2S : do_i2s(); break;
case Bytecodes.IADD : do_iadd(); break;
case Bytecodes.IALOAD : do_iaload(); break;
case Bytecodes.IAND : do_iand(); break;
case Bytecodes.IASTORE : do_iastore(); break;
case Bytecodes.ICONST_0 : do_iconst(0); break;
case Bytecodes.ICONST_1 : do_iconst(1); break;
case Bytecodes.ICONST_2 : do_iconst(2); break;
case Bytecodes.ICONST_3 : do_iconst(3); break;
case Bytecodes.ICONST_4 : do_iconst(4); break;
case Bytecodes.ICONST_5 : do_iconst(5); break;
case Bytecodes.ICONST_M1 : do_iconst(-1); break;
case Bytecodes.IDIV : do_idiv(); break;
case Bytecodes.IMUL : do_imul(); break;
case Bytecodes.INEG : do_ineg(); break;
case Bytecodes.IOR : do_ior(); break;
case Bytecodes.IREM : do_irem(); break;
case Bytecodes.ISHL : do_ishl(); break;
case Bytecodes.ISHR : do_ishr(); break;
case Bytecodes.ISUB : do_isub(); break;
case Bytecodes.IUSHR : do_iushr(); break;
case Bytecodes.IXOR : do_ixor(); break;
case Bytecodes.L2D : do_l2d(); break;
case Bytecodes.L2F : do_l2f(); break;
case Bytecodes.L2I : do_l2i(); break;
case Bytecodes.LADD : do_ladd(); break;
case Bytecodes.LALOAD : do_laload(); break;
case Bytecodes.LAND : do_land(); break;
case Bytecodes.LASTORE : do_lastore(); break;
case Bytecodes.LCMP : do_lcmp(); break;
case Bytecodes.LDIV : do_ldiv(); break;
case Bytecodes.LMUL : do_lmul(); break;
case Bytecodes.LNEG : do_lneg(); break;
case Bytecodes.LOR : do_lor(); break;
case Bytecodes.LREM : do_lrem(); break;
case Bytecodes.LSHL : do_lshl(); break;
case Bytecodes.LSHR : do_lshr(); break;
case Bytecodes.LSUB : do_lsub(); break;
case Bytecodes.LUSHR : do_lushr(); break;
case Bytecodes.LXOR : do_lxor(); break;
case Bytecodes.MONITORENTER : do_monitorenter(); break;
case Bytecodes.MONITOREXIT : do_monitorexit(); break;
case Bytecodes.POP : do_pop(); break;
case Bytecodes.POP2 : do_pop2(); break;
case Bytecodes.SALOAD : do_saload(); break;
case Bytecodes.SASTORE : do_sastore(); break;
case Bytecodes.SWAP : do_swap(); break;
case Bytecodes.LCONST_0 : do_lconst(0L); break;
case Bytecodes.LCONST_1 : do_lconst(1L); break;
case Bytecodes.DCONST_0 : do_dconst(0D); break;
case Bytecodes.DCONST_1 : do_dconst(1D); break;
case Bytecodes.DNEG : do_dneg(); break;
case Bytecodes.FCONST_0 : do_fconst(0F); break;
case Bytecodes.FCONST_1 : do_fconst(1F); break;
case Bytecodes.FCONST_2 : do_fconst(2F); break;
case Bytecodes.FNEG : do_fneg(); break;
case Bytecodes.ARETURN : do_return(ARETURN, ARETURN$unlock); break;
case Bytecodes.DRETURN : do_return(DRETURN, DRETURN$unlock); break;
case Bytecodes.FRETURN : do_return(FRETURN, FRETURN$unlock); break;
case Bytecodes.IRETURN : do_return(IRETURN, IRETURN$unlock); break;
case Bytecodes.LRETURN : do_return(LRETURN, LRETURN$unlock); break;
case Bytecodes.RETURN : do_return(RETURN, RETURN$unlock); break;
case Bytecodes.ALOAD : do_load(stream.readLocalIndex(), Kind.REFERENCE); break;
case Bytecodes.ALOAD_0 : do_load(0, Kind.REFERENCE); break;
case Bytecodes.ALOAD_1 : do_load(1, Kind.REFERENCE); break;
case Bytecodes.ALOAD_2 : do_load(2, Kind.REFERENCE); break;
case Bytecodes.ALOAD_3 : do_load(3, Kind.REFERENCE); break;
case Bytecodes.ASTORE : do_store(stream.readLocalIndex(), Kind.REFERENCE); break;
case Bytecodes.ASTORE_0 : do_store(0, Kind.REFERENCE); break;
case Bytecodes.ASTORE_1 : do_store(1, Kind.REFERENCE); break;
case Bytecodes.ASTORE_2 : do_store(2, Kind.REFERENCE); break;
case Bytecodes.ASTORE_3 : do_store(3, Kind.REFERENCE); break;
case Bytecodes.DLOAD : do_load(stream.readLocalIndex(), Kind.DOUBLE); break;
case Bytecodes.DLOAD_0 : do_load(0, Kind.DOUBLE); break;
case Bytecodes.DLOAD_1 : do_load(1, Kind.DOUBLE); break;
case Bytecodes.DLOAD_2 : do_load(2, Kind.DOUBLE); break;
case Bytecodes.DLOAD_3 : do_load(3, Kind.DOUBLE); break;
case Bytecodes.DSTORE : do_store(stream.readLocalIndex(), Kind.DOUBLE); break;
case Bytecodes.DSTORE_0 : do_store(0, Kind.DOUBLE); break;
case Bytecodes.DSTORE_1 : do_store(1, Kind.DOUBLE); break;
case Bytecodes.DSTORE_2 : do_store(2, Kind.DOUBLE); break;
case Bytecodes.DSTORE_3 : do_store(3, Kind.DOUBLE); break;
case Bytecodes.FLOAD : do_load(stream.readLocalIndex(), Kind.FLOAT); break;
case Bytecodes.FLOAD_0 : do_load(0, Kind.FLOAT); break;
case Bytecodes.FLOAD_1 : do_load(1, Kind.FLOAT); break;
case Bytecodes.FLOAD_2 : do_load(2, Kind.FLOAT); break;
case Bytecodes.FLOAD_3 : do_load(3, Kind.FLOAT); break;
case Bytecodes.FSTORE : do_store(stream.readLocalIndex(), Kind.FLOAT); break;
case Bytecodes.FSTORE_0 : do_store(0, Kind.FLOAT); break;
case Bytecodes.FSTORE_1 : do_store(1, Kind.FLOAT); break;
case Bytecodes.FSTORE_2 : do_store(2, Kind.FLOAT); break;
case Bytecodes.FSTORE_3 : do_store(3, Kind.FLOAT); break;
case Bytecodes.ILOAD : do_load(stream.readLocalIndex(), Kind.INT); break;
case Bytecodes.ILOAD_0 : do_load(0, Kind.INT); break;
case Bytecodes.ILOAD_1 : do_load(1, Kind.INT); break;
case Bytecodes.ILOAD_2 : do_load(2, Kind.INT); break;
case Bytecodes.ILOAD_3 : do_load(3, Kind.INT); break;
case Bytecodes.ISTORE : do_store(stream.readLocalIndex(), Kind.INT); break;
case Bytecodes.ISTORE_0 : do_store(0, Kind.INT); break;
case Bytecodes.ISTORE_1 : do_store(1, Kind.INT); break;
case Bytecodes.ISTORE_2 : do_store(2, Kind.INT); break;
case Bytecodes.ISTORE_3 : do_store(3, Kind.INT); break;
case Bytecodes.LLOAD : do_load(stream.readLocalIndex(), Kind.LONG); break;
case Bytecodes.LLOAD_0 : do_load(0, Kind.LONG); break;
case Bytecodes.LLOAD_1 : do_load(1, Kind.LONG); break;
case Bytecodes.LLOAD_2 : do_load(2, Kind.LONG); break;
case Bytecodes.LLOAD_3 : do_load(3, Kind.LONG); break;
case Bytecodes.LSTORE : do_store(stream.readLocalIndex(), Kind.LONG); break;
case Bytecodes.LSTORE_0 : do_store(0, Kind.LONG); break;
case Bytecodes.LSTORE_1 : do_store(1, Kind.LONG); break;
case Bytecodes.LSTORE_2 : do_store(2, Kind.LONG); break;
case Bytecodes.LSTORE_3 : do_store(3, Kind.LONG); break;
case Bytecodes.IFEQ : do_branch(Bytecodes.IFEQ, stream.readBranchDest()); break;
case Bytecodes.IFNE : do_branch(Bytecodes.IFNE, stream.readBranchDest()); break;
case Bytecodes.IFLE : do_branch(Bytecodes.IFLE, stream.readBranchDest()); break;
case Bytecodes.IFLT : do_branch(Bytecodes.IFLT, stream.readBranchDest()); break;
case Bytecodes.IFGE : do_branch(Bytecodes.IFGE, stream.readBranchDest()); break;
case Bytecodes.IFGT : do_branch(Bytecodes.IFGT, stream.readBranchDest()); break;
case Bytecodes.IF_ICMPEQ : do_branch(Bytecodes.IF_ICMPEQ, stream.readBranchDest()); break;
case Bytecodes.IF_ICMPNE : do_branch(Bytecodes.IF_ICMPNE, stream.readBranchDest()); break;
case Bytecodes.IF_ICMPGE : do_branch(Bytecodes.IF_ICMPGE, stream.readBranchDest()); break;
case Bytecodes.IF_ICMPGT : do_branch(Bytecodes.IF_ICMPGT, stream.readBranchDest()); break;
case Bytecodes.IF_ICMPLE : do_branch(Bytecodes.IF_ICMPLE, stream.readBranchDest()); break;
case Bytecodes.IF_ICMPLT : do_branch(Bytecodes.IF_ICMPLT, stream.readBranchDest()); break;
case Bytecodes.IF_ACMPEQ : do_branch(Bytecodes.IF_ACMPEQ, stream.readBranchDest()); break;
case Bytecodes.IF_ACMPNE : do_branch(Bytecodes.IF_ACMPNE, stream.readBranchDest()); break;
case Bytecodes.IFNULL : do_branch(Bytecodes.IFNULL, stream.readBranchDest()); break;
case Bytecodes.IFNONNULL : do_branch(Bytecodes.IFNONNULL, stream.readBranchDest()); break;
case Bytecodes.GOTO : do_branch(Bytecodes.GOTO, stream.readBranchDest()); break;
case Bytecodes.GOTO_W : do_branch(Bytecodes.GOTO_W, stream.readFarBranchDest()); break;
case Bytecodes.GETFIELD : do_fieldAccess(GETFIELDS, stream.readCPI()); break;
case Bytecodes.GETSTATIC : do_fieldAccess(GETSTATICS, stream.readCPI()); break;
case Bytecodes.PUTFIELD : do_fieldAccess(PUTFIELDS, stream.readCPI()); break;
case Bytecodes.PUTSTATIC : do_fieldAccess(PUTSTATICS, stream.readCPI()); break;
case Bytecodes.ANEWARRAY : do_anewarray(stream.readCPI()); break;
case Bytecodes.CHECKCAST : do_checkcast(stream.readCPI()); break;
case Bytecodes.INSTANCEOF : do_instanceof(stream.readCPI()); break;
case Bytecodes.BIPUSH : do_iconst(stream.readByte()); break;
case Bytecodes.SIPUSH : do_iconst(stream.readShort()); break;
case Bytecodes.NEW : do_new(stream.readCPI()); break;
case Bytecodes.INVOKESPECIAL : do_invokespecial(stream.readCPI()); break;
case Bytecodes.INVOKESTATIC : do_invokestatic(stream.readCPI()); break;
case Bytecodes.INVOKEVIRTUAL : do_invokevirtual(stream.readCPI()); break;
case Bytecodes.INVOKEINTERFACE : do_invokeinterface(stream.readCPI()); break;
case Bytecodes.NEWARRAY : do_newarray(stream.readLocalIndex()); break;
case Bytecodes.LDC : do_ldc(stream.readCPI()); break;
case Bytecodes.LDC_W : do_ldc(stream.readCPI()); break;
case Bytecodes.LDC2_W : do_ldc(stream.readCPI()); break;
case Bytecodes.TABLESWITCH : do_tableswitch(); break;
case Bytecodes.LOOKUPSWITCH : do_lookupswitch(); break;
case Bytecodes.IINC : do_iinc(stream.readLocalIndex(), stream.readIncrement()); break;
case Bytecodes.MULTIANEWARRAY : do_multianewarray(stream.readCPI(), stream.readUByte(stream.currentBCI() + 3)); break;
case Bytecodes.RET :
case Bytecodes.JSR_W :
case Bytecodes.JSR : throw new UnsupportedSubroutineException(opcode, stream.currentBCI());
case Bytecodes.JNICALL :
default : throw new CiBailout("Unsupported opcode" + errorSuffix());
// Checkstyle: resume
}
}
protected void do_uncommonTrap() {
// Use a safepoint so that this position is not overlapping
// with the subsequent instruction. In all other senses,
// an uncommon trap is essentially a nop in baseline code.
int pos = buf.position();
byte[] safepointCode = vm().safepointPoll.code;
buf.emitBytes(safepointCode, 0, safepointCode.length);
safepointsBuilder.addSafepoint(stream.currentBCI(), Safepoints.make(pos), null);
}
void do_profileMethodEntry() {
if (methodProfileBuilder != null) {
methodProfileBuilder.addEntryCounter(MethodInstrumentation.initialEntryCount);
if (method.isStatic()) {
start(PROFILE_STATIC_METHOD_ENTRY);
assignObject(0, "mpo", methodProfileBuilder.methodProfileObject());
finish();
} else {
start(PROFILE_NONSTATIC_METHOD_ENTRY);
assignObject(0, "mpo", methodProfileBuilder.methodProfileObject());
loadObject(1, "rcvr", 0);
finish();
}
}
}
protected void do_methodTraceEntry() {
if (T1XOptions.TraceMethods) {
start(TRACE_METHOD_ENTRY);
assignObject(0, "method", "{" + method.toString());
finish();
}
}
protected void do_synchronizedMethodAcquire() {
if (method.isSynchronized()) {
start(LOCK);
if (method.isStatic()) {
assignObject(0, "object", method.holder().javaClass());
} else {
loadObject(0, "object", 0);
storeObject(template.sig.in[0].reg, synchronizedReceiver);
}
syncRefMapStartPos = buf.position();
finish();
syncHandlerStartPos = buf.position();
}
}
protected void do_synchronizedMethodHandler(ClassMethodActor method, int endBCI) {
if (method.isSynchronized()) {
syncMethodHandlerPos = buf.position();
start(UNLOCK);
if (method.isStatic()) {
assignObject(0, "object", method.holder().javaClass());
} else {
loadObject(0, "object", synchronizedReceiver);
}
syncHandlerEndPos = buf.position();
finish();
syncRefMapEndPos = buf.position();
emit(RETHROW_EXCEPTION);
}
}
protected void do_oconst(Object value) {
assignObject(scratch, value);
incStack(1);
pokeObject(scratch, 0);
}
protected void do_iconst(int value) {
assignInt(scratch, value);
incStack(1);
pokeInt(scratch, 0);
}
protected void do_dconst(double value) {
assignLong(scratch, Double.doubleToRawLongBits(value));
incStack(2);
pokeLong(scratch, 0);
}
protected void do_fconst(float value) {
assignInt(scratch, Float.floatToRawIntBits(value));
incStack(1);
pokeInt(scratch, 0);
}
protected void do_lconst(long value) {
assignLong(scratch, value);
incStack(2);
pokeLong(scratch, 0);
}
protected void do_load(int index, Kind kind) {
switch(kind.asEnum) {
case INT:
case FLOAT:
loadInt(scratch, index);
incStack(1);
pokeInt(scratch, 0);
break;
case REFERENCE:
loadWord(scratch, index);
incStack(1);
pokeWord(scratch, 0);
break;
case LONG:
case DOUBLE:
loadLong(scratch, index);
incStack(2);
pokeLong(scratch, 0);
break;
default:
throw new InternalError("Unexpected kind: " + kind);
}
}
protected void do_store(int index, Kind kind) {
switch(kind.asEnum) {
case INT:
case FLOAT:
peekInt(scratch, 0);
decStack(1);
storeInt(scratch, index);
break;
case REFERENCE:
peekWord(scratch, 0);
decStack(1);
storeWord(scratch, index);
break;
case LONG:
case DOUBLE:
peekLong(scratch, 0);
decStack(2);
storeLong(scratch, index);
break;
default:
throw new InternalError("Unexpected kind: " + kind);
}
}
/** Similar to {@link #assignInvokeVirtualTemplateParameters}, allows
* VMA override to consistently pass the {@link FieldActor} to the (VMA) template.
* @param fieldActor
*/
protected void assignFieldAccessParameter(T1XTemplateTag tag, FieldActor fieldActor) {
assignInt(1, "offset", fieldActor.offset());
}
/**
* Emit template for a bytecode operating on a (static or dynamic) field.
* @param index Index to the field ref constant.
* @param template one of getfield, putfield, getstatic, putstatic
*/
protected void do_fieldAccess(EnumMap<KindEnum, T1XTemplateTag> tags, int index) {
FieldRefConstant fieldRefConstant = cp.fieldAt(index);
KindEnum fieldKind = fieldRefConstant.type(cp).toKind().asEnum;
T1XTemplateTag tag = tags.get(fieldKind);
if (fieldRefConstant.isResolvableWithoutClassLoading(cp)) {
try {
FieldActor fieldActor = fieldRefConstant.resolve(cp, index);
do_preVolatileFieldAccess(tag, fieldActor);
if (fieldActor.isStatic()) {
if (fieldActor.holder().isInitialized()) {
start(tag.initialized);
assignObject(0, "staticTuple", fieldActor.holder().staticTuple());
assignFieldAccessParameter(tag, fieldActor);
finish();
do_postVolatileFieldAccess(tag, fieldActor);
return;
}
} else {
start(tag.resolved);
assignFieldAccessParameter(tag, fieldActor);
finish();
do_postVolatileFieldAccess(tag, fieldActor);
return;
}
} catch (LinkageError e) {
// This should not happen since the field ref constant is resolvable without class loading (i.e., it
// has already been resolved). If it were to happen, the safe thing to do is to fall off to the
// unresolved case.
}
}
start(tag);
assignObject(0, "guard", cp.makeResolutionGuard(index));
finish();
}
protected void do_preVolatileFieldAccess(T1XTemplateTag tag, FieldActor fieldActor) {
}
protected void do_postVolatileFieldAccess(T1XTemplateTag tag, FieldActor fieldActor) {
}
protected void do_anewarray(int index) {
T1XTemplateTag tag;
ClassConstant classConstant = cp.classAt(index);
Object arrayType;
if (classConstant.isResolvableWithoutClassLoading(cp)) {
tag = ANEWARRAY$resolved;
ClassActor resolvedClassActor = classConstant.resolve(cp, index);
arrayType = ArrayClassActor.forComponentClassActor(resolvedClassActor);
} else {
tag = ANEWARRAY;
arrayType = cp.makeResolutionGuard(index);
}
start(tag);
assignObject(0, "arrayType", arrayType);
finish();
}
protected void do_iinc(int index, int increment) {
loadInt(scratch, index);
adjustReg(scratch, increment);
storeInt(scratch, index);
}
protected void do_return(T1XTemplateTag tag, T1XTemplateTag tagUnlock) {
if (T1XOptions.TraceMethods) {
start(TRACE_METHOD_EXIT);
assignObject(0, "method", method.toString() + "}");
finish();
}
if (method.holder() == ClassRegistry.OBJECT && method.isInitializer()) {
start(RETURN$registerFinalizer);
loadObject(0, "object", 0);
finish();
} else if (method.isSynchronized()) {
start(tagUnlock);
if (method.isStatic()) {
assignObject(0, "object", method.holder().javaClass());
} else {
loadObject(0, "object", synchronizedReceiver);
}
finish();
} else {
emit(tag);
}
emitEpilogue();
}
protected void do_branch(int opcode, int targetBCI) {
int bci = stream.currentBCI();
startBlock(targetBCI);
if (bci >= targetBCI) {
if (methodProfileBuilder != null) {
// Profiling of backward branches.
start(PROFILE_BACKWARD_BRANCH);
assignObject(0, "mpo", methodProfileBuilder.methodProfileObject());
finish();
}
// Ideally, we'd like to emit a safepoint at the target of a backward branch.
// However, that would require at least one extra pass to determine where
// the backward branches are. Instead, we simply emit a safepoint at the source of
// a backward branch. This means the cost of the safepoint is taken even if
// the backward branch is not taken but that cost should not be noticeable.
// Note also that the safepoint must be placed before conditional
// test instruction(s) to avoid affecting the condition flags
// with the safepoint poll instruction(s).
int pos = buf.position();
byte[] safepointCode = vm().safepointPoll.code;
buf.emitBytes(safepointCode, 0, safepointCode.length);
safepointsBuilder.addSafepoint(bci, Safepoints.make(pos), null);
}
branch(opcode, targetBCI, bci);
}
protected void finishCall(T1XTemplateTag tag, Kind returnKind, int safepoint, ClassMethodActor directCallee) {
safepointsBuilder.addSafepoint(stream.currentBCI(), safepoint, directCallee);
if (returnKind != Kind.VOID) {
incStack(returnKind.stackSlots);
CiRegister reg = vm().registerConfigs.standard.getReturnRegister(WordUtil.ciKind(returnKind, true));
switch (returnKind.asEnum) {
case FLOAT:
pokeFloat(reg, 0);
break;
case LONG:
pokeLong(reg, 0);
break;
case DOUBLE:
pokeDouble(reg, 0);
break;
case WORD:
pokeWord(reg, 0);
break;
case REFERENCE:
pokeObject(reg, 0);
break;
default:
throw new InternalError("Unexpected return kind: " + returnKind);
}
}
}
/*
* The following three methods exist to be overridden by the VMA extension.
* They permit flexibility in the form of the templates for the INVOKE bytecodes
* without hard-wiring in additional forms. In particular, they allow access to the
* associated {@link MethodActor} in all situations.
*/
protected void assignInvokeVirtualTemplateParameters(VirtualMethodActor virtualMethodActor, int receiverStackIndex) {
assignInt(0, "vTableIndex", virtualMethodActor.vTableIndex());
peekObject(1, "receiver", receiverStackIndex);
}
protected void do_invokespecial_resolved(T1XTemplateTag tag, VirtualMethodActor virtualMethodActor, int receiverStackIndex) {
peekObject(scratch, receiverStackIndex);
nullCheck(scratch);
}
protected void do_invokestatic_resolved(T1XTemplateTag tag, StaticMethodActor staticMethodActor) {
}
protected void do_invokevirtual(int index) {
ClassMethodRefConstant classMethodRef = cp.classMethodAt(index);
SignatureDescriptor signature = classMethodRef.signature(cp);
if (classMethodRef.holder(cp).toKind().isWord) {
// Dynamic dispatch on Word types is not possible, since raw pointers do not have any method tables.
do_invokespecial(index);
return;
}
Kind kind = invokeKind(signature);
T1XTemplateTag tag = INVOKEVIRTUALS.get(kind.asEnum);
int receiverStackIndex = receiverStackIndex(signature);
try {
if (classMethodRef.isResolvableWithoutClassLoading(cp)) {
try {
VirtualMethodActor virtualMethodActor = classMethodRef.resolveVirtual(cp, index);
if (processIntrinsic(virtualMethodActor)) {
return;
}
if (virtualMethodActor.isPrivate() || virtualMethodActor.isFinal() || virtualMethodActor.holder().isFinal()) {
// this is an invokevirtual to a private or final method, treat it like invokespecial
do_invokespecial_resolved(tag, virtualMethodActor, receiverStackIndex);
int safepoint = callDirect();
finishCall(tag, kind, safepoint, virtualMethodActor);
return;
}
// emit an unprofiled virtual dispatch
start(tag.resolved);
CiRegister target = template.sig.out.reg;
assignInvokeVirtualTemplateParameters(virtualMethodActor, receiverStackIndex);
finish();
int safepoint = callIndirect(target, receiverStackIndex);
finishCall(tag, kind, safepoint, null);
return;
} catch (LinkageError e) {
// fall through
}
}
} catch (LinkageError error) {
// Fall back on unresolved template that will cause the error to be rethrown at runtime.
}
start(tag);
CiRegister target = template.sig.out.reg;
assignObject(0, "guard", cp.makeResolutionGuard(index));
peekObject(1, "receiver", receiverStackIndex);
finish();
int safepoint = callIndirect(target, receiverStackIndex);
finishCall(tag, kind, safepoint, null);
}
protected void do_invokeinterface(int index) {
InterfaceMethodRefConstant interfaceMethodRef = cp.interfaceMethodAt(index);
SignatureDescriptor signature = interfaceMethodRef.signature(cp);
if (interfaceMethodRef.holder(cp).toKind().isWord) {
// Dynamic dispatch on Word types is not possible, since raw pointers do not have any method tables.
do_invokespecial(index);
return;
}
Kind kind = invokeKind(signature);
T1XTemplateTag tag = INVOKEINTERFACES.get(kind.asEnum);
int receiverStackIndex = receiverStackIndex(signature);
try {
if (interfaceMethodRef.isResolvableWithoutClassLoading(cp)) {
try {
MethodActor interfaceMethod = interfaceMethodRef.resolve(cp, index);
if (processIntrinsic(interfaceMethod)) {
return;
}
start(tag.resolved);
CiRegister target = template.sig.out.reg;
assignObject(0, "methodActor", interfaceMethod);
peekObject(1, "receiver", receiverStackIndex);
finish();
int safepoint = callIndirect(target, receiverStackIndex);
finishCall(tag, kind, safepoint, null);
return;
} catch (LinkageError e) {
// fall through
}
}
} catch (LinkageError error) {
// Fall back on unresolved template that will cause the error to be rethrown at runtime.
}
start(tag);
CiRegister target = template.sig.out.reg;
assignObject(0, "guard", cp.makeResolutionGuard(index));
peekObject(1, "receiver", receiverStackIndex);
finish();
int safepoint = callIndirect(target, receiverStackIndex);
finishCall(tag, kind, safepoint, null);
}
protected void do_invokespecial(int index) {
ClassMethodRefConstant classMethodRef = cp.classMethodAt(index);
Kind kind = invokeKind(classMethodRef.signature(cp));
SignatureDescriptor signature = classMethodRef.signature(cp);
T1XTemplateTag tag = INVOKESPECIALS.get(kind.asEnum);
int receiverStackIndex = receiverStackIndex(signature);
try {
if (classMethodRef.isResolvableWithoutClassLoading(cp)) {
VirtualMethodActor virtualMethodActor = classMethodRef.resolveVirtual(cp, index);
if (processIntrinsic(virtualMethodActor)) {
return;
}
do_invokespecial_resolved(tag, virtualMethodActor, receiverStackIndex);
int safepoint = callDirect();
finishCall(tag, kind, safepoint, virtualMethodActor);
return;
}
} catch (LinkageError error) {
// Fall back on unresolved template that will cause the error to be rethrown at runtime.
}
start(tag);
CiRegister target = template.sig.out.reg;
assignObject(0, "guard", cp.makeResolutionGuard(index));
peekObject(1, "receiver", receiverStackIndex);
finish();
int safepoint = callIndirect(target, receiverStackIndex);
finishCall(tag, kind, safepoint, null);
}
protected void do_invokestatic(int index) {
ClassMethodRefConstant classMethodRef = cp.classMethodAt(index);
Kind kind = invokeKind(classMethodRef.signature(cp));
T1XTemplateTag tag = INVOKESTATICS.get(kind.asEnum);
try {
if (classMethodRef.isResolvableWithoutClassLoading(cp)) {
StaticMethodActor staticMethodActor = classMethodRef.resolveStatic(cp, index);
if (processIntrinsic(staticMethodActor)) {
return;
}
if (staticMethodActor.holder().isInitialized()) {
do_invokestatic_resolved(tag, staticMethodActor);
int safepoint = callDirect();
finishCall(tag, kind, safepoint, staticMethodActor);
return;
}
}
} catch (LinkageError error) {
// Fall back on unresolved template that will cause the error to be rethrown at runtime.
}
start(tag);
CiRegister target = template.sig.out.reg;
assignObject(0, "guard", cp.makeResolutionGuard(index));
finish();
int safepoint = callIndirect(target, -1);
finishCall(tag, kind, safepoint, null);
}
protected boolean processIntrinsic(MethodActor method) {
String intrinsic = method.intrinsic();
if (T1X.unsafeIntrinsicIDs.contains(intrinsic)) {
T1XMetrics.Bailouts++;
if (T1XOptions.PrintBailouts) {
Log.println("T1X bailout: unsupported intrinsic method " + method + " called from " + this.method);
}
throw new CiBailout("Unsupported intrinsic " + intrinsic + ": " + errorSuffix());
} else if ((method.flags() & (Actor.FOLD | Actor.INLINE)) != 0) {
if (isDeopt && method.isVM()) {
// There is an implicit assumption here that it is ok to compile the VM method with T1X for deopt
return false;
}
T1XMetrics.Bailouts++;
if (T1XOptions.PrintBailouts) {
Log.println("T1X bailout: unsupported INLINE or FOLD method method " + method + " called from " + this.method);
}
throw new CiBailout("INLINE and FOLD methods are not supported: " + method);
}
if (intrinsic == MaxineIntrinsicIDs.UNSAFE_CAST) {
// Usafe casts do not need any implementation in T1X, so we are done.
return true;
} else if (intrinsic == MaxineIntrinsicIDs.UNCOMMON_TRAP) {
do_uncommonTrap();
return true;
}
T1XTemplate template = compiler.intrinsicTemplates.get(method);
if (template == null) {
return false;
}
start(template);
finish();
return true;
}
protected void do_instanceof(int cpi) {
ClassConstant classConstant = cp.classAt(cpi);
if (classConstant.isResolvableWithoutClassLoading(cp)) {
start(INSTANCEOF$resolved);
ClassActor resolvedClassActor = classConstant.resolve(cp, cpi);
assignObject(0, "classActor", resolvedClassActor);
finish();
} else {
start(INSTANCEOF);
assignObject(0, "guard", cp.makeResolutionGuard(cpi));
finish();
}
}
protected void do_checkcast(int cpi) {
ClassConstant classConstant = cp.classAt(cpi);
if (classConstant.isResolvableWithoutClassLoading(cp)) {
start(CHECKCAST$resolved);
assignObject(0, "classActor", classConstant.resolve(cp, cpi));
finish();
} else {
start(CHECKCAST);
assignObject(0, "guard", cp.makeResolutionGuard(cpi));
finish();
}
}
protected void do_multianewarray(int index, int numberOfDimensions) {
CiRegister lengths;
{
start(CREATE_MULTIANEWARRAY_DIMENSIONS);
assignWordReg(0, "sp", sp);
assignInt(1, "n", numberOfDimensions);
lengths = template.sig.out.reg;
finish();
decStack(numberOfDimensions);
}
ClassConstant classRef = cp.classAt(index);
if (classRef.isResolvableWithoutClassLoading(cp)) {
start(MULTIANEWARRAY$resolved);
ClassActor arrayClassActor = classRef.resolve(cp, index);
assert arrayClassActor.isArrayClass();
assert arrayClassActor.numberOfDimensions() >= numberOfDimensions : "dimensionality of array class constant smaller that dimension operand";
assignObject(0, "arrayClassActor", arrayClassActor);
assignObjectReg(1, "lengths", lengths);
finish();
} else {
// Unresolved case
start(MULTIANEWARRAY);
assignObject(0, "guard", cp.makeResolutionGuard(index));
assignObjectReg(1, "lengths", lengths);
finish();
}
}
protected void do_pop() {
decStack(1);
}
protected void do_pop2() {
decStack(2);
}
protected void do_dup() {
incStack(1);
peekWord(scratch, 1);
pokeWord(scratch, 0);
}
protected void do_dup_x1() {
incStack(1);
// value1
peekWord(scratch, 1);
pokeWord(scratch, 0);
// value2
peekWord(scratch, 2);
pokeWord(scratch, 1);
// value1
peekWord(scratch, 0);
pokeWord(scratch, 2);
}
protected void do_dup_x2() {
incStack(1);
// value1
peekWord(scratch, 1);
pokeWord(scratch, 0);
// value2
peekWord(scratch, 2);
pokeWord(scratch, 1);
// value3
peekWord(scratch, 3);
pokeWord(scratch, 2);
// value1
peekWord(scratch, 0);
pokeWord(scratch, 3);
}
protected void do_dup2() {
incStack(2);
peekWord(scratch, 3);
pokeWord(scratch, 1);
peekWord(scratch, 2);
pokeWord(scratch, 0);
}
protected void do_dup2_x1() {
incStack(2);
// value1
peekWord(scratch, 2);
pokeWord(scratch, 0);
// value2
peekWord(scratch, 3);
pokeWord(scratch, 1);
// value3
peekWord(scratch, 4);
pokeWord(scratch, 2);
// value1
peekWord(scratch, 0);
pokeWord(scratch, 3);
// value2
peekWord(scratch, 1);
pokeWord(scratch, 4);
}
protected void do_dup2_x2() {
incStack(2);
// value1
peekWord(scratch, 2);
pokeWord(scratch, 0);
// value2
peekWord(scratch, 3);
pokeWord(scratch, 1);
// value3
peekWord(scratch, 4);
pokeWord(scratch, 2);
// value4
peekWord(scratch, 5);
pokeWord(scratch, 3);
// value1
peekWord(scratch, 0);
pokeWord(scratch, 4);
// value2
peekWord(scratch, 1);
pokeWord(scratch, 5);
}
protected void do_swap() {
peekWord(scratch, 0);
peekWord(scratch2, 1);
pokeWord(scratch, 1);
pokeWord(scratch2, 0);
}
protected void do_ineg() {
start(INEG);
assignInt(1, "zero", 0);
finish();
}
protected void do_lneg() {
start(LNEG);
assignLong(1, "zero", 0L);
finish();
}
protected void do_dneg() {
start(DNEG);
assignDouble(1, "zero", 0d);
finish();
}
protected void do_fneg() {
start(FNEG);
assignFloat(1, "zero", 0f);
finish();
}
protected void do_ldc(int index) {
PoolConstant constant = cp.at(index);
switch (constant.tag()) {
case CLASS: {
ClassConstant classConstant = (ClassConstant) constant;
if (classConstant.isResolvableWithoutClassLoading(cp)) {
Object mirror = ((ClassActor) classConstant.value(cp, index).asObject()).javaClass();
incStack(1);
assignObject(scratch, mirror);
pokeObject(scratch, 0);
} else {
start(LDC$reference);
assignObject(0, "guard", cp.makeResolutionGuard(index));
finish();
}
break;
}
case INTEGER: {
IntegerConstant integerConstant = (IntegerConstant) constant;
do_iconst(integerConstant.value());
break;
}
case LONG: {
LongConstant longConstant = (LongConstant) constant;
do_lconst(longConstant.value());
break;
}
case FLOAT: {
FloatConstant floatConstant = (FloatConstant) constant;
do_fconst(floatConstant.value());
break;
}
case DOUBLE: {
DoubleConstant doubleConstant = (DoubleConstant) constant;
do_dconst(doubleConstant.value());
break;
}
case STRING: {
StringConstant stringConstant = (StringConstant) constant;
do_oconst(stringConstant.value);
break;
}
default: {
assert false : "ldc for unexpected constant tag: " + constant.tag();
break;
}
}
}
protected void do_new(int index) {
ClassConstant classRef = cp.classAt(index);
if (classRef.isResolvableWithoutClassLoading(cp)) {
ClassActor classActor = classRef.resolve(cp, index);
if (classActor.isHybridClass()) {
start(NEW_HYBRID);
assignObject(0, "hub", classActor.dynamicHub());
finish();
return;
}
if (classActor.isInitialized()) {
start(NEW$init);
assignObject(0, "hub", classActor.dynamicHub());
finish();
return;
}
}
start(NEW);
assignObject(0, "guard", cp.makeResolutionGuard(index));
finish();
}
protected void do_newarray(int tag) {
start(NEWARRAY);
Kind arrayElementKind = Kind.fromNewArrayTag(tag);
assignObject(0, "arrayClass", arrayElementKind.arrayClassActor());
finish();
}
protected abstract void do_tableswitch();
protected abstract void do_lookupswitch();
protected void do_ddiv() {
emit(DDIV);
}
protected void do_dcmpl() {
emit(DCMPL);
}
protected void do_dcmpg() {
emit(DCMPG);
}
protected void do_dastore() {
emit(DASTORE);
}
protected void do_daload() {
emit(DALOAD);
}
protected void do_dadd() {
emit(DADD);
}
protected void do_d2l() {
emit(D2L);
}
protected void do_d2i() {
emit(D2I);
}
protected void do_d2f() {
emit(D2F);
}
protected void do_castore() {
emit(CASTORE);
}
protected void do_caload() {
emit(CALOAD);
}
protected void do_bastore() {
emit(BASTORE);
}
protected void do_baload() {
emit(BALOAD);
}
protected void do_athrow() {
emit(ATHROW);
}
protected void do_arraylength() {
emit(ARRAYLENGTH);
}
protected void do_aastore() {
emit(AASTORE);
}
protected void do_aaload() {
emit(AALOAD);
}
protected void do_dmul() {
emit(DMUL);
}
protected void do_drem() {
emit(DREM);
}
protected void do_dsub() {
emit(DSUB);
}
protected void do_f2d() {
emit(F2D);
}
protected void do_f2i() {
emit(F2I);
}
protected void do_f2l() {
emit(F2L);
}
protected void do_fadd() {
emit(FADD);
}
protected void do_faload() {
emit(FALOAD);
}
protected void do_fastore() {
emit(FASTORE);
}
protected void do_fcmpg() {
emit(FCMPG);
}
protected void do_fcmpl() {
emit(FCMPL);
}
protected void do_fdiv() {
emit(FDIV);
}
protected void do_fmul() {
emit(FMUL);
}
protected void do_frem() {
emit(FREM);
}
protected void do_fsub() {
emit(FSUB);
}
protected void do_i2b() {
emit(I2B);
}
protected void do_i2c() {
emit(I2C);
}
protected void do_i2d() {
emit(I2D);
}
protected void do_i2f() {
emit(I2F);
}
protected void do_i2l() {
emit(I2L);
}
protected void do_i2s() {
emit(I2S);
}
protected void do_iadd() {
emit(IADD);
}
protected void do_iaload() {
emit(IALOAD);
}
protected void do_iand() {
emit(IAND);
}
protected void do_iastore() {
emit(IASTORE);
}
protected void do_idiv() {
emit(IDIV);
}
protected void do_imul() {
emit(IMUL);
}
protected void do_ior() {
emit(IOR);
}
protected void do_irem() {
emit(IREM);
}
protected void do_ishl() {
emit(ISHL);
}
protected void do_ishr() {
emit(ISHR);
}
protected void do_isub() {
emit(ISUB);
}
protected void do_iushr() {
emit(IUSHR);
}
protected void do_ixor() {
emit(IXOR);
}
protected void do_l2d() {
emit(L2D);
}
protected void do_l2f() {
emit(L2F);
}
protected void do_l2i() {
emit(L2I);
}
protected void do_ladd() {
emit(LADD);
}
protected void do_laload() {
emit(LALOAD);
}
protected void do_land() {
emit(LAND);
}
protected void do_lastore() {
emit(LASTORE);
}
protected void do_lcmp() {
emit(LCMP);
}
protected void do_ldiv() {
emit(LDIV);
}
protected void do_lmul() {
emit(LMUL);
}
protected void do_lor() {
emit(LOR);
}
protected void do_lrem() {
emit(LREM);
}
protected void do_lshl() {
emit(LSHL);
}
protected void do_lshr() {
emit(LSHR);
}
protected void do_lsub() {
emit(LSUB);
}
protected void do_lushr() {
emit(LUSHR);
}
protected void do_lxor() {
emit(LXOR);
}
protected void do_monitorenter() {
emit(MONITORENTER);
}
protected void do_monitorexit() {
emit(MONITOREXIT);
}
protected void do_saload() {
emit(SALOAD);
}
protected void do_sastore() {
emit(SASTORE);
}
}