@@ -577,52 +577,34 @@ function lines_required(idx::Int, src::CodeInfo, edges::CodeEdges; kwargs...)
577
577
isrequired = falses (length (edges. preds))
578
578
isrequired[idx] = true
579
579
objs = Set {Union{Symbol,GlobalRef}} ()
580
- return lines_required! (isrequired, objs, src, edges; kwargs... )
580
+ return lines_required! (isrequired, src, edges; kwargs... )
581
581
end
582
582
583
583
"""
584
- lines_required!(isrequired::AbstractVector{Bool}, src::CodeInfo, edges::CodeEdges;
585
- norequire = ())
584
+ lines_required!(isrequired::AbstractVector{Bool}, src::CodeInfo, edges::CodeEdges; exclude_named_typedefs::Bool=false)
586
585
587
586
Like `lines_required`, but where `isrequired[idx]` has already been set to `true` for all statements
588
587
that you know you need to evaluate. All other statements should be marked `false` at entry.
589
588
On return, the complete set of required statements will be marked `true`.
590
589
591
- `norequire` keyword argument specifies statements (represented as iterator of `Int`s) that
592
- should _not_ be marked as a requirement.
593
- For example, use `norequire = LoweredCodeUtils.exclude_named_typedefs(src, edges)` if you're
594
- extracting method signatures and not evaluating new definitions.
590
+ Use `exclude_named_typedefs=true` if you're extracting method signatures and not evaluating new definitions.
595
591
"""
596
592
function lines_required! (isrequired:: AbstractVector{Bool} , src:: CodeInfo , edges:: CodeEdges ; kwargs... )
597
593
objs = Set {Union{Symbol,GlobalRef}} ()
598
594
return lines_required! (isrequired, objs, src, edges; kwargs... )
599
595
end
600
596
601
- function exclude_named_typedefs (src:: CodeInfo , edges:: CodeEdges )
602
- norequire = BitSet ()
603
- i = 1
604
- nstmts = length (src. code)
605
- while i <= nstmts
606
- stmt = rhs (src. code[i])
607
- if istypedef (stmt) && ! isanonymous_typedef (stmt:: Expr )
608
- r = typedef_range (src, i)
609
- pushall! (norequire, r)
610
- i = last (r)+ 1
611
- else
612
- i += 1
613
- end
614
- end
615
- return norequire
616
- end
617
-
618
- function lines_required! (isrequired:: AbstractVector{Bool} , objs, src:: CodeInfo , edges:: CodeEdges ; norequire = ())
597
+ function lines_required! (isrequired:: AbstractVector{Bool} , objs, src:: CodeInfo , edges:: CodeEdges ; exclude_named_typedefs:: Bool = false )
619
598
# Do a traveral of "numbered" predecessors
620
599
# We'll mostly use generic graph traversal to discover all the lines we need,
621
600
# but structs are in a bit of a different category (especially on Julia 1.5+).
622
601
# It's easiest to discover these at the beginning.
602
+ # Moreover, if we're excluding named type definitions, we'll add them to `norequire`
603
+ # to prevent them from being marked.
623
604
typedef_blocks, typedef_names = UnitRange{Int}[], Symbol[]
624
- i = 1
605
+ norequire = BitSet ()
625
606
nstmts = length (src. code)
607
+ i = 1
626
608
while i <= nstmts
627
609
stmt = rhs (src. code[i])
628
610
if istypedef (stmt) && ! isanonymous_typedef (stmt:: Expr )
@@ -636,6 +618,9 @@ function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo,
636
618
isa (name, Symbol) || @show src i r stmt
637
619
push! (typedef_names, name:: Symbol )
638
620
i = last (r)+ 1
621
+ if exclude_named_typedefs && ! isanonymous_typedef (stmt)
622
+ pushall! (norequire, r)
623
+ end
639
624
else
640
625
i += 1
641
626
end
@@ -656,22 +641,19 @@ function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo,
656
641
iter = 0
657
642
while changed
658
643
changed = false
659
-
660
644
# Handle ssa predecessors
661
645
for idx = 1 : nstmts
662
646
if isrequired[idx]
663
647
changed |= add_preds! (isrequired, idx, edges, norequire)
664
648
end
665
649
end
666
-
667
650
# Handle named dependencies
668
651
for (obj, uses) in edges. byname
669
652
obj ∈ objs && continue
670
653
if any (view (isrequired, uses. succs))
671
654
changed |= add_obj! (isrequired, objs, obj, edges, norequire)
672
655
end
673
656
end
674
-
675
657
# Add control-flow. For any basic block with an evaluated statement inside it,
676
658
# check to see if the block has any successors, and if so mark that block's exit statement.
677
659
# Likewise, any preceding blocks should have *their* exit statement marked.
@@ -702,7 +684,6 @@ function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo,
702
684
end
703
685
end
704
686
end
705
-
706
687
# So far, everything is generic graph traversal. Now we add some domain-specific information.
707
688
# New struct definitions, including their constructors, get spread out over many
708
689
# statements. If we're evaluating any of them, it's important to evaluate *all* of them.
@@ -852,7 +833,7 @@ Mark each line of code with its requirement status.
852
833
function print_with_code (io:: IO , src:: CodeInfo , isrequired:: AbstractVector{Bool} )
853
834
nd = ndigits (length (isrequired))
854
835
preprint (:: IO ) = nothing
855
- preprint (io:: IO , idx:: Int ) = (c = isrequired[idx]; printstyled ( io, lpad (idx, nd), ' ' , c ? " t " : " f " ; color = c ? :cyan : :plain ) )
836
+ preprint (io:: IO , idx:: Int ) = print ( io, lpad (idx, nd), ' ' , isrequired[idx] ? " t " : " f " )
856
837
postprint (:: IO ) = nothing
857
838
postprint (io:: IO , idx:: Int , bbchanged:: Bool ) = nothing
858
839
0 commit comments