Skip to content

Commit f0603da

Browse files
class constructors + fix GC bug
1 parent eda1132 commit f0603da

File tree

8 files changed

+136
-71
lines changed

8 files changed

+136
-71
lines changed

compiler/ast/nodes.oc

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,19 +226,27 @@ def Operator::needs_lhs_pointer_for_overload(this): bool => match this {
226226
else => false
227227
}
228228

229+
enum FunctionType {
230+
Script
231+
Function
232+
Method
233+
Constructor
234+
}
235+
229236
struct Function {
237+
type: FunctionType
230238
sym: &Symbol
231239
params: &Vector<&Variable>
232240
body: &AST
233241
exits: bool
234242
span: Span
235243

236244
operator_overloads: &Vector<Operator>
237-
is_method: bool
238245
}
239246

240-
def Function::new(): &Function {
247+
def Function::new(type: FunctionType): &Function {
241248
let func = mem::alloc<Function>()
249+
func.type = type
242250
func.params = Vector<&Variable>::new()
243251
return func
244252
}

compiler/compiler.oc

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import std::span::{ Span }
33
import std::sv::{ SV }
44
import std::mem
55

6-
import @ast::nodes::{ this, AST, Variable, Symbol }
6+
import @ast::nodes::{ this, AST, Variable, Symbol, FunctionType }
77
import @errors::{ Error }
88
import @bytecode::{ Chunk, OpCode }
99
import @vm::{ VM }
@@ -30,22 +30,13 @@ struct Compiler {
3030
locals: &Vector<LocalVar>
3131
scope_depth: u32
3232
enclosing: &Compiler
33+
function_type: FunctionType
3334
}
3435

35-
enum CompileType {
36-
Script
37-
Function
38-
Method
39-
}
40-
41-
def Compiler::new(
42-
vm: &VM, name: SV, span: Span,
43-
type: CompileType,
44-
enclosing: &Compiler = null
45-
): &Compiler {
36+
def Compiler::new(vm: &VM, sym: &Symbol, type: FunctionType, enclosing: &Compiler = null): &Compiler {
4637
let compiler = mem::alloc<Compiler>()
4738

48-
let chunk = Chunk::new(span)
39+
let chunk = Chunk::new(sym.span)
4940
let locals = Vector<LocalVar>::new(capacity: 8)
5041
let upvars = Vector<UpVar>::new(capacity: 256)
5142
let func = gc::allocate_object<FunctionCode>(FunctionCode, vm, enclosing)
@@ -57,17 +48,18 @@ def Compiler::new(
5748
upvars,
5849
locals,
5950
scope_depth: 0,
60-
enclosing
51+
enclosing,
52+
function_type: type
6153
)
6254
gc::set_compiler(compiler)
6355

64-
let name_val = vm.copy_string(name.data, name.len)
56+
let name_val = compiler.make_str(sym.name)
6557
func.init(name_val.as_string(), chunk, 0) // Replace arity later...
6658

67-
if type == Method {
68-
locals.push(LocalVar(SV("this",4), span, 0, false))
59+
if type != Function {
60+
locals.push(LocalVar(SV("this",4), sym.span, 0, false))
6961
} else {
70-
locals.push(LocalVar(SV("",0), span, 0, false))
62+
locals.push(LocalVar(SV("",0), sym.span, 0, false))
7163
}
7264

7365
return compiler
@@ -369,12 +361,10 @@ def Compiler::compile_expression(&this, node: &AST) {
369361
}
370362

371363
def Compiler::compile_function(&this, node: &AST, func: &nodes::Function) {
372-
let compile_type: CompileType = if func.is_method then Method else Function
373364
let cc = Compiler::new(
374365
.vm,
375-
func.sym.name,
376-
func.sym.span,
377-
compile_type,
366+
func.sym,
367+
func.type,
378368
enclosing: this
379369
)
380370
cc.func.arity = func.params.size as u8
@@ -388,7 +378,11 @@ def Compiler::compile_function(&this, node: &AST, func: &nodes::Function) {
388378
cc.compile_statement(func.body)
389379

390380
// Add a placeholder return statement if none was provided
391-
cc.chunk.push_with_literal(.vm, Constant, Value::Null(), node.span)
381+
if func.type == Constructor {
382+
cc.chunk.push_with_arg_u16(GetLocal, 0, node.span)
383+
} else {
384+
cc.chunk.push_with_literal(.vm, Constant, Value::Null(), node.span)
385+
}
392386
cc.chunk.push_op(Return, node.span)
393387
cc.end_scope(func.sym.span)
394388

@@ -455,6 +449,8 @@ def Compiler::compile_statement(&this, node: &AST) {
455449
let method_name = .make_str(method.sym.name)
456450
.chunk.push_with_literal(.vm, Method, method_name, method.sym.span)
457451
}
452+
453+
.chunk.push_op(Pop, sym.span)
458454
}
459455
If => .compile_if(node, is_expression: false)
460456
While => {
@@ -524,7 +520,7 @@ def Compiler::compile_ns(&this, root: &AST) {
524520

525521
// TODO: More complex structures than just expressions?
526522
def compile_program(vm: &VM, root: &AST): &FunctionCode {
527-
let compiler = Compiler::new(vm, SV("",0), root.span, Script)
523+
let compiler = Compiler::new(vm, root.u.ns.sym, Script)
528524
compiler.compile_ns(root)
529525
compiler.chunk.push_op(Halt, root.span)
530526
gc::set_compiler(null)

compiler/main.oc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ def main(argc: i32, argv: &str) {
9191
let vm = VM::make()
9292
gc::set_vm(&vm)
9393
gc::state::paused = false
94+
9495
let script = compile_program(&vm, ast)
9596

9697
if debug {

compiler/parser.oc

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ def Parser::parse_atom(&this, end_type: TokenType): &AST {
522522
}
523523
Dot => {
524524
let tok = .consume(Dot)
525-
if not .cur_func? or not .cur_func.is_method {
525+
if not .cur_func? or (.cur_func.type != Method and .cur_func.type != Constructor) {
526526
.error(Error::new(tok.span, "Cannot use dot shorthand outside of a method"))
527527
return AST::new(Error, tok.span)
528528
}
@@ -1005,7 +1005,7 @@ def Parser::parse_class(&this): &AST {
10051005
}
10061006

10071007
while not .token_is_eof_or(CloseCurly) {
1008-
let method = .parse_function(is_method: true)
1008+
let method = .parse_function(Method)
10091009
if method? node.u.class.methods.push(method)
10101010
}
10111011

@@ -1052,7 +1052,7 @@ def Parser::parse_statement(&this): &AST {
10521052

10531053
match .token().type {
10541054
OpenCurly => node = .parse_block()
1055-
Def => node = .parse_function(is_method: false)
1055+
Def => node = .parse_function(Function)
10561056
Class => node = .parse_class()
10571057
Return => {
10581058
.consume(Return)
@@ -1193,12 +1193,16 @@ def Parser::parse_function_body(&this): &AST => match .token().type {
11931193
else => .parse_block()
11941194
}
11951195

1196-
def Parser::parse_function(&this, is_method: bool): &AST {
1196+
def Parser::parse_function(&this, type: FunctionType): &AST {
11971197
let start = .consume(Def)
11981198

11991199
let name = .consume(Identifier)
12001200

1201-
let func = Function::new()
1201+
if type == Method and name.text == "init" {
1202+
type = Constructor
1203+
}
1204+
1205+
let func = Function::new(type)
12021206
let node = AST::new(Function, start.span.join(name.span))
12031207
node.u.func = func
12041208

@@ -1220,7 +1224,6 @@ def Parser::parse_function(&this, is_method: bool): &AST {
12201224
}
12211225
let end_span = .consume(CloseParen).span
12221226

1223-
func.is_method = is_method
12241227
.cur_func = func
12251228

12261229
let body = .parse_function_body()

compiler/vm/gc.oc

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ def gc_mem(old: untyped_ptr, new_size: u32): untyped_ptr {
4141
// [ xxxxxxxx | ........ ........ ........ ........ ........ ]
4242
// ^ ^
4343
// 8 byte size Pointer to actual memory return from this function
44-
4544
let old_base = if old? then old - 8 else null
4645
let old_size = if old? then *(old_base as &u64) else 0u64
46+
if ALLOC_DEBUG then println(f"[GC MEM] Requested {new_size} bytes, old_ptr: {old}")
4747

4848
if old_size < new_size as u64 and not state::paused {
4949
if bytes_allocated > next_gc or STRESS_GC {
@@ -55,15 +55,18 @@ def gc_mem(old: untyped_ptr, new_size: u32): untyped_ptr {
5555
// free
5656
if new_size == 0 {
5757
mem::impl::free(old_base)
58-
if ALLOC_DEBUG then println(f"[GC] Deleted {old_size} bytes from {bytes_allocated} bytes allocated")
58+
if ALLOC_DEBUG then println(f"[GC MEM] Deleted {old_size} bytes from {bytes_allocated} bytes allocated, {old}")
5959
bytes_allocated -= old_size as u64
6060
return null
6161
}
6262

6363
// alloc / realloc
64-
let new_base = mem::impl::realloc(old_base, new_size + 8)
64+
let new_base = match old_size {
65+
0 => mem::impl::calloc(1, new_size + 8),
66+
else => mem::impl::realloc(old_base, new_size + 8)
67+
}
6568
bytes_allocated += new_size as u64 - old_size as u64
66-
if ALLOC_DEBUG then println(f"[GC] Reallocated {old_size} -> {new_size} bytes, total: {bytes_allocated} bytes allocated")
69+
if ALLOC_DEBUG then println(f"[GC MEM] Reallocated {old_size} -> {new_size} bytes, total: {bytes_allocated} bytes allocated, res={new_base+8}")
6770
*(new_base as &u64) = new_size as u64
6871
return new_base + 8
6972
}
@@ -78,7 +81,7 @@ def initialize_gc_allocator() {
7881
if stress_gc? {
7982
STRESS_GC = true
8083
}
81-
mem::set_allocator(null, gc_alloc, gc_free, gc_realloc)
84+
mem::set_allocator(null, gc_alloc, gc_free)
8285
}
8386

8487
/////
@@ -93,6 +96,7 @@ let num_garbage_collections: u32 = 0
9396
//!
9497
//! Precondition: First field of `T` must be a `Object` field.
9598
def allocate_object<T>(type: ObjectType, vm: &VM, compiler: &Compiler = null): &T {
99+
if GC_DEBUG then println(f"[GC] Requesting allocation of object {type}")
96100
let res = mem::alloc<T>()
97101
res.obj.type = type
98102
res.obj.next = vm.objects
@@ -187,6 +191,10 @@ def GarbageCollector::mark_roots(&this) {
187191
.mark_value(value)
188192
}
189193

194+
for value in .vm.tmp.iter() {
195+
.mark_value(value)
196+
}
197+
190198
.mark_object(&.vm.func.obj)
191199
for frame in .vm.frames.iter() {
192200
.mark_object(&frame.func.obj)
@@ -201,10 +209,13 @@ def GarbageCollector::mark_roots(&this) {
201209
.mark_value(it.value)
202210
}
203211

212+
.mark_object(&.vm.init_string.obj)
213+
204214
.mark_compiler_roots()
205215
}
206216

207217
def GarbageCollector::blacken_object(&this, obj: &Object) {
218+
if not obj? return
208219
if GC_DEBUG {
209220
print(`[GC] Blackening object {obj} : `)
210221
obj.print()
@@ -225,7 +236,7 @@ def GarbageCollector::blacken_object(&this, obj: &Object) {
225236
Class => {
226237
let c = obj as &Class
227238
.mark_object(&c.name.obj)
228-
if c.methods? {
239+
if c.methods? and c.methods.items? {
229240
for it in c.methods.items.iter() {
230241
.mark_object(&it.key.obj)
231242
.mark_object(&it.value.obj)

0 commit comments

Comments
 (0)