Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion graph/csharp/engine/call-edge-generation/call_chain.dl
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@ call_site_dropped(e) :- csite("client", e), !site_in_output(e).

// call_chain_summary(Tier, Count) -- the per-tier tally, which is the one number a
// run is judged on.
// One count per DISTINCT tier: driven by call_class rows, the aggregate re-counted the
// tier once per SITE in it (sites x tiers — 9.8s of a 36s solve for 7 rows, the single
// hottest rule of the C# profile). Same fix as the python engine's site_class_kind.
call_class_kind(cls) :- call_class("client", _, cls).
call_chain_summary(cls, n) :-
call_class("client", _, cls),
call_class_kind(cls),
n = count : { call_class("client", _, cls) }.
1 change: 1 addition & 0 deletions graph/csharp/souffle/decls_all.dl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
.decl call_callee_name(c0:symbol,c1:symbol,c2:symbol)
.decl call_caller_unknown(c0:symbol,c1:symbol)
.decl call_chain_edge(c0:symbol,c1:symbol,c2:symbol,c3:symbol,c4:symbol,c5:symbol,c6:symbol)
.decl call_class_kind(c0:symbol)
.decl call_chain_summary(c0:symbol,c1:number)
.decl call_class(c0:symbol,c1:symbol,c2:symbol)
.decl call_context(c0:symbol,c1:symbol,c2:symbol,c3:symbol,c4:symbol)
Expand Down
6 changes: 5 additions & 1 deletion graph/javascript/engine/resolution/instance-state.dl
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,14 @@ state_outer_carry(t, k2, i2, d + 1) :- state_outer_carry(t, k, i, d), d < 3, k !
state_outer_carry(t, k2, i2, d + 1) :- state_outer_carry(t, k, i, d), d < 3, (k = "arr" ; k = "coll"), elem_value(i, k2, i2), k2 != "alloc".
state_leak(t, f) :- state_enters(t, f, _), state_outer_carry(t, "func", f, _).
// written onto an instance of T or onto T itself from outside its instance code
state_leak(t, f) :- state_enters(t, f, _), expr_kind(_, "ASSIGNMENT", _, a), expr_owner(_, em, _, a), !state_world(em, t),
// The assignment side enumerated ONCE, keyed (t, f): anchored on state_enters the
// clause crossed every (type, entry) pair with every assignment in the program — 33s
// for 2 rows on the profile.
func_written_onto(t, f, em) :- expr_kind(_, "ASSIGNMENT", _, a), expr_owner(_, em, _, a),
expr_child(_, a, "ASSIGNMENT_TARGET", _, tgt), expr_child(_, tgt, "ACCESS_TARGET", _, r),
expr_value(r, k, t), (k = "inst" ; k = "ctor"),
expr_child(_, a, "ASSIGNMENT_VALUE", _, val), expr_value(val, "func", f).
state_leak(t, f) :- state_enters(t, f, _), func_written_onto(t, f, em), !state_world(em, t).
state_leak(t, f) :- state_enters(t, f, _), prop_value("ctor", t, _, "func", f).
// an entry that says nothing about which instance it gives F to
state_leak(t, f) :- state_enters(t, f, ce), state_entry_open(ce).
Expand Down
7 changes: 6 additions & 1 deletion graph/javascript/engine/resolution/value-flow.dl
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,13 @@ carry_step(x, c) :- expr_kind(_, "BINARY", _, x), expr_operator(_, op, x), binar
carry_step(x, c) :- expr_kind(_, "ASSIGNMENT", _, x), expr_child(_, x, "ASSIGNMENT_VALUE", _, c).
carry_step(x, c) :- expr_kind(_, "SEQUENCE", _, x), sequence_last(x, c).
carry_step(x, c) :- expr_binding(_, v, x), var_init(_, _, c, v).
carry_step(x, c) :- expr_binding(_, v, x), expr_kind(_, "ASSIGNMENT", _, a), expr_operator(_, op, a), assignment_op_writes_value(op),
// An assignment writing variable v the value c, KEYED BY THE VARIABLE and enumerated
// once. Anchored on expr_binding the clause below visited every USE of every variable
// and re-scanned the assignments for each: 3.1 minutes of a 6-minute solve, half the
// profile, for 16.5K rows.
var_assigned_value(v, c) :- expr_kind(_, "ASSIGNMENT", _, a), expr_operator(_, op, a), assignment_op_writes_value(op),
expr_child(_, a, "ASSIGNMENT_TARGET", _, tgt), expr_binding(_, v, tgt), expr_child(_, a, "ASSIGNMENT_VALUE", _, c).
carry_step(x, c) :- expr_binding(_, v, x), var_assigned_value(v, c).
carry_rest(e, x) :- carry_part(e, x), !carries_param_call(x, _).
// What the carrying return holds read context-insensitively: every caller's argument
// merged (and nothing once the wrapper is over the fan cap). Only the fallbacks below
Expand Down
2 changes: 2 additions & 0 deletions graph/javascript/souffle/decls_all.dl
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@
.decl wrapper_param_replaced(c0:symbol, c1:number)
.decl wrapper_param_written(c0:symbol, c1:number, c2:symbol)
.decl carry_part(c0:symbol, c1:symbol)
.decl var_assigned_value(c0:symbol,c1:symbol)
.decl carry_step(c0:symbol, c1:symbol)
.decl carry_rest(c0:symbol, c1:symbol)
.decl carried_value(c0:symbol, c1:symbol, c2:symbol)
Expand Down Expand Up @@ -598,6 +599,7 @@
.decl state_entry_open(c0:symbol)
.decl state_carry(c0:symbol, c1:symbol, c2:symbol, c3:number)
.decl state_enters(c0:symbol, c1:symbol, c2:symbol)
.decl func_written_onto(c0:symbol,c1:symbol,c2:symbol)
.decl state_leak(c0:symbol, c1:symbol)
.decl state_outer_ref(c0:symbol, c1:symbol)
.decl state_outer_carry(c0:symbol, c1:symbol, c2:symbol, c3:number)
Expand Down
9 changes: 7 additions & 2 deletions graph/python/engine/resolution/attribute-lookup.dl
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,15 @@ mro_lookup_data_shadow(p, t, n, f) :-
// factory), while mro_lookup is upstream of it and uses negation — folding this in makes
// that negation cyclic and souffle refuses the program. Consumed by
// expression-resolution/callee-resolution.dl, which is downstream of both.
// The class-member lookup is pure syntax and was re-run inside the fixpoint every
// iteration (12s for 783 rows on a mid-size subject); materialized once, keyed (c, n),
// the rule starts from its recursive delta and probes it.
replaced_method_of(p, c, n, def) :-
method_owner(p, c, def), method_decl(p, n, _, _, _, def),
method_target_replaced(p, def).
mro_lookup_decorated(p, t, n, r) :-
mro_winner(p, t, n, c),
method_owner(p, c, def), method_decl(p, n, _, _, _, def),
method_target_replaced(p, def),
replaced_method_of(p, c, n, def),
decorated_name_target(def, r).

// ── mro_lookup_opaque(Prov, ReceiverType, Name) ──────────────────────────────
Expand Down
3 changes: 1 addition & 2 deletions graph/python/engine/resolution/builtin-types.dl
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,7 @@ expr_container_annotation_ref(p, src, r) :-
// the same hop through ANY object whose type is known, not only self -- the fix that
// #61 / #63 had to make three times over in the other typing files.
expr_container_annotation_ref(p, src, r) :-
expr_node(p, "ATTRIBUTE_ACCESS", _, n, src), n != "",
expr_parent(p, src, "ATTRIBUTE_OBJECT", _, obj),
attr_access(p, src, n, obj),
expr_type(p, obj, ot), type_attr_field(p, ot, n, f),
type_ref_owner(p, f, "FIELD", r),
type_ref(p, _, "FIELD_TYPE", _, _, r).
Expand Down
27 changes: 15 additions & 12 deletions graph/python/engine/resolution/iteration.dl
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,19 @@ iter_pair(p, tgt, src) :-
for_statement_roots("FOR_TARGET", "FOR_ITERABLE").
for_statement_roots("ASYNC_FOR_TARGET", "ASYNC_FOR_ITERABLE").

// ── root_expr_at(Prov, RootContext, Scope, Line, Expr) — the pairing key, ONCE ──
// Both statement pairings below match a target root against a source root by scope and
// line; written inline, each pairing enumerated every root of one context and probed
// scope/span per candidate (22s between them for ~6K rows). Materialized with the key
// in the columns, each pairing is one indexed join.
root_expr_at(p, rc, s, line, e) :-
expr_root_context(p, rc, e), !expr_has_parent(p, e),
expr_scope(p, s, _, e), expr_span(p, line, _, e).

iter_pair(p, tgt, src) :-
for_statement_roots(trc, irc),
expr_root_context(p, trc, tgt), !expr_has_parent(p, tgt),
expr_root_context(p, irc, src), !expr_has_parent(p, src),
expr_scope(p, s, _, tgt), expr_scope(p, s, _, src),
expr_span(p, line, _, tgt), expr_span(p, line, _, src).
root_expr_at(p, trc, s, line, tgt),
root_expr_at(p, irc, s, line, src).

// ── with_pair(Prov, TargetExprHash, ContextExprHash) — `with X() as y` (#128) ──
// The SAME shape as a for statement, and it lives here for that reason: the parser emits
Expand All @@ -52,10 +59,8 @@ with_statement_roots("ASYNC_WITH_TARGET", "ASYNC_WITH_CONTEXT").

with_pair(p, tgt, cm) :-
with_statement_roots(trc, crc),
expr_root_context(p, trc, tgt), !expr_has_parent(p, tgt),
expr_root_context(p, crc, cm), !expr_has_parent(p, cm),
expr_scope(p, s, _, tgt), expr_scope(p, s, _, cm),
expr_span(p, line, _, tgt), expr_span(p, line, _, cm).
root_expr_at(p, trc, s, line, tgt),
root_expr_at(p, crc, s, line, cm).

// The two names this needs, stated as facts rather than written into a rule body: one is a
// dunder the language defines, the other the typing spelling for "the enclosing class".
Expand Down Expand Up @@ -125,14 +130,12 @@ element_type_of(p, src, t) :-
// self-only, here the ELEMENT type of a container held on an attribute is. The self
// clauses stay as the special case; nothing about what an element type means changes.
element_type_of(p, src, t) :-
expr_node(p, "ATTRIBUTE_ACCESS", _, n, src), n != "",
expr_parent(p, src, "ATTRIBUTE_OBJECT", _, obj),
attr_access(p, src, n, obj),
expr_type(p, obj, ot),
type_attr_field(p, ot, n, f),
field_declared_element(p, f, t).
element_type_of(p, src, t) :-
expr_node(p, "ATTRIBUTE_ACCESS", _, n, src), n != "",
expr_parent(p, src, "ATTRIBUTE_OBJECT", _, obj),
attr_access(p, src, n, obj),
expr_type(p, obj, ot),
type_attr_field(p, ot, n, f),
field_element_from_param(p, f, t).
Expand Down
6 changes: 2 additions & 4 deletions graph/python/engine/resolution/value-flow.dl
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,8 @@ type_attr_class_value(p, t, n, c) :-
// never a single edge to the assigned value. `self.x = ...` is left to the field rules,
// which see it with its write count.
instance_attr_method_value(p, t, n, m) :-
expr_node(p, "ATTRIBUTE_ACCESS", _, n, e), n != "",
attr_access(p, e, n, obj),
expr_name_context(p, "STORE", e),
expr_parent(p, e, "ATTRIBUTE_OBJECT", _, obj),
!expr_node(p, "SELF_REFERENCE", _, _, obj),
expr_type(p, obj, t),
assign_pair(p, e, val),
Expand All @@ -242,10 +241,9 @@ instance_attr_method_value(p, t, n, m) :-
// denotes what was assigned to it, beside the bound class method expr_denotes_bound_method
// already gives it.
expr_denotes_method(p, e, m) :-
expr_node(p, "ATTRIBUTE_ACCESS", _, n, e), n != "",
attr_access(p, e, n, obj),
!expr_name_context(p, "STORE", e),
!call_callee_expr(_, e),
expr_parent(p, e, "ATTRIBUTE_OBJECT", _, obj),
expr_type(p, obj, t),
instance_attr_method_value(p, t, n, m).

Expand Down
2 changes: 2 additions & 0 deletions graph/python/souffle/decls_all.dl
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@
.decl mro_tie(c0:symbol,c1:symbol,c2:symbol)
.decl mro_lookup(c0:symbol,c1:symbol,c2:symbol,c3:symbol)
.decl mro_lookup_data_shadow(c0:symbol,c1:symbol,c2:symbol,c3:symbol)
.decl replaced_method_of(c0:symbol,c1:symbol,c2:symbol,c3:symbol)
.decl mro_lookup_decorated(c0:symbol,c1:symbol,c2:symbol,c3:symbol)
.decl mro_lookup_opaque(c0:symbol,c1:symbol,c2:symbol)
.decl mro_definer_after(c0:symbol,c1:symbol,c2:symbol,c3:symbol,c4:symbol)
Expand Down Expand Up @@ -402,6 +403,7 @@
.decl method_owner_declares_param(c0:symbol,c1:symbol,c2:symbol)
.decl call_returns_type(c0:symbol,c1:symbol)
.decl call_returns_element(c0:symbol,c1:symbol)
.decl root_expr_at(c0:symbol,c1:symbol,c2:symbol,c3:symbol,c4:symbol)
.decl iter_pair(c0:symbol,c1:symbol,c2:symbol)
.decl with_pair(c0:symbol,c1:symbol,c2:symbol)
.decl with_target_declared(c0:symbol,c1:symbol,c2:symbol)
Expand Down
Loading