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) {
|
fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
|
||||||
g.push(.rbp)
|
g.push(.rbp)
|
||||||
g.mov_rbp_rsp()
|
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.stackframe_size = (locals_count * 8) + 0x10
|
||||||
g.sub8(.rsp, g.stackframe_size)
|
g.sub8(.rsp, g.stackframe_size)
|
||||||
|
|
||||||
|
@ -1917,6 +1917,11 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
|
||||||
offset += 4
|
offset += 4
|
||||||
g.mov_reg_to_var(offset, native.fn_arg_registers[i])
|
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)
|
g.stmts(node.stmts)
|
||||||
is_main := node.name == 'main.main'
|
is_main := node.name == 'main.main'
|
||||||
|
@ -1930,6 +1935,24 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
|
||||||
// g.leave()
|
// g.leave()
|
||||||
g.labels.addrs[0] = g.pos()
|
g.labels.addrs[0] = g.pos()
|
||||||
g.println('; label 0: return')
|
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.add8(.rsp, g.stackframe_size)
|
||||||
g.pop(.rbp)
|
g.pop(.rbp)
|
||||||
g.ret()
|
g.ret()
|
||||||
|
|
|
@ -48,6 +48,7 @@ mut:
|
||||||
callpatches []CallPatch
|
callpatches []CallPatch
|
||||||
strs []String
|
strs []String
|
||||||
labels &LabelTable
|
labels &LabelTable
|
||||||
|
defer_stmts []ast.DeferStmt
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RelocType {
|
enum RelocType {
|
||||||
|
@ -72,7 +73,6 @@ struct CallPatch {
|
||||||
struct LabelTable {
|
struct LabelTable {
|
||||||
mut:
|
mut:
|
||||||
label_id int
|
label_id int
|
||||||
return_ids []int = [0] // array is for defer
|
|
||||||
addrs []i64 = [i64(0)] // register address of label here
|
addrs []i64 = [i64(0)] // register address of label here
|
||||||
patches []LabelPatch // push placeholders
|
patches []LabelPatch // push placeholders
|
||||||
branches []BranchLabel
|
branches []BranchLabel
|
||||||
|
@ -489,6 +489,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||||
g.stack_var_pos = 0
|
g.stack_var_pos = 0
|
||||||
g.register_function_address(node.name)
|
g.register_function_address(node.name)
|
||||||
g.labels = &LabelTable{}
|
g.labels = &LabelTable{}
|
||||||
|
g.defer_stmts.clear()
|
||||||
if g.pref.arch == .arm64 {
|
if g.pref.arch == .arm64 {
|
||||||
g.fn_decl_arm64(node)
|
g.fn_decl_arm64(node)
|
||||||
} else {
|
} else {
|
||||||
|
@ -678,6 +679,12 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.ConstDecl {}
|
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 {
|
ast.ExprStmt {
|
||||||
g.expr(node.expr)
|
g.expr(node.expr)
|
||||||
}
|
}
|
||||||
|
@ -714,6 +721,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
// dump(node)
|
// dump(node)
|
||||||
// dump(node.types)
|
// dump(node.types)
|
||||||
mut s := '?' //${node.exprs[0].val.str()}'
|
mut s := '?' //${node.exprs[0].val.str()}'
|
||||||
|
// TODO: void return
|
||||||
e0 := node.exprs[0]
|
e0 := node.exprs[0]
|
||||||
match e0 {
|
match e0 {
|
||||||
ast.IntegerLiteral {
|
ast.IntegerLiteral {
|
||||||
|
@ -740,7 +748,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// jump to return label
|
// jump to return label
|
||||||
label := g.labels.return_ids.last()
|
label := 0
|
||||||
pos := g.jmp(0)
|
pos := g.jmp(0)
|
||||||
g.labels.patches << LabelPatch{
|
g.labels.patches << LabelPatch{
|
||||||
id: label
|
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