Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use IO.Std | |
| 3 | ||
| 4 | use Function = Semantic.Symbols.Function | |
| 5 | use Symbol = Semantic.Symbols.Symbol | |
| 6 | ||
| 7 | // Env-gated measurement reporting for the narrowing analysis. | |
| 8 | // | |
| 9 | // GHUL_NARROWING_STUDY names the file the report is written to; | |
| 10 | // unset, nothing here runs. Reporting-only: nothing in this class | |
| 11 | // alters what the compiler concludes or reports. The report has | |
| 12 | // two sections - a tally of the opaque function-value shapes that | |
| 13 | // make a parameter invocation unboundable, and a per-function | |
| 14 | // table of the effect facts the solve worked from. | |
| 15 | class NARROWING_STUDY is | |
| 16 | ||
| 17 | _enabled: bool static | |
| 18 | _enabled_known: bool static | |
| 19 | ||
| 20 | // Path the report is written to, or null. | |
| 21 | _path: string? static | |
| 22 | ||
| 23 | enabled: bool static is | |
| 24 | if !_enabled_known then | |
| 25 | _path = System.Environment.get_environment_variable("GHUL_NARROWING_STUDY") | |
| 26 | _enabled = _path? /\ _path.length > 0 | |
| 27 | _enabled_known = true | |
| 28 | fi | |
| 29 | ||
| 30 | return _enabled | |
| 31 | si | |
| 32 | ||
| 33 | // ==== opaque function-value shapes ==== | |
| 34 | // | |
| 35 | // A function-typed argument whose value cannot be traced to a | |
| 36 | // set of concrete functions makes the receiving parameter's | |
| 37 | // invocation unboundable. The tally names the value shapes | |
| 38 | // responsible, which is what argues for (or against) tracing | |
| 39 | // more of them. | |
| 40 | _opaque_shapes: Collections.MutableMap[string, int]? static | |
| 41 | ||
| 42 | opaque_shapes: Collections.MutableMap[string, int] static is | |
| 43 | if !_opaque_shapes? then | |
| 44 | _opaque_shapes = Collections.MAP[string, int]() | |
| 45 | fi | |
| 46 | ||
| 47 | return _opaque_shapes | |
| 48 | si | |
| 49 | ||
| 50 | note_opaque_shape(shape: string) static is | |
| 51 | if !enabled then | |
| 52 | return | |
| 53 | fi | |
| 54 | ||
| 55 | if opaque_shapes.contains_key(shape) then | |
| 56 | opaque_shapes[shape] = opaque_shapes[shape] + 1 | |
| 57 | else | |
| 58 | opaque_shapes[shape] = 1 | |
| 59 | fi | |
| 60 | si | |
| 61 | ||
| 62 | report() static is | |
| 63 | if !enabled \/ !_path? then | |
| 64 | return | |
| 65 | fi | |
| 66 | ||
| 67 | try | |
| 68 | let writer = IO.StreamWriter(_path) | |
| 69 | ||
| 70 | for key in opaque_shapes.keys do | |
| 71 | writer.write_line("opaque_shape\t{key}\t{opaque_shapes[key]}") | |
| 72 | od | |
| 73 | ||
| 74 | writer.write_line( | |
| 75 | "# role\towner\tname\tstore_free\tdisqualified\taliased\t" | |
| 76 | "own_stores\town_unbounded\tcallees\toverriders\topenly_dispatchable\t" | |
| 77 | "declared_pure\treason\tlocation") | |
| 78 | ||
| 79 | for function in EFFECT_FACTS.records.keys do | |
| 80 | let r = EFFECT_FACTS.records[function] | |
| 81 | ||
| 82 | writer.write_line( | |
| 83 | "{r.role}\t{r.owner_name}\t{r.name}\t" | |
| 84 | "{function.is_store_free}\t" | |
| 85 | "{r.is_disqualified}\t{r.aliased}\t" | |
| 86 | "{r.own_stores}\t{r.own_unbounded}\t{r.callee_count}\t{r.overrider_count}\t" | |
| 87 | "{r.openly_dispatchable}\t{r.declared_pure}\t" | |
| 88 | "{r.unbounded_reason}\t" | |
| 89 | "{r.location}") | |
| 90 | od | |
| 91 | ||
| 92 | writer.flush() | |
| 93 | writer.close() | |
| 94 | catch ex: System.Exception | |
| 95 | IO.Std.error.write_line("narrowing study: report failed: {ex}") | |
| 96 | yrt | |
| 97 | si | |
| 98 | si | |
| 99 | si |