/*
* Copyright (c) 2009, 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.sun.cri.xir;
import static com.sun.cri.xir.CiXirAssembler.XirOp.*;
import java.util.*;
import com.sun.cri.ci.CiAddress.Scale;
import com.sun.cri.ci.*;
import com.sun.cri.ri.*;
/**
* Represents an assembler that allows a client such as the runtime system to
* create {@link XirTemplate XIR templates}.
*/
public abstract class CiXirAssembler {
protected XirOperand resultOperand;
protected boolean allocateResultOperand;
protected final List<XirInstruction> instructions = new ArrayList<XirInstruction>();
protected final List<XirLabel> labels = new ArrayList<XirLabel>(5);
protected final List<XirParameter> parameters = new ArrayList<XirParameter>(5);
protected final List<XirTemp> temps = new ArrayList<XirTemp>(5);
protected final List<XirConstant> constants = new ArrayList<XirConstant>(5);
protected final List<XirMark> marks = new ArrayList<XirMark>(5);
protected int outgoingStackSize = 0;
/**
* Increases by one for every {@link XirOperand operand} created.
*/
protected int variableCount;
/**
* Marks the assembly complete.
*/
protected boolean finished = true;
protected final CiTarget target;
public CiXirAssembler(CiTarget target) {
this.target = target;
}
public CiKind wordKind() {
return target.wordKind;
}
public static class RuntimeCallInformation {
public final Object target;
public final boolean useInfoAfter;
public RuntimeCallInformation(Object target, boolean useInfoAfter) {
this.target = target;
this.useInfoAfter = useInfoAfter;
}
}
/**
* Represents additional address calculation information.
*/
public static class AddressAccessInformation {
/**
* The scaling factor for the scaled-index part of an address computation.
*/
public final Scale scale;
/**
* The constant byte-sized displacement part of an address computation.
*/
public final int disp;
/**
* Determines if the memory access through the address can trap.
*/
public final boolean canTrap;
private AddressAccessInformation(boolean canTrap) {
this.canTrap = canTrap;
this.scale = Scale.Times1;
this.disp = 0;
}
private AddressAccessInformation(boolean canTrap, int disp) {
this.canTrap = canTrap;
this.scale = Scale.Times1;
this.disp = disp;
}
private AddressAccessInformation(boolean canTrap, int disp, Scale scale) {
this.canTrap = canTrap;
this.scale = scale;
this.disp = disp;
}
}
/**
* A label that is the target of a control flow instruction.
*/
public static class XirLabel {
public static final String TrueSuccessor = "TrueSuccessor";
public static final String FalseSuccessor = "FalseSuccessor";
public final String name;
public final int index;
/**
* If {@code true} the label is to an instruction in the fast path sequence, otherwise to the slow path.
*/
public final boolean inline;
private XirLabel(String name, int index, boolean inline) {
this.name = name;
this.index = index;
this.inline = inline;
}
@Override
public String toString() {
return name;
}
}
/**
* Tagging interface that indicates that an {@link XirOperand} is a constant.
*/
public interface XirConstantOperand {
int getIndex();
}
public static final XirOperand VOID = null;
/**
* Operands for {@link XirInstruction instructions}.
* There are three basic variants, {@link XirConstant constant}, {@link XirParameter parameter} and {@link XirTemp}.
*/
public abstract static class XirOperand {
public final CiKind kind;
/**
* Unique id in range {@code 0} to {@link #variableCount variableCount - 1}.
*/
public final int index;
/**
* Value whose {@link #toString()} method provides a name for this operand.
*/
public final Object name;
public XirOperand(CiXirAssembler asm, Object name, CiKind kind) {
this.kind = kind;
this.name = name;
this.index = asm.variableCount++;
}
@Override
public String toString() {
return String.valueOf(name);
}
public String detailedToString() {
StringBuffer sb = new StringBuffer();
sb.append(name);
sb.append('$');
sb.append(kind.typeChar);
return sb.toString();
}
}
/**
* Parameters to {@link XirTemplate templates}.
*/
public static class XirParameter extends XirOperand {
/**
* Unique id in range {@code 0} to {@code parameters.Size() - 1}.
*/
public final int parameterIndex;
public final boolean canBeConstant;
XirParameter(CiXirAssembler asm, String name, CiKind kind, boolean canBeConstant) {
super(asm, name, kind);
this.parameterIndex = asm.parameters.size();
this.canBeConstant = canBeConstant;
asm.parameters.add(this);
}
}
public static class XirConstantParameter extends XirParameter implements XirConstantOperand {
XirConstantParameter(CiXirAssembler asm, String name, CiKind kind) {
super(asm, name, kind, true);
}
public int getIndex() {
return index;
}
}
public static class XirVariableParameter extends XirParameter {
XirVariableParameter(CiXirAssembler asm, String name, CiKind kind, boolean canBeConstant) {
super(asm, name, kind, canBeConstant);
}
}
public static class XirConstant extends XirOperand implements XirConstantOperand {
protected CiConstant value;
XirConstant(CiXirAssembler asm, CiConstant value) {
super(asm, value, value.kind);
this.value = value;
}
protected XirConstant(CiXirAssembler asm, Object name, CiConstant value) {
super(asm, name, value.kind);
this.value = value;
}
public final CiConstant value() {
return value;
}
public int getIndex() {
return index;
}
}
public static class XirTemp extends XirOperand {
public final boolean reserve;
XirTemp(CiXirAssembler asm, String name, CiKind kind, boolean reserve) {
super(asm, name, kind);
this.reserve = reserve;
}
}
public static class XirRegister extends XirTemp {
public final CiValue register;
XirRegister(CiXirAssembler asm, String name, CiRegisterValue register, boolean reserve) {
super(asm, name, register.kind, reserve);
this.register = register;
}
}
/**
* Start a new assembly with no initial {@link #resultOperand result operand}.
*/
public void restart() {
reset();
resultOperand = null;
}
/**
* Start a new assembly with a {@link #resultOperand result operand} of type {@code kind}.
* @param kind the result kind
* @return an {@code XirOperand} for the result operand
*/
public XirOperand restart(CiKind kind) {
reset();
resultOperand = new XirTemp(this, "result", kind, true);
allocateResultOperand = true;
return resultOperand;
}
/**
* Reset the state of the class to the initial conditions to facilitate a new assembly.
*/
private void reset() {
assert finished : "must be finished before!";
variableCount = 0;
allocateResultOperand = false;
finished = false;
instructions.clear();
labels.clear();
parameters.clear();
temps.clear();
constants.clear();
marks.clear();
outgoingStackSize = 0;
}
/**
* Represents an XIR instruction, characterized by an {@link XirOp operation}, a {@link CiKind kind}, an optional {@link XirOperand result}, a variable number of {@link XirOperand arguments},
* and some optional instruction-specific state. The {@link #x}, {@link #y} and {@link #z} methods are convenient ways to access the first, second and third
* arguments, respectively. Only the {@link XirOp#CallStub} and {@link XirOp#CallRuntime} instructions can have more than three arguments.
*
*/
public static final class XirInstruction {
/**
* The {@link CiKind kind} of values the instruction operates on.
*/
public final CiKind kind;
/**
* The {@link XirOp operation}.
*/
public final XirOp op;
/**
* The result, if any.
*/
public final XirOperand result;
/**
* The arguments.
*/
public final XirOperand[] arguments;
/**
* Arbitrary additional data associated with the instruction.
*/
public final Object extra;
public XirInstruction(CiKind kind, XirOp op, XirOperand result, XirOperand... arguments) {
this(kind, null, op, result, arguments);
}
public XirInstruction(CiKind kind, Object extra, XirOp op, XirOperand result, XirOperand... arguments) {
this.extra = extra;
this.kind = kind;
this.op = op;
this.result = result;
this.arguments = arguments;
}
public XirOperand x() {
assert arguments.length > 0 : "no x operand for this instruction";
return arguments[0];
}
public XirOperand y() {
assert arguments.length > 1 : "no y operand for this instruction";
return arguments[1];
}
public XirOperand z() {
assert arguments.length > 2 : "no z operand for this instruction";
return arguments[2];
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
if (result != null) {
sb.append(result.toString());
sb.append(" = ");
}
sb.append(op.name());
if (kind != CiKind.Void) {
sb.append('$');
sb.append(kind.typeChar);
}
if (arguments != null && arguments.length > 0) {
sb.append("(");
for (int i = 0; i < arguments.length; i++) {
if (i != 0) {
sb.append(", ");
}
sb.append(arguments[i]);
}
sb.append(")");
}
if (extra != null) {
sb.append(" ");
sb.append(extra);
}
return sb.toString();
}
}
/**
* These marks let the RiXirGenerator mark positions in the generated native code and bring them in relationship with on another.
* This is necessary for code patching, etc.
*/
public static class XirMark {
public final XirMark[] references;
public final Object id;
// special mark used to refer to the actual call site of an invoke
public static final XirMark CALLSITE = new XirMark(null);
public XirMark(Object id, XirMark... references) {
this.id = id;
this.references = references;
}
}
/**
* The set of opcodes for XIR instructions.
* {@link XirInstruction} defines {@code x}, {@code y} and {@code z} as the first, second and third arguments, respectively.
* We use these mnemonics, plus {@code args} for the complete set of arguments, {@code r} for the result, and {@code extra}
* for the instruction-specific extra data, in the opcode specifications. Note that the opcodes that operate on values do not directly
* specify the size (kind) of the data operated on; this is is encoded in {@link XirInstruction#kind}.
* Note: If the instruction kind differs from the argument/result kinds, the behavior is undefined.
*
*/
public enum XirOp {
/**
* Move {@code x} to {@code r}.
*/
Mov,
/**
* Add {@code y} to {@code x} and put the result in {@code r}.
*/
Add,
/**
* Subtract {@code y} from {@code x} and put the result in {@code r}.
*/
Sub,
/**
* Divide {@code y} by {@code x} and put the result in {@code r}.
*/
Div,
/**
* Multiply {@code y} by {@code x} and put the result in {@code r}.
*/
Mul,
/**
* {@code y} modulus {@code x} and put the result in {@code r}.
*/
Mod,
/**
* Shift {@code y} left by {@code x} and put the result in {@code r}.
*/
Shl,
/**
* Arithmetic shift {@code y} right by {@code x} and put the result in {@code r}.
*/
Sar,
/**
* Shift {@code y} right by {@code x} and put the result in {@code r}.
*/
Shr,
/**
* And {@code y} by {@code x} and put the result in {@code r}.
*/
And,
/**
* Or {@code y} by {@code x} and put the result in {@code r}.
*/
Or,
/**
* Exclusive Or {@code y} by {@code x} and put the result in {@code r}.
*/
Xor,
/**
* Null check on {@code x}.
*/
NullCheck,
/**
* Load value at address {@code x} and put the result in {@code r}.
*/
PointerLoad,
/**
* Store {@code y} at address {@code x}.
*/
PointerStore,
/**
* Load value at an effective address defined by base {@code x} and either a scaled index {@code y} plus displacement
* or an offset {@code y} and put the result in {@code r}.
*/
PointerLoadDisp,
/**
* Load an effective address defined by base {@code x} and either a scaled index {@code y} plus displacement
* or an offset {@code y} and put the result in {@code r}.
*/
LoadEffectiveAddress,
/**
* Store {@code z} at address defined by base {@code x} and index {@code y}.
*/
PointerStoreDisp,
/**
* Repeat move from {@code x} to {@code y} using {@code z} words.
*/
RepeatMoveWords,
/**
* Repeat move from {@code x} to {@code y} using {@code z} words.
*/
RepeatMoveBytes,
/**
* Compare value at at address {@code x} with value in {@code y} and store value {@code z} at address {@code x}
* if it was equal to {@code y}.
*/
PointerCAS,
/**
* Call the {@link XirTemplate.GlobalFlags#GLOBAL_STUB shared stub} defined by {@code extra} with {@code args} and put the result in {@code r}.
*/
CallStub,
/**
* Call the {@link RiMethod} defined by {@code extra} with {@code args} and put the result in {@code r}.
*/
CallRuntime,
/**
* Transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}.
*/
Jmp,
/**
* If {@code x == y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}.
*/
Jeq,
/**
* If {@code x != y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}.
*/
Jneq,
/**
* If {@code x > y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}.
*/
Jgt,
/**
* If {@code x >= y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}.
*/
Jgteq,
/**
* If {@code x unsigned >= y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}.
*/
Jugteq,
/**
* If {@code x < y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}.
*/
Jlt,
/**
* If {@code x <= y}, transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}.
*/
Jlteq,
/**
* Decreases the input by one and jumps to the target if the input is not 0.
*/
DecAndJumpNotZero,
/**
* If bit designated by {@code z} at effective address defined by base {@code x} and offset {@code y}
* is set transfer control to the instruction at the {@link XirLabel label} identified by {@code extra}.
*/
Jbset,
/**
* Bind the {@link XirLabel label} identified by {@code extra} to the current instruction and update any references to it.
* A label may be bound more than once to the same location.
*/
Bind,
/**
* Record a safepoint.
*/
Safepoint,
/**
* Align the code following this instruction to a multiple of (int)extra.
*/
Align,
/**
* Creates the stack banging overflow check.
*/
StackOverflowCheck,
/**
* Creates the stack frame for the method and spills callee-save registers (if any) to the {@linkplain CiRegisterSaveArea register save area}.
*/
PushFrame,
/**
* Restores all callee-save registers (if any) and removes the stack frame of the method.
*/
PopFrame,
/**
* Inserts an array of bytes directly into the code output.
*/
RawBytes,
/**
* Pushes a value onto the stack.
*/
Push,
/**
* Pops a value from the stack.
*/
Pop,
/**
* Marks a position in the generated native code.
*/
Mark,
/**
* Load instruction pointer of the next instruction in a destination register.
*/
Here,
/**
* Inserts nop instructions, with the given size in bytes.
*/
Nop,
/**
* This instruction should never be reached, this is useful for debugging purposes.
*/
ShouldNotReachHere
}
public/*private*/ void append(XirInstruction xirInstruction) {
assert !finished : "no instructions can be added to finished template";
instructions.add(xirInstruction);
}
public XirLabel createInlineLabel(String name) {
final XirLabel result = new XirLabel(name, this.labels.size(), true);
labels.add(result);
return result;
}
public XirLabel createOutOfLineLabel(String name) {
final XirLabel result = new XirLabel(name, this.labels.size(), false);
labels.add(result);
return result;
}
public void mov(XirOperand result, XirOperand a) {
append(new XirInstruction(result.kind, Mov, result, a));
}
public void add(XirOperand result, XirOperand a, XirOperand b) {
append(new XirInstruction(result.kind, Add, result, a, b));
}
public void sub(XirOperand result, XirOperand a, XirOperand b) {
append(new XirInstruction(result.kind, Sub, result, a, b));
}
public void div(XirOperand result, XirOperand a, XirOperand b) {
append(new XirInstruction(result.kind, Div, result, a, b));
}
public void mul(XirOperand result, XirOperand a, XirOperand b) {
append(new XirInstruction(result.kind, Mul, result, a, b));
}
public void mod(XirOperand result, XirOperand a, XirOperand b) {
append(new XirInstruction(result.kind, Mod, result, a, b));
}
public void shl(XirOperand result, XirOperand a, XirOperand b) {
append(new XirInstruction(result.kind, Shl, result, a, b));
}
public void shr(XirOperand result, XirOperand a, XirOperand b) {
append(new XirInstruction(result.kind, Shr, result, a, b));
}
public void and(XirOperand result, XirOperand a, XirOperand b) {
append(new XirInstruction(result.kind, And, result, a, b));
}
public void or(XirOperand result, XirOperand a, XirOperand b) {
append(new XirInstruction(result.kind, Or, result, a, b));
}
public void xor(XirOperand result, XirOperand a, XirOperand b) {
append(new XirInstruction(result.kind, Xor, result, a, b));
}
public void nullCheck(XirOperand pointer) {
append(new XirInstruction(CiKind.Object, NullCheck, VOID, pointer));
}
public void pload(CiKind kind, XirOperand result, XirOperand pointer, boolean canTrap) {
append(new XirInstruction(kind, canTrap, PointerLoad, result, pointer));
}
public void pstore(CiKind kind, XirOperand pointer, XirOperand value, boolean canTrap) {
append(new XirInstruction(kind, canTrap, PointerStore, null, pointer, value));
}
public void pload(CiKind kind, XirOperand result, XirOperand pointer, XirOperand offset, boolean canTrap) {
append(new XirInstruction(kind, new AddressAccessInformation(canTrap), PointerLoadDisp, result, pointer, offset));
}
public void pstore(CiKind kind, XirOperand pointer, XirOperand offset, XirOperand value, boolean canTrap) {
append(new XirInstruction(kind, new AddressAccessInformation(canTrap), PointerStoreDisp, VOID, pointer, offset, value));
}
public void pload(CiKind kind, XirOperand result, XirOperand pointer, XirOperand index, int disp, Scale scale, boolean canTrap) {
append(new XirInstruction(kind, new AddressAccessInformation(canTrap, disp, scale), PointerLoadDisp, result, pointer, index));
}
public void lea(XirOperand result, XirOperand pointer, XirOperand index, int disp, Scale scale) {
append(new XirInstruction(target.wordKind, new AddressAccessInformation(false, disp, scale), LoadEffectiveAddress, result, pointer, index));
}
public void repmov(XirOperand src, XirOperand dest, XirOperand length) {
append(new XirInstruction(target.wordKind, null, RepeatMoveWords, null, src, dest, length));
}
public void here(XirOperand dst) {
append(new XirInstruction(target.wordKind, null, Here, dst));
}
public void repmovb(XirOperand src, XirOperand dest, XirOperand length) {
append(new XirInstruction(target.wordKind, null, RepeatMoveBytes, null, src, dest, length));
}
public void pstore(CiKind kind, XirOperand pointer, XirOperand index, XirOperand value, int disp, Scale scale, boolean canTrap) {
append(new XirInstruction(kind, new AddressAccessInformation(canTrap, disp, scale), PointerStoreDisp, VOID, pointer, index, value));
}
public void pcas(CiKind kind, XirOperand result, XirOperand pointer, XirOperand newValue, XirOperand oldValue) {
append(new XirInstruction(kind, null, PointerCAS, result, pointer, newValue, oldValue));
}
public void jmp(XirLabel l) {
append(new XirInstruction(CiKind.Void, l, Jmp, null));
}
public void decAndJumpNotZero(XirLabel l, XirOperand val) {
append(new XirInstruction(CiKind.Void, l, DecAndJumpNotZero, null, val));
}
public void jmpRuntime(Object rt) {
append(new XirInstruction(CiKind.Void, rt, Jmp, null));
}
public void jeq(XirLabel l, XirOperand a, XirOperand b) {
jcc(Jeq, l, a, b);
}
private void jcc(XirOp op, XirLabel l, XirOperand a, XirOperand b) {
append(new XirInstruction(CiKind.Void, l, op, null, a, b));
}
public void jneq(XirLabel l, XirOperand a, XirOperand b) {
jcc(Jneq, l, a, b);
}
public void jgt(XirLabel l, XirOperand a, XirOperand b) {
jcc(Jgt, l, a, b);
}
public void jgteq(XirLabel l, XirOperand a, XirOperand b) {
jcc(Jgteq, l, a, b);
}
public void jugteq(XirLabel l, XirOperand a, XirOperand b) {
jcc(Jugteq, l, a, b);
}
public void jlt(XirLabel l, XirOperand a, XirOperand b) {
jcc(Jlt, l, a, b);
}
public void jlteq(XirLabel l, XirOperand a, XirOperand b) {
jcc(Jlteq, l, a, b);
}
public void jbset(XirLabel l, XirOperand a, XirOperand b, XirOperand c) {
append(new XirInstruction(CiKind.Void, l, Jbset, null, a, b, c));
}
public void bindInline(XirLabel l) {
assert l.inline;
append(new XirInstruction(CiKind.Void, l, Bind, null));
}
public void bindOutOfLine(XirLabel l) {
assert !l.inline;
append(new XirInstruction(CiKind.Void, l, Bind, null));
}
public void safepoint() {
append(new XirInstruction(CiKind.Void, null, Safepoint, null));
}
public void align(int multiple) {
assert multiple > 0;
append(new XirInstruction(CiKind.Void, multiple, Align, null));
}
public void stackOverflowCheck() {
append(new XirInstruction(CiKind.Void, null, StackOverflowCheck, null));
}
public void pushFrame() {
append(new XirInstruction(CiKind.Void, null, PushFrame, null));
}
public void popFrame() {
append(new XirInstruction(CiKind.Void, null, PopFrame, null));
}
public void rawBytes(byte[] bytes) {
append(new XirInstruction(CiKind.Void, bytes, RawBytes, null));
}
public void push(XirOperand value) {
append(new XirInstruction(CiKind.Void, Push, VOID, value));
}
public void pop(XirOperand result) {
append(new XirInstruction(result.kind, Pop, result));
}
public XirMark mark(Object id, XirMark... references) {
XirMark mark = new XirMark(id, references);
marks.add(mark);
append(new XirInstruction(CiKind.Void, mark, Mark, null));
return mark;
}
public void nop(int size) {
append(new XirInstruction(CiKind.Void, size, Nop, null));
}
public void shouldNotReachHere() {
append(new XirInstruction(CiKind.Void, null, ShouldNotReachHere, null));
}
public void shouldNotReachHere(String message) {
append(new XirInstruction(CiKind.Void, message, ShouldNotReachHere, null));
}
public void callStub(XirTemplate stub, XirOperand result, XirOperand... args) {
CiKind resultKind = result == null ? CiKind.Void : result.kind;
append(new XirInstruction(resultKind, stub, CallStub, result, args));
}
public void callRuntime(Object rt, XirOperand result, XirOperand... args) {
callRuntime(rt, result, false, args);
}
public void callRuntime(Object rt, XirOperand result, boolean useInfoAfter, XirOperand... args) {
CiKind resultKind = result == null ? CiKind.Void : result.kind;
append(new XirInstruction(resultKind, new RuntimeCallInformation(rt, useInfoAfter), CallRuntime, result, args));
}
/**
* Terminates the assembly, checking invariants, in particular that {@link resultOperand} is set, and setting {@link #finished} to {@code true}.
*/
private void end() {
assert !finished : "template may only be finished once!";
assert resultOperand != null : "result operand should be set";
finished = true;
}
/**
* Creates an {@link XirVariableParameter variable input parameter} of given name and {@link CiKind kind}.
* @param name a name for the parameter
* @param kind the parameter kind
* @return the {@link XirVariableParameter}
*/
public XirVariableParameter createInputParameter(String name, CiKind kind, boolean canBeConstant) {
assert !finished;
return new XirVariableParameter(this, name, kind, canBeConstant);
}
public XirVariableParameter createInputParameter(String name, CiKind kind) {
return createInputParameter(name, kind, false);
}
/**
* Creates an {@link XirConstantParameter constant input parameter} of given name and {@link CiKind kind}.
* @param name a name for the parameter
* @param kind the parameter kind
* @return the {@link XirConstantParameter}
*/
public XirConstantParameter createConstantInputParameter(String name, CiKind kind) {
assert !finished;
return new XirConstantParameter(this, name, kind);
}
public XirConstant createConstant(CiConstant constant) {
assert !finished;
XirConstant temp = new XirConstant(this, constant);
constants.add(temp);
return temp;
}
public void recordConstant(XirConstant constant) {
assert !finished;
constants.add(constant);
}
public XirOperand createTemp(String name, CiKind kind) {
assert !finished;
XirTemp temp = new XirTemp(this, name, kind, true);
temps.add(temp);
return temp;
}
public XirOperand createRegister(String name, CiKind kind, CiRegister register) {
return createRegister(name, kind, register, false);
}
public XirOperand createRegisterTemp(String name, CiKind kind, CiRegister register) {
return createRegister(name, kind, register, true);
}
private XirOperand createRegister(String name, CiKind kind, CiRegister register, boolean reserve) {
assert !finished;
XirRegister fixed = new XirRegister(this, name, register.asValue(kind), reserve);
temps.add(fixed);
return fixed;
}
public XirParameter getParameter(String name) {
for (XirParameter param : parameters) {
if (param.name.toString().equals(name)) {
return param;
}
}
throw new IllegalArgumentException("no parameter: " + name);
}
public XirTemp getTemp(String name) {
for (XirTemp temp : temps) {
if (temp.name.toString().equals(name)) {
return temp;
}
}
throw new IllegalArgumentException("no temp: " + name);
}
public XirConstant i(int v) {
return createConstant(CiConstant.forInt(v));
}
public XirConstant l(int v) {
return createConstant(CiConstant.forLong(v));
}
public XirConstant b(boolean v) {
return createConstant(CiConstant.forBoolean(v));
}
public XirConstant o(Object obj) {
return createConstant(CiConstant.forObject(obj));
}
public void reserveOutgoingStack(int size) {
outgoingStackSize = Math.max(outgoingStackSize, size);
}
/**
* Finishes the assembly of a non-stub template, providing the {@link #resultOperand} and constructs the {@link XirTemplate}.
* @param result the {@link XirOperand} to be set as the {@link #resultOperand}
* @param name the name of the template
* @return the generated template
*/
public XirTemplate finishTemplate(XirOperand result, String name) {
assert this.resultOperand == null;
assert result != null;
this.resultOperand = result;
final XirTemplate template = buildTemplate(name, false);
end();
return template;
}
/**
* Finishes the assembly of a non-stub template and constructs the {@link XirTemplate}.
* @param name the name of the template
* @return the generated template
*/
public XirTemplate finishTemplate(String name) {
final XirTemplate template = buildTemplate(name, false);
end();
return template;
}
/**
* Finishes the assembly of a {@link XirTemplate.GlobalFlags#GLOBAL_STUB stub} and constructs the {@link XirTemplate}.
* @param name the name of the template
* @return the generated template
*/
public XirTemplate finishStub(String name) {
final XirTemplate template = buildTemplate(name, true);
end();
return template;
}
/**
* Builds the {@link XirTemplate} from the assembly state in this object.
* The actual assembly is dependent on the target architecture and implemented
* in a concrete subclass.
* @param name the name of the template
* @param isStub {@code true} if the template represents a {@link XirTemplate.GlobalFlags#GLOBAL_STUB stub}
* @return the generated template
*/
protected abstract XirTemplate buildTemplate(String name, boolean isStub);
public abstract CiXirAssembler copy();
}