-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix a small number of invalid unsafe code #23914
Conversation
Could we get a little documentation/explanation on |
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan |
The infrastructure was introduced in #23610, related devdoc entry: https://docs.julialang.org/en/latest/devdocs/llvm/#Keeping-values-alive-in-the-absence-of-uses-1 |
The macro has doc.
There has been no change in the semantic, those code has always been wrong. It's just that the compiler wasn't smart enough to use them in a lot of the cases. The main issue is that local variables do not create GC roots, only their use does. This is consistent with the property that extra local variable assignments has absolutely no semantic significance, including the arguments for inlined functions. There are cases where
|
dd7a115
to
ed296e9
Compare
ed296e9
to
15ca594
Compare
@@ -137,7 +137,7 @@ hash(r::MersenneTwister, h::UInt) = foldr(hash, h, (r.seed, r.state, r.vals, r.i | |||
@inline mt_pop!(r::MersenneTwister) = @inbounds return r.vals[r.idx+=1] | |||
|
|||
function gen_rand(r::MersenneTwister) | |||
dsfmt_fill_array_close1_open2!(r.state, pointer(r.vals), length(r.vals)) | |||
Base.@gc_preserve r dsfmt_fill_array_close1_open2!(r.state, pointer(r.vals), length(r.vals)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here (also in other places), the "preserved" object is again used on the line after, isn't it enough to preserve it? (I guess not as you updated the code) Is it that the compiler can reorder instructions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No it's not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify, after inlining any uses after may be dead code and eliminated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the detail I don't want to go into since I don't want people to rely on it but another way this can be invalid is that the compiler can see you are using only some fields and then discards all other fields.
2*n128, Close1Open2()) | ||
Base.@gc_preserve A rand!(r, unsafe_wrap(Array, convert(Ptr{Float64}, pointer(A)), 2*n128), | ||
2*n128, Close1Open2()) | ||
# FIXME: This code is completely invalid!!! | ||
A128 = unsafe_wrap(Array, convert(Ptr{UInt128}, pointer(A)), n128) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had plans to change this to avoid using unsafe_wrap
for performance reasons (cf. #9174), but maybe I need to understand what is invalid here? Preserving A
wouldn't be enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't pass a managed pointer to unsafe_wrap
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok thanks for the precision (this limitation is not documented in the docstring). I will work on fixing those cases.
There are of course cases where the code will practically be fine, for now. But I don't want to go into detail to document the limitation of the compiler/optimizer especially since people don't have to rely on these anymore with the introduction of |
@@ -264,7 +264,7 @@ end | |||
function readbytes_all!(s::IOStream, b::Array{UInt8}, nb) | |||
olb = lb = length(b) | |||
nr = 0 | |||
while nr < nb | |||
@gc_preserve b while nr < nb |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we just use Ref(b, nr + 1)
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a few different places that uses pointer(ary, i)
that can be changed, yes.
@@ -2108,6 +2108,9 @@ static Value *boxed(jl_codectx_t &ctx, const jl_cgval_t &vinfo) | |||
return UndefValue::get(T_prjlvalue); | |||
if (vinfo.constant) | |||
return maybe_decay_untracked(literal_pointer_val(ctx, vinfo.constant)); | |||
// This can happen in early bootstrap for `gc_preserve_begin` return value. | |||
if (jt == (jl_value_t*)jl_void_type) | |||
return maybe_decay_untracked(literal_pointer_val(ctx, jl_nothing)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If vinfo.typ == jl_void_type
then vinfo.constant == jl_nothing
and we shouldn't get here. What's violating that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 3926 in 056b374
jl_cgval_t tok(token, NULL, false, (jl_value_t*)jl_void_type, NULL); |
nothing
but also an LLVM token
though so I'm avoiding touching that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok. Right, this was an intentionally malformed value.
There's a bunch of cases here where you use |
They are exactly the same. The |
I figured it was bootstrap-related. |
Started as trying to fix #23520 but as the title said, this end up fixing only a small number of them -- basically all use of
pointer
were wrong. Also marked a few even more invalid places where managed pointer is passed tounsafe_wrap
(the fix for those will be much more involved).The only unrelated change is https://github.com/JuliaLang/julia/compare/yyc/gc/safe_unsafe_write?expand=1#diff-b103e3ad474d354f14374e435955adcbL516 which is what I happened to notice when fixing the function.
Should in principle have no effect on performance but inlining may still be sensitive in some cases so
@nanosoldier
runbenchmarks(ALL, vs=":master")