slcom/slangc/api/BytecodeInstructionWriter.sauce

1024 lines
28 KiB
Plaintext
Raw Normal View History

package slangc.api;
import slang.data.List;
import slangc.api.BytecodeHeap;
import slangc.api.TypeOption;
import slangc.bytecode.FieldSignature;
import slangc.bytecode.MethodSignature;
import slangc.bytecode.TypeSignature;
import slangc.model.BuiltinTypeModel;
import slangc.model.TypeModel;
import slangc.model.UserTypeModel;
import slangc.parser.AnnotationType;
import slangc.parser.ErrorType;
import slangc.parser.LocationAnnotation;
import slangc.parser.Node;
public class BytecodeInstructionWriter {
public final BytecodeTarget target;
public final TypeModel owner;
public final BytecodeHeap.ObjectLike method;
private BytecodeHeap.ArrayInt32 instructions;
private List<Node> sourceStack = new List<Node>();
private List<Label> breakStack = new List<Label>();
private List<Label> continueStack = new List<Label>();
private List<Label> labels = new List<Label>();
private List<Location> locations = new List<Location>();
private List<Reference> references = new List<Reference>();
private int currentStackSize = 0;
private int maxStackSize = 0;
public static class Reference {
public int referenceLocation;
public Label targetLabel;
public boolean isLinked;
//public boolean compressed;
}
public static class Location {
public int instruction;
public int line;
public int character;
public Location(int instruction, int line, int character) {
super();
this.instruction = instruction;
this.line = line;
this.character = character;
}
public void genLocationData(BytecodeHeap.ArrayInt16 dbglist, boolean b) {
if (dbglist.elementsLength() == 0 || dbglist.getElement(dbglist.elementsLength() - 1) != line) {
dbglist.appendElement((short) instruction);
dbglist.appendElement((short) line);
}
}
}
public static class Label {
public String name;
public int location = -1;
public int stackSize = -1;
public Label(String name) {
this.name = name;
}
public byte labelTypeCode() {
return 1;
}
public void genLabelData(BytecodeHeap.ArrayInt32 lbllist, boolean verbose) {
if (verbose) {
lbllist.appendElement(labelTypeCode());
int nameidx = lbllist.getHeap().getConstString(name).recordIndex;
lbllist.appendElement(nameidx);
//lbllist.appendElement((short) (nameidx >> 16));
lbllist.appendElement(location);
//lbllist.appendElement((short) (location >> 16));
}
}
}
public static class TryLabel extends Label {
Label begin;
Label end;
public TryLabel(String name, Label begin, Label end) {
super(name);
this.begin = begin;
this.end = end;
}
@Override
public byte labelTypeCode() {
return 2;
}
@Override
public void genLabelData(BytecodeHeap.ArrayInt32 lbllist, boolean verbose) {
lbllist.appendElement(labelTypeCode());
int nameidx = lbllist.getHeap().getConstString(name).recordIndex;
lbllist.appendElement(nameidx);
//lbllist.appendElement((short) (nameidx >> 16));
lbllist.appendElement(location);
//lbllist.appendElement((short) (location >> 16));
lbllist.appendElement(begin.location);
//lbllist.appendElement((short) (begin.location >> 16));
lbllist.appendElement(end.location);
//lbllist.appendElement((short) (end.location >> 16));
}
}
public static class CatchLabel extends TryLabel {
TypeSignature type;
public CatchLabel(String name, Label begin, Label end, TypeSignature type) {
super(name, begin, end);
this.type = type;
}
@Override
public byte labelTypeCode() {
return 3;
}
@Override
public void genLabelData(BytecodeHeap.ArrayInt32 lbllist, boolean verbose) {
super.genLabelData(lbllist, true); // TODO: Should this be true
int tidx = lbllist.getHeap().getTypeSignature(type).recordIndex;
lbllist.appendElement(tidx);
//lbllist.appendElement((short) (tidx >> 16));
}
}
public static class FinallyLabel extends TryLabel {
public FinallyLabel(String name, Label begin, Label end) {
super(name, begin, end);
}
@Override
public byte labelTypeCode() {
return 4;
}
@Override
public void genLabelData(BytecodeHeap.ArrayInt32 lbllist, boolean verbose) {
super.genLabelData(lbllist, true);
}
}
public static class EndTryLabel extends Label {
public EndTryLabel(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override
public byte labelTypeCode() {
return 5;
}
@Override
public void genLabelData(BytecodeHeap.ArrayInt32 lbllist, boolean verbose) {
super.genLabelData(lbllist, true);
}
}
public BytecodeInstructionWriter(BytecodeTarget target, TypeModel owner, BytecodeHeap.ObjectLike method) {
super();
this.target = target;
this.owner = owner;
this.method = method;
}
public boolean hasLabel(String uniqueName) {
return findLabel(uniqueName) != null;
}
public Label findLabel(String uniqueName) {
for (int i = 0; i < labels.count(); i++) {
if (labels.get(i).name.equals(uniqueName)) {
return labels.get(i);
}
}
return null;
}
/* Returns a name like "startOfLoop4" using a base name like "startOfLoop". */
public String nextLabelName(String baseName) {
int x = 1;
while (hasLabel(baseName + x)) {
x++;
}
return baseName + x;
}
public Label newLabel(String baseName) {
Label result = new Label(nextLabelName(baseName));
labels.append(result);
return result;
}
public CatchLabel newCatchLabel(String baseName, Label begin, Label end, TypeSignature catchType) {
CatchLabel result = new CatchLabel(nextLabelName(baseName), begin, end, catchType);
labels.append(result);
return result;
}
public FinallyLabel newFinallyLabel(String baseName, Label begin, Label end) {
FinallyLabel result = new FinallyLabel(nextLabelName(baseName), begin, end);
labels.append(result);
return result;
}
public void labelHere(Label l) {
l.location = currentLocation();
}
public StackType stackType(TypeSignature type) {
return target.stackType(type); // Moved here so they can be cached
}
/*public StackType stackType(TypeSignature type) {
if (type.mappableEquals(TypeSignature.VOID)) {
return StackType.VOID;
} /X*else if (type.mappableEquals(getTarget().getSystem().getDefaultBooleanType().getTypeSignature())) {
return StackType.BIT;
} else if (type.mappableEquals(getTarget().getSystem().getDefaultFloat32Type().getTypeSignature())) {
return StackType.FLOAT32;
} else if (type.mappableEquals(getTarget().getSystem().getDefaultFloat64Type().getTypeSignature())) {
return StackType.FLOAT64;
} else if (type.mappableEquals(getTarget().getSystem().getDefaultInt64Type().getTypeSignature())) {
return StackType.INT64;
} else if (getTarget().getSystem().matchesTypeOption(TypeOption.Kind.DUCK, type)) {
return StackType.DUCK;
}*X/ else if (getTarget().getSystem().getType(type) instanceof BuiltinTypeModel) {
for (int i = 0; i < StackType.lookupCount(StackType.class); i++) {
if (getTarget().getSystem().matchesTypeOption((TypeOption.Kind)TypeOption.Kind.lookup(TypeOption.Kind.class, i), type)) {
return (StackType)StackType.lookup(StackType.class, i);
}
}
return StackType.INT32;
} else {
for (int i = 0; i < StackType.lookupCount(StackType.class); i++) {
if (getTarget().getSystem().matchesTypeOption((TypeOption.Kind)TypeOption.Kind.lookup(TypeOption.Kind.class, i), type)) {
return (StackType)StackType.lookup(StackType.class, i);
}
}
return StackType.OBJECT;
}
}*/
public StackType stackType(BytecodeHeap.StandardClass type) {
switch (type) {
default:
return StackType.OBJECT;
}
}
public void vpush(TypeSignature type) {
vpush(stackType(type));
}
public void vpop(TypeSignature type) {
vpop(stackType(type));
}
public void vpush(BytecodeHeap.StandardClass type) {
vpush(stackType(type));
}
public void vpop(BytecodeHeap.StandardClass type) {
vpop(stackType(type));
}
public void vpush(StackType type) {
if (type == StackType.VOID) {
return;
}
currentStackSize++;
if (currentStackSize > maxStackSize) {
maxStackSize = currentStackSize;
}
}
public void vpop(StackType type) {
if (type == StackType.VOID) {
return;
}
currentStackSize--;
if (currentStackSize < 0) {
genError("Stack underflow");
Log.line("WARNING: Stack underflow");
currentStackSize = 0;
//throw new Error("Stack underflow");
}
}
public int currentLocation() {
if (instructions == null) {
return 0;
} else {
return instructions.elementsLength();
}
}
public BytecodeHeap.ArrayInt32 writableInstructions() {
if (instructions == null) {
instructions = target.heap.newInstructions(0);
method.setElement(BytecodeHeap.MethodFields.BYTECODE.value, instructions);
}
return instructions;
}
//public void writeRaw16(short data) {
// writableInstructions().appendElement(data);
//}
public void writeRaw32(int data, boolean canBeBig) {
if (!canBeBig && ((data & 0xFFFF) != data)) throw new Error("This data (" + data + ") isn't allowed to be this big!");
writableInstructions().appendElement(data);
//writeRaw16((short) data);
//writeRaw16((short) (data >> 16));
}
public void writeRef(Label label/*, boolean compressed*/) {
Reference r = new Reference();
references.append(r);
r.referenceLocation = currentLocation();
r.targetLabel = label;
//r.compressed = compressed;
if (label.location >= 0) {
writeRaw32(label.location, true);
r.isLinked = true;
} else {
writeRaw32(-1, true);
r.isLinked = false;
}
}
public void linkRef(Reference r) {
if (!r.isLinked) {
if (r.targetLabel.location < 0) {
throw new Error("Can't link - label '" + r.targetLabel.name + "' hasn't been assigned a valid location");
}
writableInstructions().setElement(r.referenceLocation, r.targetLabel.location);
/*if (!r.compressed) {
writableInstructions().setElement(r.referenceLocation + 1, (short) (r.targetLabel.location >> 16));
}*/
}
}
public void linkAllRefs() {
for (int i = 0; i < references.count(); i++) {
linkRef(references.get(i));
}
}
public void writeRef(BytecodeHeap.Record record) {
writeRaw32(record.getRecordIndex(), true);
}
/**
* Called when generating most statements/expressions/clauses to give the nearest source
* for debugging purposes. When generating synthetic code, null should be pushed instead.
*/
public void pushSource(Node source) {
sourceStack.append(source);
}
public Node popSource() {
return sourceStack.pop();
}
public void popSource(Node source) {
Node popped = popSource();
if (popped != source) {
throw new Error("Source stack mismatch: Expecting " + source + " but got " + popped);
}
}
public void pushBreak(Label label) {
breakStack.append(label);
}
public Label getBreak() {
if (breakStack.count() < 1) {
return null;
}
return breakStack.get(breakStack.count()-1);
}
public Label popBreak() {
return breakStack.pop();
}
public void popBreak(Label label) {
Label popped = popBreak();
if (popped != label) {
throw new Error("Break stack mismatch: Expecting " + label + " but got " + popped);
}
}
public void pushContinue(Label label) {
continueStack.append(label);
}
public Label getContinue() {
if (continueStack.count() < 1) {
return null;
}
return continueStack.get(continueStack.count()-1);
}
public Label popContinue() {
return continueStack.pop();
}
public void popContinue(Label label) {
Label popped = popContinue();
if (popped != label) {
throw new Error("Continue stack mismatch: Expecting " + label + " but got " + popped);
}
}
public Node getNearestSource(boolean requireLocation) {
for (int i = sourceStack.count() - 1; i >= 0; i--) {
if (sourceStack.get(i) != null) {
if (!requireLocation || sourceStack.get(i).countAnnotations(AnnotationType.LOCATION) > 0) {
return sourceStack.get(i);
}
}
}
return null;
}
public int getNearestLine() {
Node s = getNearestSource(true);
if (s == null) {
return 0;
}
LocationAnnotation l = (LocationAnnotation) s.getAnnotations(AnnotationType.LOCATION)[0];
return l.getToken().getSnippet().getStart().getLineCount();
}
public int getNearestCharacter() {
Node s = getNearestSource(true);
if (s == null) {
return 0;
}
LocationAnnotation l = (LocationAnnotation) s.getAnnotations(AnnotationType.LOCATION)[0];
return l.getToken().getSnippet().getStart().getCharacterCount();
}
public boolean isPartlySynthetic() {
for (int i = 0; i < sourceStack.count(); i++) {
if (sourceStack.get(i) == null) {
return true;
}
}
return false;
}
public static enum ParameterFormat {
NONE,
CONSTANT_INDEX,
INSTRUCTION_INDEX,
VARIABLE_INDEX
}
public static enum MajorOpcode {
RESERVED,
ALU,
COMP,
CALL,
JUMP,
MEM,
TYPE,
MISC,
TINYCONST,
EXTENSION_A,
EXTENSION_B,
EXTENSION_C,
EXTENSION_D,
}
public static enum MiscOp {
CONST,
CONST_SPLIT32,
CONST24,
RETURN,
THROW,
RESERVED_FOR_ASSERT,
DROP,
DUP,
SWAP,
STRCAT,
NOT,
LOCK,
UNLOCK,
CHECKRETHROW
}
public static enum TypeOp {
DECLARE_LOCAL,
NEW_ARRAY,
CONVERT,
CONVERT_SMALL,
TYPECHECK,
ARRAYLENGTH,
THIS,
OUTERTHIS,
TYPEOBJECT,
}
public static enum CallOp {
STATIC_FUNCTION,
STATIC_PROCEDURE,
INSTANCE_FUNCTION,
INSTANCE_PROCEDURE,
INTERFACE_FUNCTION,
INTERFACE_PROCEDURE,
SUPER_INSTANCE_FUNCTION,
SUPER_INSTANCE_PROCEDURE,
SUPER_INTERFACE_FUNCTION,
SUPER_INTERFACE_PROCEDURE,
CONSTRUCTOR_NEW,
CONSTRUCTOR_NESTED,
CONSTRUCTOR_INNER
}
public static enum JumpOp {
GOTO,
IFTRUE,
IFFALSE
}
/* These should match the first 16 TypeOption.Kind values. */
public static enum StackType {
/* #0-#3 are used for special types (these are not valid in all scenarios). */
UNINITIALISED,
INVALID,
DUCK,
VOID,
/* #4 is the object type. */
OBJECT,
/* #5-#7 are the basic non-integer primitives. */
BIT,
FLOAT32,
FLOAT64,
/* #8-#15 are the basic integer primitives. */
INT8,
INT16,
INT32,
INT64,
UINT8,
UINT16,
UINT32,
UINT64
/*
INT32,
UINT32,
FLOAT32,
EXT32,
INT64,
UINT64,
FLOAT64,
EXT64,
EXTA,
EXTB,
EXTC,
EXTD,
OBJECT,
RESERVED1,
BOOLEAN,
VOID
*/
}
public static enum MemOp {
LOAD_LOCAL,
LOAD_PARAM,
LOAD_INSTANCE_FIELD,
LOAD_STATIC_FIELD,
LOAD_ARRAY,
LOAD_EXT1,
LOAD_EXT2,
LOAD_EXT3,
STORE_LOCAL,
STORE_PARAM,
STORE_INSTANCE_FIELD,
STORE_STATIC_FIELD,
STORE_ARRAY,
STORE_EXT1,
STORE_EXT2,
STORE_EXT3
}
public static enum ALUOp {
ADD,
SUB,
MUL,
DIV,
MOD,
SHRS,
SHRZ,
SHLZ,
AND,
OR,
XOR
}
public static enum CompOp {
EQUAL,
NOT_EQUAL,
ABOVE,
ABOVE_OR_EQUAL,
BELOW,
BELOW_OR_EQUAL
}
public int instrWord(MajorOpcode op, int minor, int a, int b) {
int result = 0;
result |= minor << 0;
result |= op.value << 4;
result |= a << 8;
result |= b << 12;
return result;
}
public void genInstrWord(MajorOpcode op, int minor, int a, int b) {
genInstrWord(instrWord(op, minor, a, b));
}
public void genInstrWord(MajorOpcode op, int minor, int a) {
genInstrWord(op,minor,a,0);
}
public void genInstrWord(MajorOpcode op, int minor) {
genInstrWord(op,minor,0,0);
}
public void genInstrWord(MajorOpcode op) {
genInstrWord(op,0,0,0);
}
private int prevLineNumber = 0;
private int prevCharNumber = 0;
public void topupDebugInfo() {
if (getNearestLine() != prevLineNumber || getNearestCharacter() != prevCharNumber) {
prevLineNumber = getNearestLine();
prevCharNumber = getNearestCharacter();
locations.append(new Location(currentLocation(), prevLineNumber, prevCharNumber));
}
}
public void genInstrWord(int instr) {
topupDebugInfo();
writeRaw32(instr, false);
}
public void genALU(ALUOp op, TypeSignature type) {
genALU(op, stackType(type));
}
public void genALU(ALUOp op, StackType type) {
vpop(type);
vpop(type);
genInstrWord(MajorOpcode.ALU, op.value, type.value);
vpush(type);
}
public void genComp(CompOp op, StackType type) {
vpop(type);
vpop(type);
genInstrWord(MajorOpcode.COMP, op.value, type.value);
vpush(StackType.BIT);
}
public void genComp(CompOp op, TypeSignature type) {
genComp(op, stackType(type));
}
public void genDrop(StackType type) {
vpop(type);
genInstrWord(MajorOpcode.MISC, MiscOp.DROP.value, type.value, 1);
}
public void genDrop(TypeSignature type) {
genDrop(stackType(type));
}
public void genDup(StackType type) {
vpop(type);
genInstrWord(MajorOpcode.MISC, MiscOp.DUP.value, type.value, 2);
vpush(type);
vpush(type);
}
public void genSwap(StackType currentTopType, StackType nextTopType) {
vpop(currentTopType);
vpop(nextTopType);
genInstrWord(MajorOpcode.MISC, MiscOp.SWAP.value, currentTopType.value, nextTopType.value);
vpush(currentTopType);
vpush(nextTopType);
}
public void genSwap(TypeSignature currentTopType, TypeSignature nextTopType) {
genSwap(stackType(currentTopType), stackType(nextTopType));
}
public void genDup(TypeSignature type) {
genDup(stackType(type));
}
public void genConst(BytecodeHeap.Record value) {
if ((value.getRecordIndex() & 0xFFF) == value.getRecordIndex()) {
genInstrWord(MajorOpcode.TINYCONST, (value.getRecordIndex() >> 8) & 0xF, (value.getRecordIndex() >> 0) & 0xF, (value.getRecordIndex() >> 4) & 0xF);
}/* else if ((value.getRecordIndex() & 0xFFFFFF) == value.getRecordIndex()) {
genInstrWord(MajorOpcode.MISC, MiscOp.CONST24.value, (value.getRecordIndex() >> 16) & 0xF, (value.getRecordIndex() >> 20) & 0xF);
writeRaw32(value.getRecordIndex() & 0xFFFF, false);
} else if (value.getRecordIndex() >= 65536) {
genInstrWord(MajorOpcode.MISC, MiscOp.CONST_SPLIT32.value);
writeRaw32(value.getRecordIndex() & 0xFFFF, false);
writeRaw32((value.getRecordIndex() >> 16) & 0xFFFF, false);
}*/ else {
genInstrWord(MajorOpcode.MISC, MiscOp.CONST.value);
writeRef(value);
}
vpush(value.getStandardClass());
}
public void genThis() {
genInstrWord(MajorOpcode.TYPE, TypeOp.THIS.value);
vpush(owner.getTypeSignature());
}
public void genOuterThis() {
vpop(StackType.OBJECT);
genInstrWord(MajorOpcode.TYPE, TypeOp.OUTERTHIS.value, 1);
vpush(StackType.OBJECT);
}
public void genNull() {
genConst(target.heap.getNull());
}
public void genBoolean(boolean value) {
genConst(value ? target.heap.getTrue() : target.heap.getFalse());
}
public void genJump(JumpOp op, Label target) {
if (op == JumpOp.IFFALSE || op == JumpOp.IFTRUE) {
vpop(StackType.BIT);
}
genInstrWord(MajorOpcode.JUMP, op.value);
writeRef(target);
}
public void genLoad(FieldSignature field) {
if (!field.isStatic) {
vpop(StackType.OBJECT);
}
genInstrWord(MajorOpcode.MEM, field.isStatic ? MemOp.LOAD_STATIC_FIELD.value : MemOp.LOAD_INSTANCE_FIELD.value);
writeRef(target.heap.getFieldSignature(field));
vpush(field.storageType);
}
public void genStore(FieldSignature field) {
if (!field.isStatic) {
vpop(StackType.OBJECT);
}
vpop(field.storageType);
genInstrWord(MajorOpcode.MEM, field.isStatic ? MemOp.STORE_STATIC_FIELD.value : MemOp.STORE_INSTANCE_FIELD.value);
writeRef(target.heap.getFieldSignature(field));
}
public void genArrayLoad(TypeSignature elementType) {
vpop(StackType.OBJECT);
vpop(StackType.INT32);
genInstrWord(MajorOpcode.MEM, MemOp.LOAD_ARRAY.value, stackType(elementType).value);
vpush(elementType);
}
public void genArrayStore(TypeSignature elementType) {
vpop(elementType);
vpop(StackType.INT32);
vpop(StackType.OBJECT);
genInstrWord(MajorOpcode.MEM, MemOp.STORE_ARRAY.value, stackType(elementType).value);
}
public void genLoadLocalOrParam(TypeSignature typeSignature, int index) {
genInstrWord(MajorOpcode.MEM, index < 0 ? MemOp.LOAD_PARAM.value : MemOp.LOAD_LOCAL.value, stackType(typeSignature).value);
writeRaw32(index < 0 ? -index : index, false);
vpush(typeSignature);
}
public void genStoreLocalOrParam(TypeSignature typeSignature, int index) {
vpop(typeSignature);
genInstrWord(MajorOpcode.MEM, index < 0 ? MemOp.STORE_PARAM.value : MemOp.STORE_LOCAL.value, stackType(typeSignature).value);
writeRaw32(index < 0 ? -index : index, false);
}
public void genArrayLength() {
vpop(StackType.OBJECT);
genInstrWord(MajorOpcode.TYPE, TypeOp.ARRAYLENGTH.value);
vpush(StackType.INT32);
}
public void genDeclareLocal(TypeSignature typeSignature, int index) {
genInstrWord(MajorOpcode.TYPE, TypeOp.DECLARE_LOCAL.value, stackType(typeSignature).value);
writeRaw32(index, false);
writeRef(getTarget().getHeap().getTypeSignature(typeSignature));
}
public void genLock() {
vpop(StackType.OBJECT);
genInstrWord(MajorOpcode.MISC, MiscOp.LOCK.value);
}
public void genUnlock() {
vpop(StackType.OBJECT);
genInstrWord(MajorOpcode.MISC, MiscOp.UNLOCK.value);
}
public void genVoidReturn() {
genInstrWord(MajorOpcode.MISC, MiscOp.RETURN.value, StackType.VOID.value);
}
public void genValueReturn(TypeSignature t) {
vpop(t);
genInstrWord(MajorOpcode.MISC, MiscOp.RETURN.value, stackType(t).value);
}
public void genConvert(TypeSignature expected, TypeSignature result) {
vpop(expected);
BytecodeHeap.ObjectLike from = getTarget().getHeap().getTypeSignature(expected);
BytecodeHeap.ObjectLike to = getTarget().getHeap().getTypeSignature(result);
genInstrWord(MajorOpcode.TYPE, TypeOp.CONVERT.value, stackType(expected).value, stackType(result).value);
writeRef(from);
writeRef(to);
vpush(result);
}
public void genTypeCheck(TypeSignature knownType, TypeSignature check) {
vpop(knownType);
genInstrWord(MajorOpcode.TYPE, TypeOp.TYPECHECK.value, stackType(knownType).value, stackType(check).value);
writeRef(getTarget().getHeap().getTypeSignature(knownType));
writeRef(getTarget().getHeap().getTypeSignature(check));
vpush(StackType.BIT);
}
public void genTypeObject(TypeSignature type) {
genInstrWord(MajorOpcode.TYPE, TypeOp.TYPEOBJECT.value, stackType(type).value);
writeRef(getTarget().getHeap().getTypeSignature(type));
vpush(StackType.OBJECT);
}
public void genThrow() {
vpop(StackType.OBJECT);
genInstrWord(MajorOpcode.MISC, MiscOp.THROW.value, StackType.OBJECT.value);
}
public void genCheckRethrow() {
genInstrWord(MajorOpcode.MISC, MiscOp.CHECKRETHROW.value);
}
public void genNot() {
vpop(StackType.BIT);
genInstrWord(MajorOpcode.MISC, MiscOp.NOT.value, StackType.BIT.value);
vpush(StackType.BIT);
}
public void vpopArgs(TypeSignature[] args) {
for (int i = args.length-1; i > 0; i--) {
vpop(args[i]);
}
}
public void genNewArray(TypeSignature arrayType) {
// TODO: May require some extension to account for local variables used in an inner class
vpop(StackType.INT32);
genInstrWord(MajorOpcode.TYPE, TypeOp.NEW_ARRAY.value, StackType.OBJECT.value);
writeRef(target.heap.getTypeSignature(arrayType));
vpush(arrayType);
}
public void genStrcat(int nstrs) {
// A quick hack in case > 15 need to be concatenated, just generate multiple instructions
while (nstrs > 15) {
genStrcat(15);
nstrs -= 14;
}
for (int i = 0; i < nstrs; i++) {
vpop(StackType.OBJECT);
}
genInstrWord(MajorOpcode.MISC, MiscOp.STRCAT.value, nstrs);
vpush(StackType.OBJECT);
}
public void genNewObject(MethodSignature constructor) {
vpopArgs(constructor.argumentTypes);
genInstrWord(MajorOpcode.CALL, CallOp.CONSTRUCTOR_NEW.value, StackType.OBJECT.value);
writeRef(target.heap.getMethodSignature(constructor));
vpush(constructor.owner);
}
public void genNewInner(MethodSignature constructor, TypeSignature[] upvalues) {
vpopArgs(constructor.argumentTypes);
vpopArgs(upvalues);
vpop(StackType.OBJECT); // Assume the relevant "this" has been pushed appropriately
genInstrWord(MajorOpcode.CALL, CallOp.CONSTRUCTOR_INNER.value, StackType.OBJECT.value);
writeRef(target.heap.getMethodSignature(constructor));
vpush(constructor.owner);
}
public void genNestedConstructorCall(MethodSignature constructor) {
// Conceptually, this instruction pushes, and then pops, the "this" value implicitly
vpush(StackType.OBJECT);
vpop(StackType.OBJECT);
// TODO: May require some extension to account for local variables used in an inner class
vpopArgs(constructor.argumentTypes);
genInstrWord(MajorOpcode.CALL, CallOp.CONSTRUCTOR_NESTED.value, StackType.OBJECT.value);
writeRef(target.heap.getMethodSignature(constructor));
vpush(StackType.OBJECT);
// Autogenerate a drop after the call
genDrop(StackType.OBJECT);
}
public void genCall(MethodSignature method) {
genCall(method, false);
}
public void genCall(MethodSignature method, boolean isSuperCall) {
if (!method.isStatic()) {
vpop(StackType.OBJECT);
}
vpopArgs(method.argumentTypes);
CallOp type = null;
if (method.isStatic() && method.returnType.mappableEquals(TypeSignature.VOID)) {
type = CallOp.STATIC_PROCEDURE;
} else if (!method.isStatic() && method.returnType.mappableEquals(TypeSignature.VOID)) {
if (isSuperCall) {
type = method.kind == MethodSignature.Kind.INTERFACE_METHOD ? CallOp.SUPER_INTERFACE_PROCEDURE : CallOp.SUPER_INSTANCE_PROCEDURE;
} else {
type = method.kind == MethodSignature.Kind.INTERFACE_METHOD ? CallOp.INTERFACE_PROCEDURE : CallOp.INSTANCE_PROCEDURE;
}
} else if (method.isStatic() && !method.returnType.mappableEquals(TypeSignature.VOID)) {
type = CallOp.STATIC_FUNCTION;
} else {
if (isSuperCall) {
type = method.kind == MethodSignature.Kind.INTERFACE_METHOD ? CallOp.SUPER_INTERFACE_FUNCTION : CallOp.SUPER_INSTANCE_FUNCTION;
} else {
type = method.kind == MethodSignature.Kind.INTERFACE_METHOD ? CallOp.INTERFACE_FUNCTION : CallOp.INSTANCE_FUNCTION;
}
}
genInstrWord(MajorOpcode.CALL, type.value, stackType(method.returnType).value);
writeRef(target.heap.getMethodSignature(method));
vpush(method.returnType);
}
/**
* This can be used for reporting some kind of error. For purely synthetic code, this will throw
* an error, whereas if a source is available the error will be reported there.
*/
public void genError(String message) {
if (getNearestSource(false) == null) {
throw new Error("Failed to produce synthetic code: " + message);
} else {
getNearestSource(false).annotate(ErrorType.INTERNAL_ERROR, message);
}
}
/**
* Added for convenience when generating constructors with an implicit super-constructor.
*/
public void genDefaultSuperConstructorCall() {
if (((UserTypeModel)owner).getBaseClass() == null) {
return; // Skip super-constructor call if this is the root class
}
genNestedConstructorCall(((UserTypeModel)owner).getBaseClass().getDefaultInstanceConstructor().getMethodSignature());
}
/**
* Called at the end of most methods to add a default return or report error.
*/
public void genEnd() {
/* This should cause the default behaviour if the return type is void, or
* trigger an error if reached in a non-void method.
*/
genVoidReturn();
linkAllRefs();
BytecodeHeap.ArrayInt32 lbllist = getTarget().getHeap().newLabels(0);
method.setElement(BytecodeHeap.MethodFields.EXCEPTIONS.value, lbllist);
for (int i = 0; i < labels.count(); i++) {
labels.get(i).genLabelData(lbllist, false);
}
BytecodeHeap.ArrayInt16 dbglist = getTarget().getHeap().newDebug(0);
method.setElement(BytecodeHeap.MethodFields.DEBUG.value, dbglist);
for (int i = 0; i < locations.count(); i++) {
locations.get(i).genLocationData(dbglist, false);
}
method.setElement(BytecodeHeap.MethodFields.MAXSTACK.value, getTarget().getHeap().getConstInt32(""+maxStackSize));
}
public BytecodeTarget getTarget() {
return target;
}
public TypeModel getOwner() {
return owner;
}
}