Skip to content
← Back

src/ir/values/load/function_pointer.ghul

1
namespace IR.Values.Load is
2
use IO.Std
3
4
use System.NotImplementedException
5
use System.Text.StringBuilder
6
7
use TypeTyped = Semantic.Types.Typed
8
use Semantic.Types.Type
9
use SymbolBase = Semantic.Symbols.Symbol
10
11
// The cast to the symbol's expected kind is a checked construction
12
// invariant: the caller only ever builds this value with a symbol of
13
// that kind, so a throw here means the invariant broke elsewhere.
14
@suppress("cast-may-throw")
15
class FUNCTION_POINTER: SYMBOL, TypeTyped is
16
has_address: bool => false
17
is_consumable: bool => true
18
19
// True when this pointer must dispatch virtually - a real
20
// override could sit behind the statically-known symbol at
21
// the receiver's runtime type, and a plain `ldftn` always
22
// captures the statically-resolved implementation. Only ever
23
// true for a function reference bound to a live receiver
24
// (FUNCTION_REFERENCE_RESOLVER); a closure's own synthesized
25
// method is never virtual, so every other caller passes false.
26
is_virtual: bool
27
is_virtual_dispatch: bool => is_virtual
28
29
init(symbol: Semantic.Symbols.Symbol) is
30
init(symbol, false)
31
si
32
33
init(symbol: Semantic.Symbols.Symbol, is_virtual: bool) is
34
super.init(null, symbol)
35
36
self.is_virtual = is_virtual
37
si
38
39
referenced_function: Semantic.Symbols.Function? =>
40
cast Semantic.Symbols.Function?(symbol)
41
42
gen(context: IR.CONTEXT) is
43
let opcode = if is_virtual then "ldvirtftn" else "ldftn" fi
44
45
let body = context.current_srm_body_emitter!
46
let target = context.resolve_call_target(cast Semantic.Symbols.Function(symbol))
47
48
if is_virtual then
49
body.load_virtual_function_pointer(target)
50
else
51
body.load_function_pointer(target)
52
fi
53
si
54
55
to_string() -> string =>
56
"function:[{type}](\"{symbol.name}\")"
57
si
58
si