mirror of https://github.com/aamine/cbc
* net/loveruby/cflat/compiler/CodeGenerator.java: apply jump elimination.
* net/loveruby/cflat/asm/PeepholeOptimizer.java: new optimization method: jump elimination. * net/loveruby/cflat/asm/Assembler.java: refactoring: #string -> #toSource. * net/loveruby/cflat/asm/Assembler.java: refactoring: list -> assemblies. * net/loveruby/cflat/asm/Assembly.java: new method #isDirective and #isComment. * net/loveruby/cflat/asm/Directive.java: implement it. * net/loveruby/cflat/asm/AsmComment.java: implement it. * net/loveruby/cflat/asm/Label.java: implement it. * net/loveruby/cflat/asm/Label.java: new method #equals, #hashCode. * net/loveruby/cflat/asm/Instruction.java: add jump related methods to analyze jump instruction. * net/loveruby/cflat/asm/LabelRef.java: new method #label to allow extracting a Label. * net/loveruby/cflat/asm/Register.java: new method #equals, #hashCode. * net/loveruby/cflat/asm/AsmStatistics.java: use Object for map keys. * net/loveruby/cflat/asm/AsmStatistics.java: new method #doesRegisterUsed. * net/loveruby/cflat/utils/ClonableIterator.java: new utility. git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4050 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
parent
4f1f681a7c
commit
637fce5053
43
ChangeLog
43
ChangeLog
|
|
@ -1,3 +1,46 @@
|
|||
Tue Sep 23 22:50:52 2008 Minero Aoki <aamine@loveruby.net>
|
||||
|
||||
* net/loveruby/cflat/compiler/CodeGenerator.java: apply jump
|
||||
elimination.
|
||||
|
||||
* net/loveruby/cflat/asm/PeepholeOptimizer.java: new optimization
|
||||
method: jump elimination.
|
||||
|
||||
* net/loveruby/cflat/asm/Assembler.java: refactoring: #string ->
|
||||
#toSource.
|
||||
|
||||
* net/loveruby/cflat/asm/Assembler.java: refactoring: list ->
|
||||
assemblies.
|
||||
|
||||
* net/loveruby/cflat/asm/Assembly.java: new method #isDirective
|
||||
and #isComment.
|
||||
|
||||
* net/loveruby/cflat/asm/Directive.java: implement it.
|
||||
|
||||
* net/loveruby/cflat/asm/AsmComment.java: implement it.
|
||||
|
||||
* net/loveruby/cflat/asm/Label.java: implement it.
|
||||
|
||||
* net/loveruby/cflat/asm/Label.java: new method #equals,
|
||||
#hashCode.
|
||||
|
||||
* net/loveruby/cflat/asm/Instruction.java: add jump related
|
||||
methods to analyze jump instruction.
|
||||
|
||||
* net/loveruby/cflat/asm/LabelRef.java: new method #label to allow
|
||||
extracting a Label.
|
||||
|
||||
* net/loveruby/cflat/asm/Register.java: new method #equals,
|
||||
#hashCode.
|
||||
|
||||
* net/loveruby/cflat/asm/AsmStatistics.java: use Object for map
|
||||
keys.
|
||||
|
||||
* net/loveruby/cflat/asm/AsmStatistics.java: new method
|
||||
#doesRegisterUsed.
|
||||
|
||||
* net/loveruby/cflat/utils/ClonableIterator.java: new utility.
|
||||
|
||||
Tue Sep 23 22:45:00 2008 Minero Aoki <aamine@loveruby.net>
|
||||
|
||||
* lib/Makefile: parameterize.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ public class AsmComment extends Assembly {
|
|||
this.indentLevel = indentLevel;
|
||||
}
|
||||
|
||||
public boolean isComment() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toSource() {
|
||||
return "\t" + indent() + "# " + string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,16 @@ public class AsmStatistics {
|
|||
insnUsage = new HashMap();
|
||||
}
|
||||
|
||||
public int numRegisterUsage(String name) {
|
||||
return fetchCount(registerUsage, name);
|
||||
public boolean doesRegisterUsed(Register reg) {
|
||||
return numRegisterUsage(reg) > 0;
|
||||
}
|
||||
|
||||
public void registerUsed(String name) {
|
||||
incrementCount(registerUsage, name);
|
||||
public int numRegisterUsage(Register reg) {
|
||||
return fetchCount(registerUsage, reg);
|
||||
}
|
||||
|
||||
public void registerUsed(Register reg) {
|
||||
incrementCount(registerUsage, reg);
|
||||
}
|
||||
|
||||
public int numInstructionUsage(String insn) {
|
||||
|
|
@ -36,8 +40,8 @@ public class AsmStatistics {
|
|||
incrementCount(insnUsage, insn);
|
||||
}
|
||||
|
||||
protected int fetchCount(Map m, String name) {
|
||||
Integer n = (Integer)m.get(name);
|
||||
protected int fetchCount(Map m, Object key) {
|
||||
Integer n = (Integer)m.get(key);
|
||||
if (n == null) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -46,7 +50,7 @@ public class AsmStatistics {
|
|||
}
|
||||
}
|
||||
|
||||
protected void incrementCount(Map m, String name) {
|
||||
m.put(name, new Integer(fetchCount(m, name) + 1));
|
||||
protected void incrementCount(Map m, Object key) {
|
||||
m.put(key, new Integer(fetchCount(m, key) + 1));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import net.loveruby.cflat.utils.*;
|
|||
import java.util.*;
|
||||
|
||||
public class Assembler {
|
||||
protected List list; // List<Assembly>
|
||||
protected List assemblies; // List<Assembly>
|
||||
protected Type naturalType;
|
||||
protected int commentIndentLevel;
|
||||
|
||||
|
|
@ -13,24 +13,24 @@ public class Assembler {
|
|||
}
|
||||
|
||||
public Assembler(Type naturalType) {
|
||||
this.list = new ArrayList();
|
||||
this.assemblies = new ArrayList();
|
||||
this.naturalType = naturalType;
|
||||
this.commentIndentLevel = 0;
|
||||
}
|
||||
|
||||
public List assemblies() {
|
||||
return this.list;
|
||||
return this.assemblies;
|
||||
}
|
||||
|
||||
public void addAll(List assemblies) {
|
||||
this.list.addAll(assemblies);
|
||||
this.assemblies.addAll(assemblies);
|
||||
}
|
||||
|
||||
public String string() {
|
||||
public String toSource() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
Iterator i = list.iterator();
|
||||
while (i.hasNext()) {
|
||||
Assembly asm = (Assembly)i.next();
|
||||
Iterator asms = assemblies.iterator();
|
||||
while (asms.hasNext()) {
|
||||
Assembly asm = (Assembly)asms.next();
|
||||
buf.append(asm.toSource());
|
||||
buf.append("\n");
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ public class Assembler {
|
|||
}
|
||||
|
||||
public void comment(String str) {
|
||||
list.add(new AsmComment(str, commentIndentLevel));
|
||||
assemblies.add(new AsmComment(str, commentIndentLevel));
|
||||
}
|
||||
|
||||
public void indentComment() {
|
||||
|
|
@ -50,39 +50,39 @@ public class Assembler {
|
|||
}
|
||||
|
||||
public void label(String sym) {
|
||||
list.add(new Label(sym));
|
||||
assemblies.add(new Label(sym));
|
||||
}
|
||||
|
||||
public void label(Label label) {
|
||||
list.add(label);
|
||||
assemblies.add(label);
|
||||
}
|
||||
|
||||
protected void directive(String direc) {
|
||||
list.add(new Directive(direc));
|
||||
assemblies.add(new Directive(direc));
|
||||
}
|
||||
|
||||
protected void insn(String op) {
|
||||
list.add(new Instruction(op));
|
||||
assemblies.add(new Instruction(op));
|
||||
}
|
||||
|
||||
protected void insn(String op, AsmOperand a) {
|
||||
list.add(new Instruction(op, "", a));
|
||||
assemblies.add(new Instruction(op, "", a));
|
||||
}
|
||||
|
||||
protected void insn(String op, String suffix, AsmOperand a) {
|
||||
list.add(new Instruction(op, suffix, a));
|
||||
assemblies.add(new Instruction(op, suffix, a));
|
||||
}
|
||||
|
||||
protected void insn(Type t, String op, AsmOperand a) {
|
||||
list.add(new Instruction(op, typeSuffix(t), a));
|
||||
assemblies.add(new Instruction(op, typeSuffix(t), a));
|
||||
}
|
||||
|
||||
protected void insn(String op, String suffix, AsmOperand a, AsmOperand b) {
|
||||
list.add(new Instruction(op, suffix, a, b));
|
||||
assemblies.add(new Instruction(op, suffix, a, b));
|
||||
}
|
||||
|
||||
protected void insn(Type t, String op, AsmOperand a, AsmOperand b) {
|
||||
list.add(new Instruction(op, typeSuffix(t), a, b));
|
||||
assemblies.add(new Instruction(op, typeSuffix(t), a, b));
|
||||
}
|
||||
|
||||
protected String typeSuffix(Type t1, Type t2) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,14 @@ abstract public class Assembly {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean isDirective() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isComment() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void collectStatistics(AsmStatistics stats) {
|
||||
// does nothing by default.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ public class Directive extends Assembly {
|
|||
this.content = content;
|
||||
}
|
||||
|
||||
public boolean isDirective() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toSource() {
|
||||
return this.content;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,17 @@ public class Instruction extends Assembly {
|
|||
return this.mnemonic;
|
||||
}
|
||||
|
||||
public boolean isJumpInstruction() {
|
||||
return mnemonic.equals("jmp")
|
||||
|| mnemonic.equals("jz")
|
||||
|| mnemonic.equals("jne")
|
||||
|| mnemonic.equals("je")
|
||||
|| mnemonic.equals("jne");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of operands.
|
||||
*/
|
||||
public int numOperands() {
|
||||
return this.operands.length;
|
||||
}
|
||||
|
|
@ -53,6 +64,14 @@ public class Instruction extends Assembly {
|
|||
return this.operands[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract jump destination label from operands.
|
||||
*/
|
||||
public Label jmpDestination() {
|
||||
DirectMemoryReference ref = (DirectMemoryReference)(operands[0]);
|
||||
return ((LabelRef)ref.value()).label();
|
||||
}
|
||||
|
||||
public void collectStatistics(AsmStatistics stats) {
|
||||
stats.instructionUsed(mnemonic);
|
||||
for (int i = 0; i < operands.length; i++) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ public class Label extends Assembly {
|
|||
name = n;
|
||||
}
|
||||
|
||||
public boolean isLabel() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public long seq() {
|
||||
return seq;
|
||||
}
|
||||
|
|
@ -22,6 +26,23 @@ public class Label extends Assembly {
|
|||
return name;
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof Label) {
|
||||
return equals((Label)other);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Label label) {
|
||||
return name.equals(label.name());
|
||||
}
|
||||
|
||||
public String toSource() {
|
||||
return name + ":";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ public class LabelRef extends Literal {
|
|||
this.label = label;
|
||||
}
|
||||
|
||||
public Label label() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public String symbol() {
|
||||
return label.name();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
package net.loveruby.cflat.asm;
|
||||
import net.loveruby.cflat.utils.ClonableIterator;
|
||||
import java.util.*;
|
||||
|
||||
public class PeepholeOptimizer implements AsmOptimizer {
|
||||
|
|
@ -8,6 +9,10 @@ public class PeepholeOptimizer implements AsmOptimizer {
|
|||
this.filters = defaultFilterSet();
|
||||
}
|
||||
|
||||
public List optimize(List assemblies) {
|
||||
return jumpElimination(insnOptimization(assemblies));
|
||||
}
|
||||
|
||||
// List<Filter>
|
||||
protected List defaultFilterSet() {
|
||||
List set = new ArrayList();
|
||||
|
|
@ -123,7 +128,7 @@ public class PeepholeOptimizer implements AsmOptimizer {
|
|||
return new AnyRegisterPattern();
|
||||
}
|
||||
|
||||
public List optimize(List assemblies) {
|
||||
public List insnOptimization(List assemblies) {
|
||||
List result = new ArrayList();
|
||||
Iterator asms = assemblies.iterator();
|
||||
while (asms.hasNext()) {
|
||||
|
|
@ -205,4 +210,64 @@ public class PeepholeOptimizer implements AsmOptimizer {
|
|||
interface InsnTemplate {
|
||||
abstract public Instruction apply(Instruction insn);
|
||||
}
|
||||
|
||||
//
|
||||
// jumpElimination
|
||||
//
|
||||
|
||||
public List jumpElimination(List assemblies) {
|
||||
List result = new ArrayList();
|
||||
ClonableIterator asms = new ClonableIterator(assemblies);
|
||||
while (asms.hasNext()) {
|
||||
Assembly asm = (Assembly)asms.next();
|
||||
if (isUselessJump(asm, asms)) {
|
||||
; // remove useless jump
|
||||
}
|
||||
else {
|
||||
result.add(asm);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean isUselessJump(Assembly asm, ClonableIterator asms) {
|
||||
if (! asm.isInstruction()) return false;
|
||||
Instruction insn = (Instruction)asm;
|
||||
if (! insn.isJumpInstruction()) return false;
|
||||
return doesLabelFollows(asms.dup(), insn.jmpDestination());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if jmpDest is found in asms before any instruction
|
||||
* or directives. For example, this method returns true if contents
|
||||
* of asms are:
|
||||
*
|
||||
* if_end3:
|
||||
* # comment
|
||||
* jmpDest:
|
||||
* mov
|
||||
* mov
|
||||
* add
|
||||
*/
|
||||
protected boolean doesLabelFollows(ClonableIterator asms, Label jmpDest) {
|
||||
while (asms.hasNext()) {
|
||||
Assembly asm = (Assembly)asms.next();
|
||||
if (asm.isLabel()) {
|
||||
Label label = (Label)asm;
|
||||
if (label.equals(jmpDest)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (asm.isComment()) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,22 @@ public class Register extends AsmOperand {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof Register)) return false;
|
||||
return equals((Register)other);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* size difference does NOT matter.
|
||||
*/
|
||||
public boolean equals(Register reg) {
|
||||
return name.equals(reg.baseName());
|
||||
}
|
||||
|
||||
public String baseName() {
|
||||
return name;
|
||||
}
|
||||
|
|
@ -62,7 +78,7 @@ public class Register extends AsmOperand {
|
|||
}
|
||||
|
||||
public void collectStatistics(AsmStatistics stats) {
|
||||
stats.registerUsed(name);
|
||||
stats.registerUsed(this);
|
||||
}
|
||||
|
||||
public String toSource() {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
|
|||
protected AsmOptimizer optimizer;
|
||||
protected ErrorHandler errorHandler;
|
||||
protected boolean verboseAsm;
|
||||
protected Assembler assembler;
|
||||
protected LinkedList asStack;
|
||||
protected Assembler as;
|
||||
protected TypeTable typeTable;
|
||||
protected DefinedFunction currentFunction;
|
||||
|
|
@ -20,6 +20,7 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
|
|||
this.optimizer = optimizer;
|
||||
this.errorHandler = errorHandler;
|
||||
this.verboseAsm = verboseAsm;
|
||||
this.asStack = new LinkedList();
|
||||
}
|
||||
// #@@}
|
||||
|
||||
|
|
@ -27,12 +28,26 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
|
|||
// #@@range/generate
|
||||
public String generate(AST ast) {
|
||||
this.typeTable = ast.typeTable();
|
||||
this.assembler = newAssembler();
|
||||
this.as = this.assembler;
|
||||
pushAssembler();
|
||||
allocateGlobalVariables(ast.globalVariables());
|
||||
allocateCommonSymbols(ast.commonSymbols());
|
||||
compileAST(ast);
|
||||
return as.string();
|
||||
return popAssembler().toSource();
|
||||
}
|
||||
|
||||
protected void pushAssembler() {
|
||||
asStack.add(newAssembler());
|
||||
this.as = (Assembler)asStack.getLast();
|
||||
}
|
||||
|
||||
protected Assembler popAssembler() {
|
||||
Assembler poped = (Assembler)asStack.removeLast();
|
||||
this.as = asStack.isEmpty() ? null : (Assembler)asStack.getLast();
|
||||
return poped;
|
||||
}
|
||||
|
||||
protected Assembler newAssembler() {
|
||||
return new Assembler(typeTable.unsignedLong());
|
||||
}
|
||||
|
||||
public void compileAST(AST ast) {
|
||||
|
|
@ -54,10 +69,6 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
|
|||
}
|
||||
// #@@}
|
||||
|
||||
protected Assembler newAssembler() {
|
||||
return new Assembler(typeTable.unsignedLong());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets memory reference for...
|
||||
* * public global variables
|
||||
|
|
@ -189,37 +200,38 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
|
|||
/** Compiles a function. */
|
||||
// #@@range/compileFunction{
|
||||
protected void compileFunction(DefinedFunction func) {
|
||||
long numSavedRegs = 0; // 1 for PIC
|
||||
allocateParameters(func);
|
||||
allocateLocalVariablesTemp(func.body().scope());
|
||||
|
||||
List bodyAsms = compileFunctionBody(func);
|
||||
AsmStatistics stats = AsmStatistics.collect(bodyAsms);
|
||||
List usedCalleeSavedRegs = usedCalleeSavedRegs(stats);
|
||||
long lvarBytes = allocateLocalVariables(func.body().scope(),
|
||||
usedCalleeSavedRegs.size());
|
||||
|
||||
String symbol = csymbol(func.name());
|
||||
if (! func.isPrivate()) {
|
||||
_globl(symbol);
|
||||
}
|
||||
_type(symbol, "@function");
|
||||
label(symbol);
|
||||
prologue(func, usedCalleeSavedRegs, lvarBytes);
|
||||
as.addAll(bodyAsms);
|
||||
epilogue(func, usedCalleeSavedRegs, lvarBytes);
|
||||
compileFunctionBody(func);
|
||||
_size(symbol, ".-" + symbol);
|
||||
}
|
||||
// #@@}
|
||||
|
||||
protected List compileFunctionBody(DefinedFunction func) {
|
||||
protected void compileFunctionBody(DefinedFunction func) {
|
||||
List bodyAsms = compileStmts(func);
|
||||
AsmStatistics stats = AsmStatistics.collect(bodyAsms);
|
||||
List saveRegs = usedCalleeSavedRegisters(stats);
|
||||
long lvarBytes = allocateLocalVariables(func.body().scope(),
|
||||
saveRegs.size());
|
||||
prologue(func, saveRegs, lvarBytes);
|
||||
as.addAll(bodyAsms);
|
||||
epilogue(func, saveRegs, lvarBytes);
|
||||
}
|
||||
|
||||
protected List compileStmts(DefinedFunction func) {
|
||||
pushAssembler();
|
||||
currentFunction = func;
|
||||
this.as = newAssembler();
|
||||
compile(func.body());
|
||||
List assemblies = this.as.assemblies();
|
||||
this.as = this.assembler;
|
||||
label(epilogueLabel(func));
|
||||
currentFunction = null;
|
||||
return optimizer.optimize(assemblies);
|
||||
return optimizer.optimize(popAssembler().assemblies());
|
||||
}
|
||||
|
||||
// #@@range/compile{
|
||||
|
|
@ -250,12 +262,12 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
|
|||
}
|
||||
// #@@}
|
||||
|
||||
protected List usedCalleeSavedRegs(AsmStatistics stats) {
|
||||
protected List usedCalleeSavedRegisters(AsmStatistics stats) {
|
||||
List result = new ArrayList();
|
||||
Iterator regs = calleeSavedRegisters().iterator();
|
||||
while (regs.hasNext()) {
|
||||
Register reg = (Register)regs.next();
|
||||
if (stats.numRegisterUsage(reg.baseName()) > 0) {
|
||||
if (stats.doesRegisterUsed(reg)) {
|
||||
result.add(reg);
|
||||
}
|
||||
}
|
||||
|
|
@ -318,16 +330,8 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
|
|||
List saveRegs, long lvarBytes) {
|
||||
push(bp());
|
||||
mov(sp(), bp());
|
||||
Iterator regs = saveRegs.iterator();
|
||||
while (regs.hasNext()) {
|
||||
Register reg = (Register)regs.next();
|
||||
// bp is already saved
|
||||
if (! reg.baseName().equals("bp")) {
|
||||
push(reg);
|
||||
}
|
||||
}
|
||||
saveRegisters(saveRegs);
|
||||
extendStack(lvarBytes);
|
||||
|
||||
if (verboseAsm) {
|
||||
Iterator vars = func.localVariables();
|
||||
while (vars.hasNext()) {
|
||||
|
|
@ -341,21 +345,34 @@ public class CodeGenerator extends Visitor implements ASTLHSVisitor {
|
|||
// #@@range/epilogue{
|
||||
protected void epilogue(DefinedFunction func,
|
||||
List savedRegs, long lvarBytes) {
|
||||
label(epilogueLabel(func));
|
||||
shrinkStack(lvarBytes);
|
||||
Iterator regs = savedRegs.iterator();
|
||||
while (regs.hasNext()) {
|
||||
Register reg = (Register)regs.next();
|
||||
if (! reg.baseName().equals("bp")) {
|
||||
pop(reg);
|
||||
}
|
||||
}
|
||||
restoreRegisters(savedRegs);
|
||||
mov(bp(), sp());
|
||||
pop(bp());
|
||||
ret();
|
||||
}
|
||||
// #@@}
|
||||
|
||||
protected void saveRegisters(List saveRegs) {
|
||||
Iterator regs = saveRegs.iterator();
|
||||
while (regs.hasNext()) {
|
||||
Register reg = (Register)regs.next();
|
||||
if (! reg.equals(bp())) { // bp is already saved.
|
||||
push(reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreRegisters(List savedRegs) {
|
||||
Iterator regs = savedRegs.iterator();
|
||||
while (regs.hasNext()) {
|
||||
Register reg = (Register)regs.next();
|
||||
if (! reg.equals(bp())) { // bp is going to be restored.
|
||||
pop(reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #@@range/jmpEpilogue{
|
||||
protected void jmpEpilogue() {
|
||||
jmp(new Label(epilogueLabel(currentFunction)));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package net.loveruby.cflat.utils;
|
||||
import java.util.*;
|
||||
|
||||
public class ClonableIterator implements Iterator {
|
||||
protected List list;
|
||||
protected int index;
|
||||
|
||||
public ClonableIterator(List list) {
|
||||
this(list, 0);
|
||||
}
|
||||
|
||||
protected ClonableIterator(List list, int index) {
|
||||
this.list = list;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
return new ClonableIterator(list, index);
|
||||
}
|
||||
|
||||
public ClonableIterator dup() {
|
||||
return new ClonableIterator(list, index);
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return index < list.size();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
return list.get(index++);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
list.remove(index);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "#<ClonableIterator list=" + list + " index=" + index + ">";
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue