package nebula.vm;
import static nebula.vm.BytecodeDefinition.INSTR_CALL;
import static nebula.vm.BytecodeDefinition.INSTR_FLOAD;
import static nebula.vm.BytecodeDefinition.INSTR_FSTORE;
import static nebula.vm.BytecodeDefinition.INSTR_IADD;
import static nebula.vm.BytecodeDefinition.INSTR_ICONST;
import static nebula.vm.BytecodeDefinition.INSTR_IMUL;
import static nebula.vm.BytecodeDefinition.INSTR_ISUB;
import static nebula.vm.BytecodeDefinition.INSTR_MOVE;
import static nebula.vm.BytecodeDefinition.INSTR_RET;
import static nebula.vm.BytecodeDefinition.INSTR_STRUCT;
import static nebula.vm.BytecodeDefinition.MASK_XX;
import static nebula.vm.BytecodeDefinition.MASK_X_;
import static nebula.vm.BytecodeDefinition.OFFSET_A_;
import static nebula.vm.BytecodeDefinition.OFFSET_BX;
import static nebula.vm.BytecodeDefinition.OFFSET_B_;
import static nebula.vm.BytecodeDefinition.OFFSET_C_;
import static nebula.vm.BytecodeDefinition.OFFSET_OP;
import java.util.ArrayList;
import java.util.List;
import org.antlr.runtime.TokenStream;
public class SourceCompiler extends NebulaRegisterParser {
public static final int INITIAL_CODE_SIZE = 1024;
public static final short UNKNOWN = 0;
// protected Map<String, Integer> instructionOpcodeMapping = new
// HashMap<String, Integer>();
// protected Map<String, LabelSymbol> labels = // label scope
// new HashMap<String, LabelSymbol>();
protected List<Object> poolLocalK = new ArrayList<>();
protected List<MethodSymbol> methods = new ArrayList<>();
protected List<FieldSymbol> fields = new ArrayList<>();
protected int ip = 0; // Instruction address pointer; used to fill code
protected int[] codeBuffer = new int[INITIAL_CODE_SIZE]; // code memory
public SourceCompiler(TokenStream input) {
super(input);
}
// ************** START:members **************
@Override
protected ClassSymbol resolveType(String name) {
ClassSymbol clz = new ClassSymbol(name);
short index = indexOfPool(clz);
clz = (ClassSymbol) poolLocalK.get(index);
return clz;
};
@Override
protected ClassSymbol enterClass(String name, Type superType) {
ClassSymbol v = new ClassSymbol(name);
this.indexOfPool(v);
return v;/* TODO add super class support */
};
@Override
protected ClassSymbol exitClass(ClassSymbol clz) {
clz.poolLocalK = this.poolLocalK.toArray();
clz.fields = this.fields.toArray(new FieldSymbol[0]);
clz.methods = this.methods.toArray(new MethodSymbol[0]);
return clz;
};
@Override
protected FieldSymbol defineField(ClassSymbol clz, String name, Type type) {
FieldSymbol f = new FieldSymbol(clz, name, type);
this.indexOfPool(f);
this.fields.add(f);
return f;
};
@Override
protected MethodSymbol enterMethod(ClassSymbol clz, String name, Type returnType, List<Var> params) {
MethodSymbol m = new MethodSymbol(clz, name, returnType);
super.maxLocals = 0;
initLocals();
pushLocal("this", clz);
for (Var v : params) {
pushLocal(v.name, v.type);
}
m.nargs = params.size();
this.methods.add(m);
poolLocalK.set(indexOfPool(m), m);
ip = 0;
return m;
};
@Override
protected MethodSymbol exitMethod(MethodSymbol method) {
if (ip == 0 || codeBuffer[ip - 1] >>> OFFSET_OP != INSTR_RET) {
gen(INSTR_RET, UNKNOWN);
}
int[] code = new int[ip];
System.arraycopy(codeBuffer, 0, code, 0, ip);
method.code = code;
method.nlocals = super.maxLocals - method.nargs;
return method;
};
@Override
protected Var opIAdd(Var a, Var b) {
if (!a.applied) resolveTemp(a);
if (!b.applied) resolveTemp(b);
TempVar v = popTmp(a.type);
v.addReference(ip, 1);
gen(INSTR_IADD, UNKNOWN, a.reg, b.reg);
return v;
};
@Override
protected Var opISub(Var a, Var b) {
if (!a.applied) resolveTemp(a);
if (!b.applied) resolveTemp(b);
TempVar v = popTmp(a.type);
v.addReference(ip, 1);
gen(INSTR_ISUB, UNKNOWN, a.reg, b.reg);
return v;
};
@Override
protected Var opIMul(Var a, Var b) {
if (!a.applied) resolveTemp(a);
if (!b.applied) resolveTemp(b);
TempVar v = popTmp(a.type);
v.addReference(ip, 1);
gen(INSTR_IMUL, UNKNOWN, a.reg, b.reg);
return v;
};
@Override
protected Var opFLoad(Var obj, FieldSymbol field) {
if (!obj.applied) resolveTemp(obj);
TempVar v = popTmp(BuiltInTypeSymbol.FLEX);
short index = indexOfPool(field);
v.addReference(ip, 1);
gen(INSTR_FLOAD, UNKNOWN, obj.reg, index);
return v;
};
@Override
protected Var opFStore(Var obj, FieldSymbol field, Var v) {
if (!obj.applied) resolveTemp(obj);
if (!v.applied) resolveTemp(v);
short index = indexOfPool(field);
gen(INSTR_FSTORE, obj.reg, index, v.reg);
return v;
};
@Override
protected Var opInvoke(Var obj, MethodSymbol method, List<Var> params) {
if (!obj.applied) resolveTemp(obj);
for (Var vp : params) {
if (!vp.applied) resolveTemp(vp);
}
TempVar v = popTmp(BuiltInTypeSymbol.FLEX);
;
short index = indexOfPool(method);
if (params.size() > 0) {
TempVar ov = (TempVar) params.get(0);
assert v.reg == ov.reg;
v.applied = true;
} else {
v.addReference(ip, 3);
}
gen(INSTR_CALL, obj.reg, index, v.reg);
return v;
};
@Override
protected Var opMove(Var to, Var from) {
if (!from.applied) resolveTemp(from);
if (to.applied) {
gen(INSTR_MOVE, to.reg, from.reg);
} else {
((TempVar) to).addReference(ip, 1);
gen(INSTR_MOVE, to.reg, from.reg);
}
return to;
}
@Override
protected Var opNew(ClassSymbol clz) {
TempVar v = popTmp(clz);
v.addReference(ip, 1);
gen(INSTR_STRUCT, UNKNOWN, indexOfPool(clz));
return v;
}
@Override
protected Var opILoad(String text) {
TempVar v = popTmp(BuiltInTypeSymbol.INT);
v.addReference(ip, 1);
gen(INSTR_ICONST, UNKNOWN, Integer.parseInt(text));
return v;
};
@Override
protected Var opReturn(Var v) {
if (!v.applied) resolveTemp(v);
gen(INSTR_RET, v.reg);
return v;
}
private short indexOfPool(Object o) {
if (poolLocalK.contains(o)) return (short) poolLocalK.indexOf(o);
poolLocalK.add(o);
return (short) (poolLocalK.size() - 1);
}
// ************** END :members **************
// ************** START: Deal local **************
@Override
protected void resolveTemp(Var v) {
assert !v.applied;
((TempVar) v).resolveForwardReferences(codeBuffer);
}
@Override
protected void resolveTemp(Var v, short reg) {
assert !v.applied || v.reg == reg;
if (!v.applied) ((TempVar) v).resolveForwardReferences(reg, codeBuffer);
}
private void gen(short op, short a) {
gen(op, a, (short) 0, (short) 0);
}
private void gen(short op, short a, short b) {
gen(op, a, b, (short) 0);
}
// @formatter:off
protected void gen(short op, short a, short b, short c) {
codeBuffer[ip++] = (op & 0xFF) << OFFSET_OP
| ((a & MASK_X_) << OFFSET_A_)
| ((b & MASK_X_) << OFFSET_B_)
| ((c & MASK_X_) << OFFSET_C_);
}
protected void gen(short op, short a, int bx) {
codeBuffer[ip++] = (op & 0xFF) << OFFSET_OP
| ((a & MASK_X_) << OFFSET_A_)
| ((bx & MASK_XX) << OFFSET_BX);
}
// @formatter:on
// ************** END : Deal local **************
}