Merge branch 'lang/memory-owned' into lang/foundations
This commit is contained in:
commit
f16ac4ef9e
6 changed files with 74859 additions and 72140 deletions
|
|
@ -229,6 +229,7 @@ function deps_keeps(f: pointer, seen: []bool) -> void {
|
|||
if g_arena_strict and n > 0 { exit(1) }
|
||||
deps_births(f, seen)
|
||||
deps_resources(f) # 25.5e
|
||||
deps_owned(f)
|
||||
}
|
||||
|
||||
function fr_consumed(n: Node) -> bool {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ var g_res_free_fn: []pointer = new []pointer
|
|||
var g_res_free_kind: []pointer = new []pointer
|
||||
var g_res_pending_make: pointer = null
|
||||
var g_res_pending_free: pointer = null
|
||||
var g_own_type: []pointer = new []pointer # @owns(Kind) fields: the record's type ...
|
||||
var g_own_field: []pointer = new []pointer # ... the field ...
|
||||
var g_own_kind: []pointer = new []pointer # ... and the kind of handle it owns
|
||||
var g_own_pending: pointer = null
|
||||
|
||||
function res_kind_made_by(name: pointer) -> pointer {
|
||||
var i = 0
|
||||
|
|
@ -98,3 +102,86 @@ function deps_resources(f: pointer) -> void {
|
|||
}
|
||||
deps_line(f, `resource_drops {itoa(g_res_drops)}`)
|
||||
}
|
||||
|
||||
function res_is_release(name: pointer) -> bool {
|
||||
var i = 0
|
||||
while i < len(g_res_free_fn) { if (g_res_free_fn[i] == name) { return true }; i += 1 }
|
||||
return false
|
||||
}
|
||||
|
||||
# every `base.field` handed to a call in n: into rel when the callee @releases, into all always
|
||||
function own_collect(n: Node, rel_b: []pointer, rel_f: []pointer, all_b: []pointer, all_f: []pointer, rel_line: []int) -> void {
|
||||
if n == null { return }
|
||||
if n.kind == E_CALL and n.a != null and n.a.kind == E_ID and n.kids != null {
|
||||
let releasing = res_is_release(n.a.s)
|
||||
var i = 0
|
||||
while i < len(n.kids) {
|
||||
let a = n.kids[i]
|
||||
if a != null and a.kind == E_MEMBER and a.a != null and a.a.kind == E_ID and a.s != null {
|
||||
push(all_b, a.a.s)
|
||||
push(all_f, a.s)
|
||||
if releasing {
|
||||
push(rel_b, a.a.s)
|
||||
push(rel_f, a.s)
|
||||
push(rel_line, n.line)
|
||||
}
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
own_collect(n.a, rel_b, rel_f, all_b, all_f, rel_line)
|
||||
own_collect(n.b, rel_b, rel_f, all_b, all_f, rel_line)
|
||||
own_collect(n.c, rel_b, rel_f, all_b, all_f, rel_line)
|
||||
if n.kids != null {
|
||||
var j = 0
|
||||
while j < len(n.kids) { own_collect(n.kids[j], rel_b, rel_f, all_b, all_f, rel_line); j += 1 }
|
||||
}
|
||||
}
|
||||
|
||||
function own_has(bs: []pointer, fs: []pointer, b: pointer, f: pointer) -> bool {
|
||||
var i = 0
|
||||
while i < len(bs) { if (bs[i] == b) and (fs[i] == f) { return true }; i += 1 }
|
||||
return false
|
||||
}
|
||||
|
||||
# 25.5e's owned fields: a function that releases one @owns field of a record (x.body) and neither
|
||||
# releases nor hands on another @owns field of the same record type (x.shape) gives the first back
|
||||
# and loses the second - phys_remove freeing the body and not its shape. `oleak` lines, owned_leaks
|
||||
var g_own_leaks: int = 0
|
||||
function deps_owned(f: pointer) -> void {
|
||||
g_own_leaks = 0
|
||||
if len(g_own_field) > 0 {
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
let d = prog[i]
|
||||
if (d.kind == N_FN or d.kind == N_SYS) and d.file != null and not is_runtime_file(d.file) {
|
||||
let rb = new []pointer
|
||||
let rf = new []pointer
|
||||
let rl = new []int
|
||||
let ab = new []pointer
|
||||
let af = new []pointer
|
||||
own_collect(d.a, rb, rf, ab, af, rl)
|
||||
var r = 0
|
||||
while r < len(rb) {
|
||||
var t = 0
|
||||
while t < len(g_own_field) {
|
||||
if (g_own_field[t] == rf[r]) {
|
||||
var o = 0
|
||||
while o < len(g_own_field) {
|
||||
if o != t and (g_own_type[o] == g_own_type[t]) and not own_has(ab, af, rb[r], g_own_field[o]) {
|
||||
deps_line(f, `oleak {g_own_type[o]}.{g_own_field[o]} {d.file}:{itoa(rl[r])} {d.s} {rb[r]}.{rf[r]}`)
|
||||
g_own_leaks += 1
|
||||
}
|
||||
o += 1
|
||||
}
|
||||
}
|
||||
t += 1
|
||||
}
|
||||
r += 1
|
||||
}
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
deps_line(f, `owned_leaks {itoa(g_own_leaks)}`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@ function parse_component() -> Node {
|
|||
pi += 1
|
||||
let ann = eat_id()
|
||||
if ann == "Computed" { is_computed = true } else if ann == "Sync" { is_sync = true } else if ann == "frame" { is_frame = true }
|
||||
else if ann == "owns" { # @owns(PhysShape) — this field holds a handle its record owns (25.5e)
|
||||
eat_op("(")
|
||||
g_own_pending = eat_id()
|
||||
eat_op(")")
|
||||
}
|
||||
else if ann == "max" {
|
||||
eat_op("(")
|
||||
let ce = expr()
|
||||
|
|
@ -27,6 +32,7 @@ function parse_component() -> Node {
|
|||
let f = node(N_FIELD); f.s = eat_id(); eat_op(":"); f.ty = ptype()
|
||||
if is_frame { push(g_frame_fields, `{n.s}.{f.s}`) }
|
||||
if cap > 0 { push(g_cap_keys, `{n.s}.{f.s}`); push(g_cap_vals, cap) }
|
||||
if g_own_pending != null { push(g_own_type, n.s); push(g_own_field, f.s); push(g_own_kind, g_own_pending); g_own_pending = null }
|
||||
if is_op("=") { pi += 1; f.a = expr() }
|
||||
if is_sync { f.ival = 1 } # mark the field replicable (read by emit_net)
|
||||
if is_computed { register_computed(n.s, f.s, f.ty, f.a) } # derived: no storage
|
||||
|
|
|
|||
73459
selfhost/ludicc.seed.ll
73459
selfhost/ludicc.seed.ll
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -60,6 +60,8 @@ var dp_fbirths: []pointer = new []pointer # 25.2: `fbirth <kind> <file:l
|
|||
var dp_birth_leaks: int = 0
|
||||
var dp_rdrops: []pointer = new []pointer # 25.5e: `rdrop <kind> <file:line> <fn> <how>`
|
||||
var dp_resource_drops: int = 0
|
||||
var dp_oleaks: []pointer = new []pointer # 25.5e: `oleak <Type.field> <file:line> <fn> <released>`
|
||||
var dp_owned_leaks: int = 0
|
||||
var dp_wreach_n: int = 0
|
||||
var dp_wreach_at: pointer = ""
|
||||
|
||||
|
|
@ -102,6 +104,7 @@ function dp_load(path: pointer) -> bool {
|
|||
dp_fkeeps = new []pointer; dp_frame_keeps = 0
|
||||
dp_fbirths = new []pointer; dp_birth_leaks = 0
|
||||
dp_rdrops = new []pointer; dp_resource_drops = 0
|
||||
dp_oleaks = new []pointer; dp_owned_leaks = 0
|
||||
dp_writes = new []pointer; dp_aliases = new []pointer; dp_wowner = new []pointer; dp_wname = new []pointer; dp_wfrom = new []pointer
|
||||
let lines = split_lines(text)
|
||||
for i in 0 .. len(lines) {
|
||||
|
|
@ -131,6 +134,8 @@ function dp_load(path: pointer) -> bool {
|
|||
if len(w) == 2 and w[0] == "birth_leaks" { dp_birth_leaks = s_to_int(w[1]) }
|
||||
if len(w) >= 5 and w[0] == "rdrop" { push(dp_rdrops, lines[i]) }
|
||||
if len(w) == 2 and w[0] == "resource_drops" { dp_resource_drops = s_to_int(w[1]) }
|
||||
if len(w) >= 5 and w[0] == "oleak" { push(dp_oleaks, lines[i]) }
|
||||
if len(w) == 2 and w[0] == "owned_leaks" { dp_owned_leaks = s_to_int(w[1]) }
|
||||
if len(w) >= 5 and w[0] == "width" and w[4] == "0" and s_to_int(w[1]) > dp_wide_n {
|
||||
dp_wide_n = s_to_int(w[1])
|
||||
dp_wide_at = `{dp_fn_name(w[2])} ({w[3]})`
|
||||
|
|
@ -330,7 +335,7 @@ var dp_vals: []int = null
|
|||
var dp_cycle: []int = null
|
||||
var dp_cycle_all: []int = null # the same with the layers' own edges counted
|
||||
function dp_numbers() -> void {
|
||||
dp_names = ["modules", "dependencies", "largest_cycle", "cross_writes", "globals_written_from_outside", "widest_function", "widest_reach", "widest_write_reach", "frame_allocs", "frame_keeps", "birth_leaks", "resource_drops"]
|
||||
dp_names = ["modules", "dependencies", "largest_cycle", "cross_writes", "globals_written_from_outside", "widest_function", "widest_reach", "widest_write_reach", "frame_allocs", "frame_keeps", "birth_leaks", "resource_drops", "owned_leaks"]
|
||||
var mods = 0
|
||||
for k in 0 .. len(dp_mods) { if dp_own(k) { mods += 1 } }
|
||||
var deps = 0
|
||||
|
|
@ -352,7 +357,7 @@ function dp_numbers() -> void {
|
|||
}
|
||||
}
|
||||
dp_reach_best()
|
||||
dp_vals = [mods, deps, len(dp_cycle), writes, len(seen), dp_wide_n, dp_reach_n, dp_wreach_n, dp_frame_allocs, dp_frame_keeps, dp_birth_leaks, dp_resource_drops]
|
||||
dp_vals = [mods, deps, len(dp_cycle), writes, len(seen), dp_wide_n, dp_reach_n, dp_wreach_n, dp_frame_allocs, dp_frame_keeps, dp_birth_leaks, dp_resource_drops, dp_owned_leaks]
|
||||
}
|
||||
|
||||
# ---- the command --------------------------------------------------------------
|
||||
|
|
@ -510,6 +515,7 @@ function cmd_deps() -> int {
|
|||
else if a == "--keeps" { mode = "keeps" }
|
||||
else if a == "--births" { mode = "births" }
|
||||
else if a == "--resources" { mode = "resources" }
|
||||
else if a == "--owned" { mode = "resources" }
|
||||
else if a == "--uses" or a == "--check" or a == "--baseline" or a == "--widest" or a == "--reach" or a == "--wreach" {
|
||||
if ai + 1 >= arg_count() { err(`ludic deps: {a} needs an argument\n`); return 2 }
|
||||
mode = sslice(a, 2, slen(a))
|
||||
|
|
@ -583,6 +589,11 @@ function cmd_deps() -> int {
|
|||
print(`resource dropped: {w[1]} at {w[2]} in {w[3]}: {w[4]}`)
|
||||
}
|
||||
print(`resource_drops: {string(dp_resource_drops)}`)
|
||||
for a in 0 .. len(dp_oleaks) {
|
||||
let w = dp_words(dp_oleaks[a])
|
||||
print(`owned field lost: {w[1]} at {w[2]} in {w[3]}, which releases {w[4]}`)
|
||||
}
|
||||
print(`owned_leaks: {string(dp_owned_leaks)}`)
|
||||
return 0
|
||||
}
|
||||
if mode == "widest" { dp_top(s_to_int(arg2), 0); return 0 }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue