Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use Collections | |
| 3 | ||
| 4 | use Field = Semantic.Symbols.Field | |
| 5 | use Node = Trees.Node | |
| 6 | ||
| 7 | // The state-machine frame field a composite value expression (a | |
| 8 | // `val ... lav`, or an `if` / `case` / statement list in expression | |
| 9 | // position) routes its result through when its body suspends. | |
| 10 | // | |
| 11 | // Recorded by compile-expressions and read by IL generation, which | |
| 12 | // treats the presence of an entry as the decision to spill: a | |
| 13 | // composite with no entry here captures its value inline instead. | |
| 14 | // The field has to be declared here rather than where it is used, | |
| 15 | // because the emitter runs after the pass that fixes which rows the | |
| 16 | // assembly contains, and a field invented later has no row. | |
| 17 | // | |
| 18 | // Entries are keyed by (file name, node id), not node object | |
| 19 | // identity - see Node.node_id. Ids are never reused, so an entry | |
| 20 | // orphaned by tree replacement can go stale but can never be | |
| 21 | // served for a different node. | |
| 22 | class COMPOSITE_SPILL_STORE: NodeStateStore is | |
| 23 | _field_by_file: MutableMap[string, MutableMap[int, Field]] | |
| 24 | ||
| 25 | name: string => "composite-spill" | |
| 26 | ||
| 27 | entry_count: int => _count_entries() | |
| 28 | ||
| 29 | init(registry: STATE_STORE_REGISTRY) is | |
| 30 | _field_by_file = MAP[string, MutableMap[int, Field]]() | |
| 31 | ||
| 32 | registry.register(self) | |
| 33 | si | |
| 34 | ||
| 35 | // The frame field recorded for `node`, or null when the | |
| 36 | // composite is not spilling. | |
| 37 | get(node: Node) -> Field? is | |
| 38 | let by_node: MutableMap[int, Field] mut | |
| 39 | ||
| 40 | if !_field_by_file.try_get_value(node.location.file_name, by_node ref) then | |
| 41 | return null | |
| 42 | fi | |
| 43 | ||
| 44 | let result: Field mut | |
| 45 | ||
| 46 | if by_node.try_get_value(node.node_id, result ref) then | |
| 47 | return result | |
| 48 | fi | |
| 49 | ||
| 50 | return null | |
| 51 | si | |
| 52 | ||
| 53 | set(node: Node, `field: Field) is | |
| 54 | let file_name = node.location.file_name | |
| 55 | ||
| 56 | let by_node: MutableMap[int, Field] mut | |
| 57 | ||
| 58 | if !_field_by_file.try_get_value(file_name, by_node ref) then | |
| 59 | by_node = MAP[int, Field]() | |
| 60 | _field_by_file[file_name] = by_node | |
| 61 | fi | |
| 62 | ||
| 63 | by_node[node.node_id] = `field | |
| 64 | si | |
| 65 | ||
| 66 | // Forgets the field recorded for `node`, if any. | |
| 67 | remove(node: Node) is | |
| 68 | let by_node: MutableMap[int, Field] mut | |
| 69 | ||
| 70 | if _field_by_file.try_get_value(node.location.file_name, by_node ref) then | |
| 71 | by_node.remove(node.node_id) | |
| 72 | fi | |
| 73 | si | |
| 74 | ||
| 75 | // Forgets every field `owner` declared, across all files: a | |
| 76 | // state-machine frame that has been dropped and rebuilt leaves | |
| 77 | // fields nothing will emit. | |
| 78 | drop_owned_by(owner: Semantic.Symbols.Symbol) is | |
| 79 | for by_node in _field_by_file.values do | |
| 80 | let stale = LIST[int]() | |
| 81 | ||
| 82 | for (node_id, `field) in by_node do | |
| 83 | if `field.owner == owner then | |
| 84 | stale.add(node_id) | |
| 85 | fi | |
| 86 | od | |
| 87 | ||
| 88 | for node_id in stale do | |
| 89 | by_node.remove(node_id) | |
| 90 | od | |
| 91 | od | |
| 92 | si | |
| 93 | ||
| 94 | drop_file(file_name: string) is | |
| 95 | _field_by_file.remove(file_name) | |
| 96 | si | |
| 97 | ||
| 98 | clear_all() is | |
| 99 | _field_by_file = MAP[string, MutableMap[int, Field]]() | |
| 100 | si | |
| 101 | ||
| 102 | _count_entries() -> int is | |
| 103 | let result mut = 0 | |
| 104 | ||
| 105 | for by_node in _field_by_file.values do | |
| 106 | result = result + by_node.count | |
| 107 | od | |
| 108 | ||
| 109 | return result | |
| 110 | si | |
| 111 | si | |
| 112 | si |