From 4f6b8411870e2817d7c7bc00bd7d32d3a7674ac9 Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Thu, 16 May 2019 07:56:18 -0400 Subject: [PATCH 1/3] implement splatnew --- src/overdub.jl | 9 +++++++++ src/tagging.jl | 29 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/overdub.jl b/src/overdub.jl index 7e8698f..280b046 100644 --- a/src/overdub.jl +++ b/src/overdub.jl @@ -358,6 +358,14 @@ function overdub_pass!(reflection::Reflection, end end + #=== replace `Expr(:splatnew, ...)` with `Expr(:call, :tagged_splatnew)` if tagging is enabled ===# + if istaggingenabled && !iskwfunc + replace_match!(x -> Base.Meta.isexpr(x, :splatnew), overdubbed_code) do x + return Expr(:call, Expr(:nooverdub, GlobalRef(Cassette, :tagged_splatnew)), overdub_ctx_slot, x.args...) + end + end + + #=== replace `Expr(:call, ...)` with `Expr(:call, :overdub, ...)` calls ===# if iskwfunc @@ -569,6 +577,7 @@ If `Cassette.hastagging(typeof(context))`, then a number of additional passes ar order to accomodate tagged value propagation: - `Expr(:new)` is replaced with a call to `Cassette.tagged_new` +- `Expr(:splatnew)` is replaced with a call to `Cassette.tagged_splatnew` - conditional values passed to `Expr(:gotoifnot)` are untagged - arguments to `Expr(:foreigncall)` are untagged - load/stores to external module bindings are intercepted by the tagging system diff --git a/src/tagging.jl b/src/tagging.jl index 13f5ae6..6d01944 100644 --- a/src/tagging.jl +++ b/src/tagging.jl @@ -493,6 +493,35 @@ Base.iterate(t::Tagged, state) = destructstate(t.context, overdub(t.context, ite end end +@generated function tagged_splatnew(context::C, ::Type{T}, args...) where {C<:Context,T} + argmetaexprs = Any[] + for i in 1:fieldcount(T) + if i <= nfields(args) && istaggedtype(args[i], C) + push!(argmetaexprs, :(args[$i].meta)) + else + push!(argmetaexprs, :NOMETA) + end + end + untagged_args = [:(untag(args[$i], context)) for i in 1:nfields(args)] + newexpr = Expr(:splatnew, T, (untagged_args...)) + onlytypeargs = true + for arg in args + if !(arg <: Type) + onlytypeargs = false + break + end + end + if (all(x == :NOMETA for x in argmetaexprs) && doesnotneedmetatype(T)) || onlytypeargs + return newexpr + else + metametaexpr = _metametaexpr(C, T, argmetaexprs) + return quote + M = metatype(C, T) + return Tagged(context, $newexpr, Meta(NoMetaData(), $metametaexpr)) + end + end +end + @generated function tagged_new_array(context::C, ::Type{T}, args...) where {C<:Context,T<:Array} untagged_args = [:(untag(args[$i], context)) for i in 1:nfields(args)] return quote From d0c3d7321c75c5716316e4f715ce717038f7f166 Mon Sep 17 00:00:00 2001 From: Jarrett Revels Date: Sat, 29 Jun 2019 14:58:59 -0400 Subject: [PATCH 2/3] shorten tagged_splatnew implementation --- src/overdub.jl | 20 +++++++------------- src/tagging.jl | 35 ++++------------------------------- 2 files changed, 11 insertions(+), 44 deletions(-) diff --git a/src/overdub.jl b/src/overdub.jl index 280b046..404aa93 100644 --- a/src/overdub.jl +++ b/src/overdub.jl @@ -261,7 +261,7 @@ function overdub_pass!(reflection::Reflection, i >= original_code_start_index || return nothing stmt = Base.Meta.isexpr(x, :(=)) ? x.args[2] : x Base.Meta.isexpr(stmt, :replaceglobalref) && return 1 - if isa(stmt, Expr) # Base.Meta.isexpr(stmt, :call) || Base.Meta.isexpr(stmt, :new) || Base.Meta.isexpr(stmt, :return) + if isa(stmt, Expr) count = 0 for arg in stmt.args if Base.Meta.isexpr(arg, :replaceglobalref) @@ -280,7 +280,7 @@ function overdub_pass!(reflection::Reflection, globalref = stmt.args[2] name = QuoteNode(globalref.name) result = Expr(:call, Expr(:nooverdub, GlobalRef(Cassette, :tagged_globalref)), overdub_ctx_slot, tagmodssa, name, globalref) - elseif isa(stmt, Expr) # Base.Meta.isexpr(stmt, :call) || Base.Meta.isexpr(stmt, :new) || Base.Meta.isexpr(stmt, :return) + elseif isa(stmt, Expr) result = Expr(stmt.head) for arg in stmt.args if Base.Meta.isexpr(arg, :replaceglobalref) @@ -350,22 +350,16 @@ function overdub_pass!(reflection::Reflection, ]) end - #=== replace `Expr(:new, ...)` with `Expr(:call, :tagged_new)` if tagging is enabled ===# + #=== replace `Expr(:new, ...)`/`Expr(:splatnew, ...)` with ===# + #=== `Expr(:call, :tagged_new)`/`Expr(:call, :tagged_splatnew)` if tagging is enabled ===# if istaggingenabled && !iskwfunc - replace_match!(x -> Base.Meta.isexpr(x, :new), overdubbed_code) do x - return Expr(:call, Expr(:nooverdub, GlobalRef(Cassette, :tagged_new)), overdub_ctx_slot, x.args...) + replace_match!(x -> Base.Meta.isexpr(x, :new) || Base.Meta.isexpr(x, :splatnew), overdubbed_code) do x + tagged_version = x.head == :new ? :tagged_new : :tagged_splatnew + return Expr(:call, Expr(:nooverdub, GlobalRef(Cassette, tagged_version)), overdub_ctx_slot, x.args...) end end - #=== replace `Expr(:splatnew, ...)` with `Expr(:call, :tagged_splatnew)` if tagging is enabled ===# - if istaggingenabled && !iskwfunc - replace_match!(x -> Base.Meta.isexpr(x, :splatnew), overdubbed_code) do x - return Expr(:call, Expr(:nooverdub, GlobalRef(Cassette, :tagged_splatnew)), overdub_ctx_slot, x.args...) - end - end - - #=== replace `Expr(:call, ...)` with `Expr(:call, :overdub, ...)` calls ===# if iskwfunc diff --git a/src/tagging.jl b/src/tagging.jl index 6d01944..42361b4 100644 --- a/src/tagging.jl +++ b/src/tagging.jl @@ -460,9 +460,9 @@ destructstate(ctx, state) = untag(state, ctx) Base.iterate(t::Tagged) = destructstate(t.context, overdub(t.context, iterate, t)) Base.iterate(t::Tagged, state) = destructstate(t.context, overdub(t.context, iterate, t, state)) -################ -# `tagged_new` # -################ +################################## +# `tagged_new`/`tagged_splatnew` # +################################## @generated function tagged_new(context::C, ::Type{T}, args...) where {C<:Context,T} argmetaexprs = Any[] @@ -493,34 +493,7 @@ Base.iterate(t::Tagged, state) = destructstate(t.context, overdub(t.context, ite end end -@generated function tagged_splatnew(context::C, ::Type{T}, args...) where {C<:Context,T} - argmetaexprs = Any[] - for i in 1:fieldcount(T) - if i <= nfields(args) && istaggedtype(args[i], C) - push!(argmetaexprs, :(args[$i].meta)) - else - push!(argmetaexprs, :NOMETA) - end - end - untagged_args = [:(untag(args[$i], context)) for i in 1:nfields(args)] - newexpr = Expr(:splatnew, T, (untagged_args...)) - onlytypeargs = true - for arg in args - if !(arg <: Type) - onlytypeargs = false - break - end - end - if (all(x == :NOMETA for x in argmetaexprs) && doesnotneedmetatype(T)) || onlytypeargs - return newexpr - else - metametaexpr = _metametaexpr(C, T, argmetaexprs) - return quote - M = metatype(C, T) - return Tagged(context, $newexpr, Meta(NoMetaData(), $metametaexpr)) - end - end -end +@inline tagged_splatnew(context::Context, T::Type, args) = tagged_new(context, T, args...) @generated function tagged_new_array(context::C, ::Type{T}, args...) where {C<:Context,T<:Array} untagged_args = [:(untag(args[$i], context)) for i in 1:nfields(args)] From 90c4c04f7cfeab6f28b19891e42b28f6f3d4f6d6 Mon Sep 17 00:00:00 2001 From: Jarrett Revels Date: Sat, 29 Jun 2019 15:02:06 -0400 Subject: [PATCH 3/3] test against Julia 1.1 and 1.2 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 680f4b1..8112997 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,9 @@ language: julia os: - linux julia: - - 0.7 - 1.0 + - 1.1 + - 1.2 - nightly matrix: allow_failures: