From d27b979d2c55b0fdcf0e5938d7f2167cc47c8791 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 2 Feb 2022 06:47:16 -0600 Subject: [PATCH] Add `hasbox` to check for `Core.Box` (#29) --- src/MethodAnalysis.jl | 24 ++++++++++++++++++++++++ test/runtests.jl | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/MethodAnalysis.jl b/src/MethodAnalysis.jl index 1ba8517..ad95380 100644 --- a/src/MethodAnalysis.jl +++ b/src/MethodAnalysis.jl @@ -8,6 +8,7 @@ using Base.Meta: isexpr export visit, call_type, methodinstance, methodinstances, worlds # findcallers is exported from its own file export visit_backedges, all_backedges, with_all_backedges, terminal_backedges, direct_backedges +export hasbox include("visit.jl") include("backedges.jl") @@ -189,6 +190,29 @@ function methodinstances(@nospecialize(types::Type)) return methodinstances(f, types) end +if isdefined(Base, :code_typed_by_type) + function hasbox(mi::MethodInstance) + try + srcs = Base.code_typed_by_type(mi.specTypes) + for (ci, rt) in srcs + (any(==(Core.Box), ci.slottypes) || any(==(Core.Box), ci.ssavaluetypes)) && return true + end + return false + catch + return false + end + end +else + hasbox(mi::MethodInstance) = error("hasbox requires at least Julia 1.6") +end + +""" + hasbox(mi::MethodInstance) + +Return `true` if the code for `mi` has a `Core.Box`. This often arises from a limitation in Julia's type-inference, +see https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured. +""" +hasbox if isdefined(Core, :MethodMatch) include("findcallers.jl") diff --git a/test/runtests.jl b/test/runtests.jl index 63f4365..26f0e99 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -198,6 +198,30 @@ end end end +@testset "hasbox" begin + function abmult(r::Int) + if r < 0 + r = -r + end + f = x -> x * r + return f + end + function abmult2(r::Int) + f = x -> x * abs(r) + return f + end + abmult(1) + mi = methodinstance(abmult, (Int,)) + abmult2(1) + mi2 = methodinstance(abmult2, (Int,)) + if isdefined(Base, :code_typed_by_type) + @test hasbox(mi) + @test !hasbox(mi2) + else + @test_throws ErrorException("hasbox requires at least Julia 1.6") hasbox(mi) + end +end + module Callers f(x) = rand()