From b367ed9ba3d5e5c9ec92138c8f00c49b2e0ca13b Mon Sep 17 00:00:00 2001 From: pancake Date: Fri, 19 Nov 2021 09:25:42 +0100 Subject: [PATCH] native: support defining functions in any order (#12511) --- vlib/v/gen/native/amd64.v | 36 +++++++++++++++++++++++++++++++----- vlib/v/gen/native/gen.v | 13 ++++++++++--- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 63984b72af..d168dc86ca 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -778,10 +778,6 @@ pub fn (mut g Gen) call_fn(node ast.CallExpr) { n = 'main.$n' } addr := g.fn_addr[n] - if addr == 0 { - // g.warning('fn addr of `$name` = 0') - g.n_error('fn addr of `$name` = 0') - } // Copy values to registers (calling convention) // g.mov(.eax, 0) for i in 0 .. node.args.len { @@ -808,11 +804,41 @@ pub fn (mut g Gen) call_fn(node ast.CallExpr) { if node.args.len > 6 { g.v_error('more than 6 args not allowed for now', node.pos) } - g.call(int(addr)) + if addr == 0 { + g.delay_fn_call(name) + g.call(int(0)) + } else { + g.call(int(addr)) + } g.println('fn call `${name}()`') // println('call $name $addr') } +fn (mut g Gen) patch_calls() { + for c in g.callpatches { + addr := g.fn_addr[c.name] + if addr == 0 { + g.n_error('fn addr of `$c.name` = 0') + return + } + last := g.buf.len + g.call(int(addr + last - c.pos)) + mut patch := []byte{} + for last < g.buf.len { + patch << g.buf.pop() + } + for i := 0; i < patch.len; i++ { + g.buf[c.pos + i] = patch[patch.len - i - 1] + } + } +} + +fn (mut g Gen) delay_fn_call(name string) { + pos := g.buf.len + g.callpatches << CallPatch{name, pos} + // do nothing for now +} + fn (mut g Gen) assign_stmt(node ast.AssignStmt) { // `a := 1` | `a,b := 1,2` for i, left in node.left { diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 10cfcfb4d9..72ee00dfd1 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -44,9 +44,15 @@ mut: errors []errors.Error warnings []errors.Warning syms []Symbol - relocs []Reloc - size_pos []int - nlines int + // UNUSED relocs []Reloc + size_pos []int + nlines int + callpatches []CallPatch +} + +struct CallPatch { + name string + pos int } enum Size { @@ -141,6 +147,7 @@ pub fn (mut g Gen) create_executable() { } pub fn (mut g Gen) generate_footer() { + g.patch_calls() match g.pref.os { .macos { g.generate_macho_footer()