|
|
|
@ -92,7 +92,6 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
stmt.dispatch(stmtAnalyzer);
|
|
|
|
|
}
|
|
|
|
|
stmtAnalyzer.emitSizeLabel();
|
|
|
|
|
|
|
|
|
|
backend.emitLI(A0, EXIT_ECALL, "Code for ecall: exit");
|
|
|
|
|
backend.emitEcall(null);
|
|
|
|
|
}
|
|
|
|
@ -110,8 +109,6 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
{
|
|
|
|
|
backend.emitGlobalLabel(funcInfo.getCodeLabel());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- Prologue ---
|
|
|
|
|
// space for return address = 1
|
|
|
|
|
// space for control link = 1
|
|
|
|
@ -126,14 +123,14 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
//backend.emitSW(FP, SP, requiredStackSpace-12, "static link");
|
|
|
|
|
backend.emitADDI(FP, SP, sizelabel, "New fp is at old SP.");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(funcInfo);
|
|
|
|
|
int emptySlotNum = 3;
|
|
|
|
|
for (StackVarInfo var : funcInfo.getLocals()) {
|
|
|
|
|
for (StackVarInfo var : funcInfo.getLocals())
|
|
|
|
|
{
|
|
|
|
|
Literal varLiteral = var.getInitialValue();
|
|
|
|
|
varLiteral.dispatch(stmtAnalyzer);
|
|
|
|
|
Register reg = varLiteral.dispatch(stmtAnalyzer);
|
|
|
|
|
// All Literals should save locations for the values in A0
|
|
|
|
|
backend.emitSW(A0, SP, sizelabel+String.format("-%d",emptySlotNum*wordSize), "Push local variable " + var.getVarName() + " onto stack");
|
|
|
|
|
backend.emitSW(reg, SP, sizelabel+String.format("-%d",emptySlotNum*wordSize), "Push local variable " + var.getVarName() + " onto stack");
|
|
|
|
|
emptySlotNum++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -143,13 +140,13 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
// statements use fp to load the variables
|
|
|
|
|
// example: 0(fp) is the last variable (z) while 8(fp) is the first variable (x)
|
|
|
|
|
// for function with 3 params f(x, y, z)
|
|
|
|
|
for (Stmt stmt : funcInfo.getStatements()) {
|
|
|
|
|
for (Stmt stmt : funcInfo.getStatements())
|
|
|
|
|
{
|
|
|
|
|
stmt.dispatch(stmtAnalyzer);
|
|
|
|
|
}
|
|
|
|
|
stmtAnalyzer.emitSizeLabel();
|
|
|
|
|
backend.emitJ(stmtAnalyzer.epilogue, "Jump to function epilogue");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- Epilogue ---
|
|
|
|
|
backend.emitLocalLabel(stmtAnalyzer.epilogue, "Epilogue");
|
|
|
|
|
backend.emitLW(RA, FP, -4, "Get return address");
|
|
|
|
@ -159,7 +156,8 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** An analyzer that encapsulates code generation for statements. */
|
|
|
|
|
private class StmtAnalyzer extends AbstractNodeAnalyzer<Register> {
|
|
|
|
|
private class StmtAnalyzer extends AbstractNodeAnalyzer<Register>
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The symbol table has all the info you need to determine what a given
|
|
|
|
|
* identifier 'x' in the current scope is. You can use it as follows: SymbolInfo
|
|
|
|
@ -199,8 +197,7 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
/** Label of code that exits from block. */
|
|
|
|
|
protected Stack<Label> elseBlock = new Stack<Label>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Label which stores total size of function on stack */
|
|
|
|
|
private final String size_label;
|
|
|
|
|
/** Variable to store offset from frame pointer to identify next
|
|
|
|
|
* empty space on stack frame to store variable*/
|
|
|
|
@ -210,7 +207,8 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
private boolean l_value = false;
|
|
|
|
|
private final Register[] registerPool = {T2,T3, T4, T5, T6, A2, A3, A4, A5, A6, A7};
|
|
|
|
|
private final boolean[] registerAvilMap = {true, true, true, true, true, true, true, true, true, true, true};
|
|
|
|
|
private int getRegister(){ //return a handle of a vacant register
|
|
|
|
|
private int getRegister()
|
|
|
|
|
{ //return a handle of a vacant register
|
|
|
|
|
for(int i = 0; i < 11; ++i)
|
|
|
|
|
if(registerAvilMap[i])
|
|
|
|
|
{
|
|
|
|
@ -222,13 +220,16 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
System.out.println("Insufficient Registers!!!");
|
|
|
|
|
registerAvilMap[i] = true; //freeall;
|
|
|
|
|
}
|
|
|
|
|
registerAvilMap[0]=false;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
private void freeRegister(int handle){ //handle used to free the register
|
|
|
|
|
private void freeRegister(int handle)
|
|
|
|
|
{ //handle used to free the register
|
|
|
|
|
registerAvilMap[handle] = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int getParamLocationOffset(int index, int paramSize) {
|
|
|
|
|
private int getParamLocationOffset(int index, int paramSize)
|
|
|
|
|
{
|
|
|
|
|
return (paramSize - index - 1) * wordSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -236,7 +237,8 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
return - (index - paramSize + 1) * wordSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int getStaticLinkOffset(int paramSize) {
|
|
|
|
|
private int getStaticLinkOffset(int paramSize)
|
|
|
|
|
{
|
|
|
|
|
return paramSize * wordSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -244,39 +246,44 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
* An analyzer for the function described by FUNCINFO0, which is null for the
|
|
|
|
|
* top level.
|
|
|
|
|
*/
|
|
|
|
|
StmtAnalyzer(FuncInfo funcInfo0) {
|
|
|
|
|
StmtAnalyzer(FuncInfo funcInfo0)
|
|
|
|
|
{
|
|
|
|
|
funcInfo = funcInfo0;
|
|
|
|
|
if (funcInfo == null) {
|
|
|
|
|
if (funcInfo == null)
|
|
|
|
|
{
|
|
|
|
|
sym = globalSymbols;
|
|
|
|
|
sp_off = max_sp = 2;
|
|
|
|
|
size_label = "@..main.size";
|
|
|
|
|
} else {
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sym = funcInfo.getSymbolTable();
|
|
|
|
|
sp_off = max_sp = funcInfo0.getLocals().size() + 2 + 1;
|
|
|
|
|
size_label = "@"+funcInfo0.getFuncName()+".size";
|
|
|
|
|
}
|
|
|
|
|
epilogue = generateLocalLabel();
|
|
|
|
|
}
|
|
|
|
|
private void incSp(int i){
|
|
|
|
|
private void incSp(int i)
|
|
|
|
|
{
|
|
|
|
|
sp_off+=i;
|
|
|
|
|
max_sp = max_sp >= sp_off?max_sp:sp_off;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void emitSizeLabel(){
|
|
|
|
|
public void emitSizeLabel()
|
|
|
|
|
{
|
|
|
|
|
backend.defineSym(size_label, max_sp*wordSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// *********** functions start ***********
|
|
|
|
|
|
|
|
|
|
public Register analyze(CallExpr node) {
|
|
|
|
|
System.out.println("Inside CallExpr: " + node.function.name);
|
|
|
|
|
//ackend.emitLW(T6, FP, 0, "Inside CallExpr: " + node.function.name);
|
|
|
|
|
|
|
|
|
|
SymbolInfo Ty = sym.get(node.function.name);
|
|
|
|
|
if(Ty instanceof ClassInfo){
|
|
|
|
|
public Register analyze(CallExpr node)
|
|
|
|
|
{
|
|
|
|
|
SymbolInfo ty = sym.get(node.function.name);
|
|
|
|
|
if(ty instanceof ClassInfo)
|
|
|
|
|
{
|
|
|
|
|
//object create
|
|
|
|
|
ClassInfo cls = (ClassInfo) Ty;
|
|
|
|
|
ClassInfo cls = (ClassInfo) ty;
|
|
|
|
|
/**
|
|
|
|
|
la a0, $DoublingVector$prototype # Load pointer to prototype of: DoublingVector
|
|
|
|
|
jal alloc # Allocate new object in A0
|
|
|
|
@ -289,8 +296,7 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
addi sp, fp, -@..main.size # Set SP to stack frame top.
|
|
|
|
|
lw a0, -12(fp) # Pop stack slot 3
|
|
|
|
|
*/
|
|
|
|
|
backend.emitLA(A0, cls.getPrototypeLabel(),
|
|
|
|
|
String.format("Load pointer to prototype of: %s", cls.getClassName()));
|
|
|
|
|
backend.emitLA(A0, cls.getPrototypeLabel(), String.format("Load pointer to prototype of: %s", cls.getClassName()));
|
|
|
|
|
backend.emitJAL(objectAllocLabel, "Allocate new object in A0");
|
|
|
|
|
backend.emitSW(A0, FP, -sp_off*wordSize, String.format("Push on stack slot %d", sp_off));
|
|
|
|
|
incSp(1);
|
|
|
|
@ -303,16 +309,16 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
backend.emitADDI(SP, FP, "-"+size_label, "Set SP to stack frame top.");
|
|
|
|
|
-- sp_off;
|
|
|
|
|
backend.emitLW(A0, FP, -sp_off*wordSize, String.format("Pop stack slot %d", sp_off));
|
|
|
|
|
} else {
|
|
|
|
|
// function
|
|
|
|
|
Identifier functionId = node.function;
|
|
|
|
|
FuncInfo calleeFunctionInfo = (FuncInfo) sym.get(node.function.name);
|
|
|
|
|
boolean isInMainFunction = funcInfo == null;
|
|
|
|
|
if (!isInMainFunction) {
|
|
|
|
|
System.out.println("--> caller: " + funcInfo.getFuncName() + " depth: " + funcInfo.getDepth());
|
|
|
|
|
System.out.println("--> callee: " + calleeFunctionInfo.getFuncName() + " depth: " + calleeFunctionInfo.getDepth());
|
|
|
|
|
|
|
|
|
|
int calleeDepth = calleeFunctionInfo.getDepth();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// function
|
|
|
|
|
Identifier functionId = node.function;
|
|
|
|
|
FuncInfo calleeFunctionInfo = (FuncInfo) sym.get(node.function.name);
|
|
|
|
|
boolean isInMainFunction = funcInfo == null;
|
|
|
|
|
if (!isInMainFunction)
|
|
|
|
|
{
|
|
|
|
|
int calleeDepth = calleeFunctionInfo.getDepth();
|
|
|
|
|
int callerDepth = funcInfo.getDepth();
|
|
|
|
|
int jumps = callerDepth - calleeDepth + 1;
|
|
|
|
|
|
|
|
|
@ -322,74 +328,81 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
backend.emitMV(tmp, FP, "Load FP");
|
|
|
|
|
|
|
|
|
|
FuncInfo curr = funcInfo;
|
|
|
|
|
for (int i = 0; i < jumps; i++) {
|
|
|
|
|
for (int i = 0; i < jumps; i++)
|
|
|
|
|
{
|
|
|
|
|
backend.emitLW(tmp, tmp, curr.getParams().size()*wordSize, "Load static link to " + curr.getFuncName());
|
|
|
|
|
curr = curr.getParentFuncInfo();
|
|
|
|
|
}
|
|
|
|
|
backend.emitSW(tmp, FP, -(sp_off+1) * wordSize, "Push static link onto active frame.");
|
|
|
|
|
freeRegister(tmpHandle);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
backend.emitSW(FP, FP, -(sp_off+1) * wordSize, "Push static link onto active frame.");
|
|
|
|
|
}
|
|
|
|
|
int origsp = sp_off;
|
|
|
|
|
incSp(1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
backend.emitSW(FP, FP, -(sp_off+1) * wordSize, "Push static link onto active frame.");
|
|
|
|
|
}
|
|
|
|
|
int origsp = sp_off;
|
|
|
|
|
incSp(1);
|
|
|
|
|
|
|
|
|
|
List<Expr> args = node.args;
|
|
|
|
|
int spaceRequiredForArgs = (args.size() + 1)*4;
|
|
|
|
|
for (int i = 0; i < args.size(); i++) {
|
|
|
|
|
incSp(1);
|
|
|
|
|
|
|
|
|
|
int argNum = i + 1;
|
|
|
|
|
int slotNum = argNum + 1; // We have extra slot for static link
|
|
|
|
|
Expr expr = args.get(i);
|
|
|
|
|
expr.dispatch(this);
|
|
|
|
|
|
|
|
|
|
String formalParamName = calleeFunctionInfo.getParams().get(i);
|
|
|
|
|
StackVarInfo formalParamInfo = (StackVarInfo) calleeFunctionInfo.getSymbolTable().get(formalParamName);
|
|
|
|
|
for (int i = 0; i < args.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
incSp(1);
|
|
|
|
|
int argNum = i + 1;
|
|
|
|
|
int slotNum = argNum + 1; // We have extra slot for static link
|
|
|
|
|
Expr expr = args.get(i);
|
|
|
|
|
expr.dispatch(this);
|
|
|
|
|
|
|
|
|
|
String formalParamName = calleeFunctionInfo.getParams().get(i);
|
|
|
|
|
StackVarInfo formalParamInfo = (StackVarInfo) calleeFunctionInfo.getSymbolTable().get(formalParamName);
|
|
|
|
|
|
|
|
|
|
if (expr.getInferredType().equals(Type.INT_TYPE)) {
|
|
|
|
|
if ((functionId.name.equals("print")) &&(formalParamInfo.getVarType().equals(Type.OBJECT_TYPE) || formalParamInfo.getVarType().equals(Type.INT_TYPE))) {
|
|
|
|
|
if(!(args.size() == 1 && (args.get(0) instanceof CallExpr) &&
|
|
|
|
|
if (expr.getInferredType().equals(Type.INT_TYPE))
|
|
|
|
|
{
|
|
|
|
|
if ((functionId.name.equals("print")) &&(formalParamInfo.getVarType().equals(Type.OBJECT_TYPE) || formalParamInfo.getVarType().equals(Type.INT_TYPE)))
|
|
|
|
|
{
|
|
|
|
|
if(!(args.size() == 1 && (args.get(0) instanceof CallExpr) &&
|
|
|
|
|
(sym.get(((CallExpr) args.get(0)).function.name) instanceof ClassInfo)))
|
|
|
|
|
backend.emitJAL(makeintLabel, "Box integer");
|
|
|
|
|
backend.emitJAL(makeintLabel, "Box integer");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// FIXME: passed argument does not match formal parameter
|
|
|
|
|
}
|
|
|
|
|
} else if (expr.getInferredType().equals(Type.BOOL_TYPE)) {
|
|
|
|
|
if ((functionId.name.equals("print"))&&(formalParamInfo.getVarType().equals(Type.OBJECT_TYPE) || formalParamInfo.getVarType().equals(Type.BOOL_TYPE))) {
|
|
|
|
|
if(!(args.size() == 1 && (args.get(0) instanceof CallExpr) &&
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (expr.getInferredType().equals(Type.BOOL_TYPE))
|
|
|
|
|
{
|
|
|
|
|
if ((functionId.name.equals("print"))&&(formalParamInfo.getVarType().equals(Type.OBJECT_TYPE) || formalParamInfo.getVarType().equals(Type.BOOL_TYPE)))
|
|
|
|
|
{
|
|
|
|
|
if(!(args.size() == 1 && (args.get(0) instanceof CallExpr) &&
|
|
|
|
|
(sym.get(((CallExpr) args.get(0)).function.name) instanceof ClassInfo)))
|
|
|
|
|
backend.emitJAL(makeboolLabel, "Box boolean");
|
|
|
|
|
backend.emitJAL(makeboolLabel, "Box boolean");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// FIXME: passed argument does not match formal parameter
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// All expressions should save their end result in A0
|
|
|
|
|
// So, once expr is evaluated add value inside A0 onto stack as an actual argument
|
|
|
|
|
//System.out.printf("1: %d\n",sp_off + 1 - slotNum-origsp);
|
|
|
|
|
backend.emitSW(A0, FP, -(sp_off) * wordSize, "Push actual argument for " + formalParamName + " onto stack");
|
|
|
|
|
|
|
|
|
|
backend.emitSW(A0, FP, -(sp_off) * wordSize, "Push actual argument for " + formalParamName + " onto stack");
|
|
|
|
|
}
|
|
|
|
|
//System.out.printf("2: %d",sp_off - spaceRequiredForArgs/wordSize - origsp);
|
|
|
|
|
|
|
|
|
|
backend.emitADDI(SP, FP, -(sp_off)*wordSize, "Set SP to last argument.");
|
|
|
|
|
backend.emitJAL(calleeFunctionInfo.getCodeLabel(), "Invoke function: " + functionId.name);
|
|
|
|
|
backend.emitADDI(SP, FP, "-"+size_label, "Set SP to stack frame top.");
|
|
|
|
|
sp_off-=spaceRequiredForArgs/wordSize;
|
|
|
|
|
backend.emitADDI(SP, FP, -(sp_off)*wordSize, "Set SP to last argument.");
|
|
|
|
|
backend.emitJAL(calleeFunctionInfo.getCodeLabel(), "Invoke function: " + functionId.name);
|
|
|
|
|
backend.emitADDI(SP, FP, "-"+size_label, "Set SP to stack frame top.");
|
|
|
|
|
sp_off-=spaceRequiredForArgs/wordSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return A0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Register analyze(MethodCallExpr node) {
|
|
|
|
|
public Register analyze(MethodCallExpr node)
|
|
|
|
|
{
|
|
|
|
|
System.out.println("Inside MethodCallExpr: " + node.method.member.name);
|
|
|
|
|
// backend.emitLW(T6, FP, 0, "Inside MethodCallExpr: " + node.method.member.name);
|
|
|
|
|
Register obj = node.method.object.dispatch(this);
|
|
|
|
|
Register obj = node.method.object.dispatch(this);
|
|
|
|
|
int n_args = node.args.size();
|
|
|
|
|
|
|
|
|
|
Label label = generateLocalLabel();
|
|
|
|
@ -422,29 +435,23 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Register analyze(ReturnStmt stmt) {
|
|
|
|
|
System.out.println("Inside ReturnStmt: ");
|
|
|
|
|
// backend.emitLW(T6, FP, 0, "Inside ReturnStmt: ");
|
|
|
|
|
Expr expr = stmt.value;
|
|
|
|
|
if (expr == null) {
|
|
|
|
|
backend.emitMV(A0, ZERO, "Return None");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
// All expressions should save their end result in A0
|
|
|
|
|
expr.dispatch(this);
|
|
|
|
|
backend.emitJ(this.epilogue, "Jump to function epilogue");
|
|
|
|
|
public Register analyze(ReturnStmt stmt)
|
|
|
|
|
{
|
|
|
|
|
Expr expr = stmt.value;
|
|
|
|
|
if(expr == null)
|
|
|
|
|
backend.emitMV(A0, ZERO, "Return None");
|
|
|
|
|
else
|
|
|
|
|
// All expressions should save their end result in A0
|
|
|
|
|
expr.dispatch(this);
|
|
|
|
|
backend.emitJ(this.epilogue, "Jump to function epilogue");
|
|
|
|
|
return A0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// *********** functions end ***********
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Register analyze(NoneLiteral node)
|
|
|
|
|
{
|
|
|
|
|
System.out.println("Inside NoneLiteral: ");
|
|
|
|
|
// backend.emitLW(T6, FP, 0, "Inside NoneLiteral: ");
|
|
|
|
|
backend.emitMV(Register.A0, Register.ZERO, "Load none");
|
|
|
|
|
return Register.A0;
|
|
|
|
|
}
|
|
|
|
@ -452,8 +459,6 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
@Override
|
|
|
|
|
public Register analyze(StringLiteral node)
|
|
|
|
|
{
|
|
|
|
|
System.out.println("Inside StringLiteral: ");
|
|
|
|
|
//backend.emitLW(T6, FP, 0, "Inside StringLiteral: ");
|
|
|
|
|
Label l = constants.getStrConstant(node.value);
|
|
|
|
|
backend.emitLA(Register.A0, l, "Load string literal");
|
|
|
|
|
return Register.A0;
|
|
|
|
@ -462,8 +467,6 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
@Override
|
|
|
|
|
public Register analyze(BooleanLiteral node)
|
|
|
|
|
{
|
|
|
|
|
System.out.println("Inside BooleanLiteral: ");
|
|
|
|
|
// backend.emitLW(T6, FP, 0, "Inside BooleanLiteral: ");
|
|
|
|
|
if(node.value==true)
|
|
|
|
|
backend.emitLI(Register.A0, 1, "Load boolean literal: true ");
|
|
|
|
|
else
|
|
|
|
@ -471,7 +474,8 @@ public class CodeGenImpl extends CodeGenBase
|
|
|
|
|
return Register.A0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class StackVarRuntimeInfo {
|
|
|
|
|
class StackVarRuntimeInfo
|
|
|
|
|
{
|
|
|
|
|
public final int off;
|
|
|
|
|
public final Register sl;
|
|
|
|
|
public int regHandle;
|
|
|
|
|