slcom/slangc/api/BytecodeTarget.sauce

340 lines
13 KiB
Plaintext

package slangc.api;
import slang.data.List;
import slang.data.Map;
import slangc.api.BytecodeHeap;
import slangc.bytecode.MethodSignature;
import slangc.bytecode.TypeSignature;
import slangc.model.FieldModel;
import slangc.model.Flags;
import slangc.model.MethodModel;
import slangc.model.ParameterModel;
import slangc.model.UserTypeModel;
import slangc.model.statements.BlockStatement;
import slangc.model.BuiltinTypeModel;
public class BytecodeTarget extends CompilerTarget {
final BytecodeHeap heap;
final BytecodeOutput output;
private final List<ReprocessType> types = new List<ReprocessType>();
private final Map<TypeSignature,BytecodeInstructionWriter.StackType> cachedStackTypes = new Map<TypeSignature,BytecodeInstructionWriter.StackType>();
public BytecodeInstructionWriter.StackType stackType(TypeSignature type) {
if (!cachedStackTypes.hasKey(type)) {
BytecodeInstructionWriter.StackType t = calculateStackType(type);
cachedStackTypes.set(type, t);
return t;
}
return cachedStackTypes.get(type);
}
public BytecodeInstructionWriter.StackType calculateStackType(TypeSignature type) {
if (type.mappableEquals(TypeSignature.VOID)) {
return BytecodeInstructionWriter.StackType.VOID;
} /*else if (type.mappableEquals(getSystem().getDefaultBooleanType().getTypeSignature())) {
return BytecodeInstructionWriter.StackType.BIT;
} else if (type.mappableEquals(getSystem().getDefaultFloat32Type().getTypeSignature())) {
return BytecodeInstructionWriter.StackType.FLOAT32;
} else if (type.mappableEquals(getSystem().getDefaultFloat64Type().getTypeSignature())) {
return BytecodeInstructionWriter.StackType.FLOAT64;
} else if (type.mappableEquals(getSystem().getDefaultInt64Type().getTypeSignature())) {
return BytecodeInstructionWriter.StackType.INT64;
} else if (getSystem().matchesTypeOption(TypeOption.Kind.DUCK, type)) {
return BytecodeInstructionWriter.StackType.DUCK;
}*/ else if (getSystem().getType(type) instanceof BuiltinTypeModel) {
for (int i = 0; i < BytecodeInstructionWriter.StackType.lookupCount(BytecodeInstructionWriter.StackType.class); i++) {
if (getSystem().matchesTypeOption((TypeOption.Kind)TypeOption.Kind.lookup(TypeOption.Kind.class, i), type)) {
return (BytecodeInstructionWriter.StackType)BytecodeInstructionWriter.StackType.lookup(BytecodeInstructionWriter.StackType.class, i);
}
}
return BytecodeInstructionWriter.StackType.INT32;
} else {
for (int i = 0; i < BytecodeInstructionWriter.StackType.lookupCount(BytecodeInstructionWriter.StackType.class); i++) {
if (getSystem().matchesTypeOption((TypeOption.Kind)TypeOption.Kind.lookup(TypeOption.Kind.class, i), type)) {
return (BytecodeInstructionWriter.StackType)BytecodeInstructionWriter.StackType.lookup(BytecodeInstructionWriter.StackType.class, i);
}
}
return BytecodeInstructionWriter.StackType.OBJECT;
}
}
private static class ReprocessType {
UserTypeModel type;
boolean addToMainList;
ReprocessType(UserTypeModel type, boolean addToMainList) {
this.type = type;
this.addToMainList = addToMainList;
}
}
public BytecodeTarget(BytecodeOutput output, BytecodeHeap heap) {
this.output = output;
this.heap = heap;
}
public BytecodeTarget(BytecodeOutput output) {
this(output, new BytecodeHeap(1000000000, true));
}
public void generateFieldInitialisers(UserTypeModel t, BytecodeInstructionWriter w, boolean isStaticInit) {
for (int i = 0; i < t.countFieldMembers(); i++) {
FieldModel f = t.getFieldMember(i);
if (isStaticInit && f.isEnumField()) {
w.genNewObject(t.getDefaultInstanceConstructor().getMethodSignature());
w.genStore(f.getFieldSignature());
} else if (f.hasInitialiser() && f.isStatic() == isStaticInit) {
TypeSignature storing = f.getInitialisationExpression().generate(w);
if (!storing.mappableEquals(f.getStorageType().getTypeSignature())) {
w.genConvert(storing, f.getStorageType().getTypeSignature());
storing = f.getStorageType().getTypeSignature();
}
if (!f.isStatic()) {
w.genThis();
}
w.genStore(f.getFieldSignature());
}
}
}
private void visitField(BytecodeHeap.ObjectLike typ, FieldModel m) {
BytecodeHeap.ObjectLike member = heap.newField(typ, m.getFlags(), m.getFieldSignature());
for (int i = 0; i < m.getAttributes().countTranslations(); i++) {
heap.addMemberTranslation(member, m.getAttributes().getTranslation(i).language, m.getAttributes().getTranslation(i).name);
}
}
private void visitMethod(BytecodeHeap.ObjectLike typ, MethodModel m) {
BytecodeHeap.ObjectLike member = heap.newMethod(typ, m.getFlags(), m.getMethodSignature(), m.countLocals());
for (int i = 0; i < m.getAttributes().countTranslations(); i++) {
heap.addMemberTranslation(member, m.getAttributes().getTranslation(i).language, m.getAttributes().getTranslation(i).name);
}
if (m.hasBody() || m.isConstructor()) {
BytecodeInstructionWriter w = new BytecodeInstructionWriter(this, m.getOwner(), member);
w.pushSource(m.getSource());
boolean initAfterFirstStatement = false;
if (m.isStaticInitialisation()) {
generateFieldInitialisers((UserTypeModel)m.getOwner(), w, true);
} else if (m.isConstructor()) {
if (m.checkExplicitBaseConstructorCall(true)) {
// This will have "approved" the constructor call location,
// But we need to check if it was actually a super(...) call
// (and not a call to another this(...) constructor)
// before we go around re-initialising any already-initialised fields!
if (m.checkExplicitBaseConstructorCall(false)) {
initAfterFirstStatement = true;
}
} else {
if (m.hasBody()) {
w.genDefaultSuperConstructorCall();
} else {
// This handles synthetic constructors
// These naturally pass all arguments to the super-constructor
for (int i = 0; i < m.countParameters(); i++) {
ParameterModel p = m.getParameter(i);
w.genLoadLocalOrParam(p.getStorageType().getTypeSignature(), p.getIndex());
}
w.genNestedConstructorCall(m.getPrototype().getMethodSignature());
}
generateFieldInitialisers((UserTypeModel)m.getOwner(), w, false);
}
}
if (m.countExceptions() > 0) {
BytecodeHeap.ObjectLike o = getHeap().newObjectLike(BytecodeHeap.StandardClass.SIMPLEARRAY, m.countExceptions());
for (int i = 0; i < m.countExceptions(); i++) {
o.setElement(i, getHeap().getTypeSignature(m.getException(i).getTypeSignature()));
}
member.setElement(BytecodeHeap.MethodFields.THROWS.value, o);
}
if (m.hasBody()) {
/* Manually loop through statements to ensure fields are initialised if needed. */
if (m.getBody() instanceof BlockStatement) {
BlockStatement block = (BlockStatement) m.getBody();
w.pushSource(block.getSource());
if (block.countInnerStatements() == 0 && initAfterFirstStatement) {
generateFieldInitialisers((UserTypeModel)m.getOwner(), w, false);
}
for (int i = 0; i < block.countInnerStatements(); i++) {
block.getInnerStatement(i).generate(w);
if (i == 0 && initAfterFirstStatement) {
generateFieldInitialisers((UserTypeModel)m.getOwner(), w, false);
}
}
w.popSource();
} else {
m.getBody().generate(w);
if (initAfterFirstStatement) {
generateFieldInitialisers((UserTypeModel)m.getOwner(), w, false);
}
}
}
w.genEnd();
w.popSource(m.getSource());
}
}
void generateImplicitStaticInit(UserTypeModel m, BytecodeHeap.ObjectLike typ) {
int flags = Flags.MASK_METHOD | Flags.MASK_CONSTRUCTOR | Flags.MASK_STATIC | Flags.MASK_SYNTHETIC;
BytecodeHeap.ObjectLike member = heap.newMethod(typ, flags, new MethodSignature(m.getTypeSignature(), MethodSignature.Kind.STATIC_INIT, TypeSignature.VOID, "static-init", new TypeSignature[0]), 0);
BytecodeInstructionWriter w = new BytecodeInstructionWriter(this, m, member);
w.pushSource(m.getParsed());
generateFieldInitialisers(m, w, true);
w.genEnd();
w.popSource(m.getParsed());
}
@Override
public void visitProvidesOrDepends(ProvidesOrDepends x) {
if (x.provides) {
heap.newProvides(x.name, x.version);
} else {
heap.newDepends(x.name, x.version, null, null);
}
}
@Override
public void visitMeta(boolean important, String key, String value) {
heap.newMetadata(important, key, value);
}
@Override
public void visitTypeOption(TypeOption o) {
heap.registerRuntimeType(o.kind.value, o.kind.value, o.getTypeSignature(), o.formatopt, o.isBuiltin, o.isNumber, o.isFloat, o.isSigned, o.nbits);
}
@Override
public void visitDataFile(DataFile dataFile) {
heap.newFile(dataFile.packagename, dataFile.innername, dataFile.data, dataFile.typeinfo, dataFile.debugname);
}
@Override
public void visitType(UserTypeModel m, boolean addToMainList) {
types.append(new ReprocessType(m, addToMainList));
dryRun(m, addToMainList);
}
private boolean firstDryRun = true;
private void dryRun(UserTypeModel m, boolean addToMainList) {
if (firstDryRun) {
for (int i = 0; i <= 1024; i++) {
//heap.getConstInt32(""+i);
}
firstDryRun = false;
}
heap.getTypeSignature(m.getTypeSignature());
for (int i = 0; i < m.countFieldMembers(); i++) {
FieldModel f = m.getFieldMember(i);
heap.getFieldSignature(f.getFieldSignature());
}
for (int i = 0; i < m.countMethodMembers(); i++) {
MethodModel mt = m.getMethodMember(i);
if (!mt.isStaticInitialisation()) {
//Log.line("For " + mt.toString() + "[" + mt.getMethodSignature().toString() + "] got " + heap.getMethodSignature(mt.getMethodSignature()).debugString());
}
}
}
private void processType(UserTypeModel m, boolean addToMainList) {
BytecodeHeap.ObjectLike typ = heap.newType(m.getFlags(), m.getTypeSignature());
if (m.getBaseClass() != null) {
typ.setElement(2, heap.getTypeSignature(m.getBaseClass().getTypeSignature()));
}
if (m.countInterfaces() > 0) {
BytecodeHeap.ObjectLike ifcs = heap.newObjectLike(BytecodeHeap.StandardClass.SIMPLEARRAY, m.countInterfaces());
typ.setElement(3, ifcs);
for (int i = 0; i < m.countInterfaces(); i++) {
ifcs.setElement(i, heap.getTypeSignature(m.getInterface(i).getTypeSignature()));
}
}
if (m.getSource() != null) {
typ.setElement(BytecodeHeap.TypeFields.FILENAME.value, heap.getConstString(m.getSource().getFilename()));
}
for (int i = 0; i < m.countFieldMembers(); i++) {
FieldModel f = m.getFieldMember(i);
visitField(typ, f);
}
boolean explicitStaticInit = false;
for (int i = 0; i < m.countMethodMembers(); i++) {
MethodModel mt = m.getMethodMember(i);
if (mt.isStaticInitialisation()) {
explicitStaticInit = true;
}
visitMethod(typ, mt);
}
if (!explicitStaticInit) {
generateImplicitStaticInit(m, typ);
}
if (addToMainList) {
getHeap().getEntrypointsArray().appendElement(typ);
}
}
@Override
public void finish() {
for (int i = 0; i < types.count(); i++) {
Log.line("Reprocessing type #" + i);
ReprocessType t = types.get(i);
Log.line("Reprocessing type " + t.type.toString());
processType(t.type, t.addToMainList);
}
Log.line("FINISHING: " + quickReport());
Log.line("in BytecodeTaget...");
if (output != null) {
heap.writeAll(output, "#!/usr/bin/env testvm", 3, 256, 1, 1);
output.endOfFile();
} else {
Log.line("NO OUTPUT??");
}
}
public String strbytes(int size) {
int orig = size;
String result = "";
if (size > 1024*1024) {
result += (size/(1024*1024)) + " MB";
size %= (1024*1024);
}
if (size > 1024) {
if (!result.equals("")) {
result += " ";
}
result += (size/1024) + " KB";
size %= 1024;
}
if (size != 0 || result.equals("")) {
if (!result.equals("")) {
result += " ";
}
result += size + " bytes";
size = 0;
}
result += " (" + /*String.format("%.4f",*/ (orig / (1024.0*1024.0)) + "MB)";
return result;
}
@Override
public String quickReport() {
return "Object table " + strbytes(heap.objectTableSize(3)) + " (" + (heap.highestUsedRecordIndex() + 1) + " entries), index size " + strbytes(heap.objectTableIndexSize(3, 256)) + ", data section " + strbytes(heap.dataSize(1)) + ": total file size " + strbytes(heap.fileSize(3, 256, 1, 1)) /*heap.objectTableSize(3) + heap.objectTableIndexSize(3, 256) + heap.dataSize(1))*/;
}
public BytecodeHeap getHeap() {
return heap;
}
}