native: initial support for `defer` (#14779)
parent
10051e005a
commit
e0310964d9
|
@ -1903,7 +1903,7 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
|
|||
fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
|
||||
g.push(.rbp)
|
||||
g.mov_rbp_rsp()
|
||||
locals_count := node.scope.objects.len + node.params.len
|
||||
locals_count := node.scope.objects.len + node.params.len + node.defer_stmts.len
|
||||
g.stackframe_size = (locals_count * 8) + 0x10
|
||||
g.sub8(.rsp, g.stackframe_size)
|
||||
|
||||
|
@ -1917,6 +1917,11 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
|
|||
offset += 4
|
||||
g.mov_reg_to_var(offset, native.fn_arg_registers[i])
|
||||
}
|
||||
// define defer vars
|
||||
for i in 0 .. node.defer_stmts.len {
|
||||
name := '_defer$i'
|
||||
g.allocate_var(name, 8, 0)
|
||||
}
|
||||
//
|
||||
g.stmts(node.stmts)
|
||||
is_main := node.name == 'main.main'
|
||||
|
@ -1930,6 +1935,24 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
|
|||
// g.leave()
|
||||
g.labels.addrs[0] = g.pos()
|
||||
g.println('; label 0: return')
|
||||
if g.defer_stmts.len != 0 {
|
||||
// save return value
|
||||
g.push(.rax)
|
||||
for defer_stmt in g.defer_stmts.reverse() {
|
||||
defer_var := g.get_var_offset('_defer$defer_stmt.idx_in_fn')
|
||||
g.mov_var_to_reg(.rax, defer_var)
|
||||
g.cmp_zero(.rax)
|
||||
label := g.labels.new_label()
|
||||
jump_addr := g.cjmp(.je)
|
||||
g.labels.patches << LabelPatch{
|
||||
id: label
|
||||
pos: jump_addr
|
||||
}
|
||||
g.stmts(defer_stmt.stmts)
|
||||
g.labels.addrs[label] = g.pos()
|
||||
}
|
||||
g.pop(.rax)
|
||||
}
|
||||
g.add8(.rsp, g.stackframe_size)
|
||||
g.pop(.rbp)
|
||||
g.ret()
|
||||
|
|
|
@ -48,6 +48,7 @@ mut:
|
|||
callpatches []CallPatch
|
||||
strs []String
|
||||
labels &LabelTable
|
||||
defer_stmts []ast.DeferStmt
|
||||
}
|
||||
|
||||
enum RelocType {
|
||||
|
@ -71,11 +72,10 @@ struct CallPatch {
|
|||
|
||||
struct LabelTable {
|
||||
mut:
|
||||
label_id int
|
||||
return_ids []int = [0] // array is for defer
|
||||
addrs []i64 = [i64(0)] // register address of label here
|
||||
patches []LabelPatch // push placeholders
|
||||
branches []BranchLabel
|
||||
label_id int
|
||||
addrs []i64 = [i64(0)] // register address of label here
|
||||
patches []LabelPatch // push placeholders
|
||||
branches []BranchLabel
|
||||
}
|
||||
|
||||
struct LabelPatch {
|
||||
|
@ -489,6 +489,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
|||
g.stack_var_pos = 0
|
||||
g.register_function_address(node.name)
|
||||
g.labels = &LabelTable{}
|
||||
g.defer_stmts.clear()
|
||||
if g.pref.arch == .arm64 {
|
||||
g.fn_decl_arm64(node)
|
||||
} else {
|
||||
|
@ -678,6 +679,12 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
}
|
||||
}
|
||||
ast.ConstDecl {}
|
||||
ast.DeferStmt {
|
||||
defer_var := g.get_var_offset('_defer$g.defer_stmts.len')
|
||||
g.mov_int_to_var(defer_var, ._8, 1)
|
||||
g.defer_stmts << node
|
||||
g.defer_stmts[g.defer_stmts.len - 1].idx_in_fn = g.defer_stmts.len - 1
|
||||
}
|
||||
ast.ExprStmt {
|
||||
g.expr(node.expr)
|
||||
}
|
||||
|
@ -714,6 +721,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
// dump(node)
|
||||
// dump(node.types)
|
||||
mut s := '?' //${node.exprs[0].val.str()}'
|
||||
// TODO: void return
|
||||
e0 := node.exprs[0]
|
||||
match e0 {
|
||||
ast.IntegerLiteral {
|
||||
|
@ -740,7 +748,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
}
|
||||
|
||||
// jump to return label
|
||||
label := g.labels.return_ids.last()
|
||||
label := 0
|
||||
pos := g.jmp(0)
|
||||
g.labels.patches << LabelPatch{
|
||||
id: label
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
fn defer_test() {
|
||||
println('normal1')
|
||||
defer {
|
||||
println('defer1')
|
||||
}
|
||||
defer {
|
||||
println('defer2')
|
||||
}
|
||||
println('normal2')
|
||||
}
|
||||
|
||||
fn defer_condition_test(i int) {
|
||||
if i > 3 {
|
||||
defer {
|
||||
println('defer1')
|
||||
}
|
||||
} else {
|
||||
defer {
|
||||
println('defer2')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn defer_return_test() int {
|
||||
mut i := 1
|
||||
defer {
|
||||
i = 3
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
fn main() {
|
||||
defer_test()
|
||||
defer_condition_test(1)
|
||||
defer_condition_test(6)
|
||||
a := defer_return_test()
|
||||
println(a)
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
normal1
|
||||
normal2
|
||||
defer2
|
||||
defer1
|
||||
defer2
|
||||
defer1
|
||||
1
|
Loading…
Reference in New Issue