done without gc

This commit is contained in:
ridethepig 2023-04-01 15:34:50 +08:00
parent c29b455305
commit fec2e03a75
5 changed files with 183 additions and 22 deletions

View File

@ -356,6 +356,63 @@ static void emit_gc_check(char *source, ostream &s) {
s << JAL << "_gc_check" << endl;
}
/*
| ........ |
|------------|
| param 2 |
|------------|
| param 1 |
|------------|
| old $fp |<----------- $sp before entry
|------------|
| old $s0 |
|------------|
| ret addr |<----------- current $fp
|------------|
| local 1 |<----------- $sp at entry
|------------|
| local 2 |
|------------|
| ........ |
Throughout the code generated for expressions, I used 4 registers:
$a0, $s0, $a1, $t1. According to MIPS calling conventions, only $s0 needs
to be saved. Thus the callee pushes and pops $fp,$s0,$ra when entering and
leaving the context.
By default, self object is passed to called in $a0, so move it to $s0
*/
static void emit_procedure_header(ostream &s) {
/*
addiu $sp $sp -12
sw $fp 12($sp)
sw $s0 8($sp)
sw $ra 4($sp)
addiu $fp $sp 4
move $s0 $a0
*/
emit_addiu(SP, SP, -12, s);
emit_store(FP, 3, SP, s);
emit_store(SELF, 2, SP, s);
emit_store(RA, 1, SP, s);
emit_addiu(FP, SP, 4, s);
emit_move(SELF, ACC, s);
rel_stack_depth = 0;
}
static void emit_procedure_footer(int nparams, ostream &s) {
/*
lw $fp 12($sp)
lw $s0 8($sp)
lw $ra 4($sp)
addiu $sp $sp (12 + 4 * nparams)
jr $ra
*/
emit_load(FP, 3, SP, s);
emit_load(SELF, 2, SP, s);
emit_load(RA, 1, SP, s);
emit_addiu(SP, SP, 4 * (3 + nparams), s);
emit_return(s);
}
#pragma endregion
///////////////////////////////////////////////////////////////////////////////
@ -635,16 +692,16 @@ void CgenClassTable::code_prototypeObject() {
str << WORD << node->get_class_tag() << endl; // class tag
str << WORD << node->get_object_size() << endl; // object size
str << WORD << node->get_name() << DISPTAB_SUFFIX << endl; // dispatch ptr
for (auto attr : *node->get_attributes()) {
if (attr->type_decl == Int) {
for (auto attr_pair : *node->get_attributes()) {
if (attr_pair.second->type_decl == Int) {
str << WORD;
_int_default->code_ref(str);
str << endl;
} else if (attr->type_decl == Bool) {
} else if (attr_pair.second->type_decl == Bool) {
str << WORD;
_bool_default->code_ref(str);
str << endl;
} else if (attr->type_decl == Str) {
} else if (attr_pair.second->type_decl == Str) {
str << WORD;
_str_default->code_ref(str);
str << endl;
@ -666,6 +723,81 @@ void CgenClassTable::code_objectTab() {
}
}
void CgenClassTable::gen_init_code() {
for (auto node : nodes) {
this->cur_class = node;
str << node->get_name() << CLASSINIT_SUFFIX << LABEL;
emit_procedure_header(str);
if (node->get_parentnd() && node->get_parentnd()->name != No_class) {
str << JAL << node->parent->get_string() << CLASSINIT_SUFFIX << endl;
}
auto attrs = node->get_attributes();
// attributes are available when initializing
loctab.enterscope();
for (auto i = 0U; i < attrs->size(); ++i) {
auto attr_pair = (*attrs)[i];
loctab.add(LocationTableItem(attr_pair.second->name, Attribute,
i + DEFAULT_OBJFIELDS));
}
for (auto i = 0U; i < attrs->size(); ++i) {
auto attr_pair = (*attrs)[i];
if (attr_pair.first->name != node->name)
continue;
// base class initializer will handle inherited attributes
// here we only deal with our new attributes
if (is_no_expr(attr_pair.second->init))
continue;
// we can safely skip for those attributes without initialization expr
// because the default values are set in the prototype object, when
// the object is created by Object.copy(), they will be set to correct
// default values
this->expr_type_decl = attr_pair.second->type_decl;
attr_pair.second->init->code(str, this);
emit_store(ACC, i + DEFAULT_OBJFIELDS, SELF, str);
}
loctab.exitscope();
emit_move(ACC, SELF, str);
// remember to place the initialized object back to $a0, other code rely on
// this behavior
emit_procedure_footer(0, str);
}
}
void CgenClassTable::gen_method_code() {
for (auto node : nodes) {
if (node->basic())
continue;
this->cur_class = node;
for (auto method_pair : *node->get_methods()) {
if (method_pair.first->name != node->name)
continue; // skip inherited methods
auto method = method_pair.second;
auto attrs = node->get_attributes();
// add attributes and formals to location table
loctab.enterscope();
// add attributes
for (auto i = 0U; i < attrs->size(); ++i) {
auto attr_pair = (*attrs)[i];
loctab.add(LocationTableItem(attr_pair.second->name, Attribute,
i + DEFAULT_OBJFIELDS));
}
// add formals
for (auto i = method->formals->first(); method->formals->more(i);
i = method->formals->next(i)) {
auto formal = static_cast<formal_class *>(method->formals->nth(i));
loctab.add(LocationTableItem(formal->name, Stack,
method->formals->len() - i + 3 - 1));
// &formal[i] = (4 * i + 12)($fp)
}
str << node->name << "." << method->name << LABEL;
emit_procedure_header(str);
method->expr->code(str, this);
emit_procedure_footer(method->formals->len(), str);
loctab.exitscope();
}
}
}
CgenClassTable::CgenClassTable(Classes classes, ostream &s) : str(s) {
enterscope();
if (cgen_debug)
@ -974,10 +1106,13 @@ void CgenClassTable::code() {
}
#endif
// Add your code to emit
// - object initializer
// - the class methods
// - etc...
if (cgen_debug)
cout << "generating object initializers" << endl;
gen_init_code();
if (cgen_debug)
cout << "generating class methods" << endl;
gen_method_code();
}
///////////////////////////////////////////////////////////////////////
@ -1031,7 +1166,9 @@ void CgenNode::traverse_generate_object() {
feature_i = features->next(feature_i)) {
auto feature = features->nth(feature_i);
if (typeid(*feature) == typeid(attr_class)) {
this->attributes.push_back(static_cast<attr_class *>(feature));
this->attributes.push_back(
std::make_pair(static_cast<class__class *>(this),
static_cast<attr_class *>(feature)));
// inherited attrs cannot be redefined, so simply add to list
} else {
auto method = static_cast<method_class *>(feature);
@ -1055,7 +1192,8 @@ void CgenNode::traverse_generate_object() {
std::cerr << "Object info -- " << this->name << "\n";
std::cerr << "Attributes:\n";
for (auto attr : attributes) {
std::cerr << " " << attr->name << ":" << attr->type_decl << "\n";
std::cerr << " " << attr.first->name << "." << attr.second->name << ":"
<< attr.second->type_decl << "\n";
}
std::cerr << "Methods:\n";
for (auto method : methods) {
@ -1118,11 +1256,13 @@ void assign_class::code(ostream &s, CgenClassTable *classtab) {
and jalr.
*/
void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {
int nparams = 0;
for (auto actual_i = this->actual->first(); this->actual->more(actual_i);
actual_i = this->actual->next(actual_i)) {
auto actual_expr = this->actual->nth(actual_i);
actual_expr->code(s, classtab);
emit_push(ACC, s); // push param to stack
++ nparams;
}
this->expr->code(s, classtab);
auto label_dispatch = classtab->alloc_label_index();
@ -1130,11 +1270,11 @@ void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {
emit_bne(ACC, ZERO, label_dispatch, s);
// Prints the line number, from $t1, and filename, from $a0, at which the
// dispatch occurred, and aborts.
emit_load_imm(T1, this->line_number, s);
emit_partial_load_address(ACC, s);
stringtable.lookup_string(classtab->cur_class->get_filename()->get_string())
->code_ref(s);
s << endl;
emit_load_imm(T1, this->line_number, s);
emit_jal("_dispatch_abort", s);
// ready to call the method
emit_label_def(label_dispatch, s);
@ -1146,6 +1286,7 @@ void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {
emit_load(T1, classtab->get_method_index(this->type_name, this->name), T1, s);
// call the method whose address is in $t1, with self object in $a0
emit_jalr(T1, s);
rel_stack_depth -= nparams;
}
/*
@ -1154,11 +1295,13 @@ void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {
dispTab feild(offset 8) instead of querying method address at compile time.
*/
void dispatch_class::code(ostream &s, CgenClassTable *classtab) {
int nparams = 0;
for (auto actual_i = this->actual->first(); this->actual->more(actual_i);
actual_i = this->actual->next(actual_i)) {
auto actual_expr = this->actual->nth(actual_i);
actual_expr->code(s, classtab);
emit_push(ACC, s); // push param to stack
++ nparams;
}
this->expr->code(s, classtab);
auto label_dispatch = classtab->alloc_label_index();
@ -1166,11 +1309,11 @@ void dispatch_class::code(ostream &s, CgenClassTable *classtab) {
emit_bne(ACC, ZERO, label_dispatch, s);
// Prints the line number, from $t1, and filename, from $a0, at which the
// dispatch occurred, and aborts.
emit_load_imm(T1, this->line_number, s);
emit_partial_load_address(ACC, s);
stringtable.lookup_string(classtab->cur_class->get_filename()->get_string())
->code_ref(s);
s << endl;
emit_load_imm(T1, this->line_number, s);
emit_jal("_dispatch_abort", s);
// ready to call the method
emit_label_def(label_dispatch, s);
@ -1188,6 +1331,7 @@ void dispatch_class::code(ostream &s, CgenClassTable *classtab) {
emit_load(T1, method_index, T1, s);
// call the method whose address is in $t1, with self object in $a0
emit_jalr(T1, s);
rel_stack_depth -= nparams;
}
/*
@ -1284,8 +1428,9 @@ void typcase_class::code(ostream &s, CgenClassTable *classtab) {
// because we dont know whether $a0 is going to be overwritten
emit_push(ACC, s);
// allocate a new location
classtab->enterscope();
classtab->loctab.add(LocationTableItem(branch->name, Stack, -rel_stack_depth));
classtab->loctab.enterscope();
classtab->loctab.add(
LocationTableItem(branch->name, Stack, -rel_stack_depth));
// if expr's tag is in range, evaluate this branch
branch->expr->code(s, classtab);
classtab->loctab.exitscope();
@ -1423,7 +1568,7 @@ void neg_class::code(ostream &s, CgenClassTable *classtab) {
this->e1->code(s, classtab);
emit_jal("Object.copy", s);
emit_fetch_int(T1, ACC, s);
emit_neg(T1, ACC, s);
emit_neg(T1, T1, s);
emit_store_int(T1, ACC, s);
}
@ -1633,6 +1778,8 @@ void no_expr_class::code(ostream &s, CgenClassTable *classtab) {
emit_load_bool(ACC, *classtab->bool_default(), s);
} else if (classtab->expr_type_decl == Str) {
emit_load_string(ACC, classtab->str_default(), s);
} else if (classtab->expr_type_decl == prim_slot) {
assert(0); // basic type should not get attrs init
} else {
assert(classtab->expr_type_decl);
emit_move(ACC, ZERO, s);

View File

@ -1,4 +1,5 @@
#include "cool-tree.h"
#include "cool-tree.handcode.h"
#include "emit.h"
#include "symtab.h"
#include <assert.h>
@ -24,7 +25,7 @@ typedef CgenNode *CgenNodeP;
class BoolConst;
typedef std::vector<std::pair<class__class *, method_class *>> MethodListT;
typedef std::vector<attr_class *> AttrListT;
typedef std::vector<std::pair<class__class *, attr_class *>> AttrListT;
struct LocationTableItem {
LocationTableItem(Symbol id, VariableLocation loc, int off)
@ -108,6 +109,7 @@ private:
CgenNode *get_node(Symbol);
void code_objectTab();
void gen_init_code();
void gen_method_code();
public:
LocationTable loctab;
@ -168,3 +170,7 @@ public:
void code_def(ostream &, int boolclasstag);
void code_ref(ostream &) const;
};
inline bool is_no_expr(Expression expr) {
return typeid(*expr) == typeid(no_expr_class);
}

View File

@ -20,8 +20,11 @@ class B inherits A {
};
class C inherits A {
attr_C_1 : String <- "This is C\n".concat(new A.method_common2());
attr_C_2 : SELF_TYPE;
attr_C_0 : Int <- 10;
attr_C_1 : String <- "This is C\n".concat(new A.method_common2());
attr_C_3 : Int <- "12345".length();
attr_C_4 : Bool <- "12345".length() = 5;
method_common(x1: Int) : SELF_TYPE {
self
};

View File

@ -1,2 +1,4 @@
#!/bin/bash
./lexer $* | ./parser $* | ./semant $* > debug.in
./lexer $* | ./parser $* | ./semant $* | ./cgen $*
rm debug.in

View File

@ -1,2 +1,5 @@
#!/bin/bash
filename=$(basename -- "$*")
filename="${filename%.*}"
../../bin/lexer $* | ../../bin/parser $* | ../../bin/semant $* | ../../bin/cgen $*
mv $filename.s $filename.std.s