@@ -142,22 +142,28 @@ struct BigFloat <: AbstractFloat
142142
143143 # Not recommended for general use:
144144 # used internally by, e.g. deepcopy
145- global _BigFloat (d:: Memory{Limb} ) = new (d)
145+ global function _BigFloat (d:: Memory{Limb} )
146+ Base. unsafe_convert (Ref{BigFloat}, BigFloatData (d)) # force early initialization of pointer field of z.d
147+ return new (d)
148+ end
146149
147150 function BigFloat (; precision:: Integer = _precision_with_base_2 (BigFloat))
148151 precision < 1 && throw (DomainError (precision, " `precision` cannot be less than 1." ))
149152 nb = ccall ((:mpfr_custom_get_size ,libmpfr), Csize_t, (Clong,), precision)
150153 nl = (nb + offset_p + sizeof (Limb) - 1 ) ÷ Core. sizeof (Limb) # align to number of Limb allocations required for this
151154 d = Memory {Limb} (undef, nl % Int)
152155 # ccall-based version, inlined below
153- z = _BigFloat (d) # initialize to +NAN
154156 # ccall((:mpfr_custom_init,libmpfr), Cvoid, (Ptr{Limb}, Clong), BigFloatData(d), prec) # currently seems to be a no-op in mpfr
155157 # NAN_KIND = Cint(0)
156158 # ccall((:mpfr_custom_init_set,libmpfr), Cvoid, (Ref{BigFloat}, Cint, Clong, Ptr{Limb}), z, NAN_KIND, prec, BigFloatData(d))
157- z. prec = Clong (precision)
158- z. sign = one (Cint)
159- z. exp = mpfr_special_exponent_nan
160- return z
159+ p = Base. unsafe_convert (Ptr{Limb}, d)
160+ GC. @preserve d begin # initialize to +NAN
161+ unsafe_store! (Ptr {Clong} (p) + offset_prec, Clong (precision))
162+ unsafe_store! (Ptr {Cint} (p) + offset_sign, one (Cint))
163+ unsafe_store! (Ptr {Clong} (p) + offset_exp, mpfr_special_exponent_nan)
164+ unsafe_store! (Ptr {Ptr{Limb}} (p) + offset_d, p + offset_p)
165+ end
166+ return new (d)
161167 end
162168end
163169
@@ -186,16 +192,16 @@ end
186192 end
187193end
188194
195+ # While BigFloat (like all Numbers) is considered immutable, for practical reasons
196+ # of writing the algorithms on it we allow mutating sign, exp, and the contents of d
189197@inline function Base. setproperty! (x:: BigFloat , s:: Symbol , v)
190198 d = getfield (x, :d )
191199 p = Base. unsafe_convert (Ptr{Limb}, d)
192- if s === :prec
193- return GC. @preserve d unsafe_store! (Ptr {Clong} (p) + offset_prec, v)
194- elseif s === :sign
200+ if s === :sign
195201 return GC. @preserve d unsafe_store! (Ptr {Cint} (p) + offset_sign, v)
196202 elseif s === :exp
197203 return GC. @preserve d unsafe_store! (Ptr {Clong} (p) + offset_exp, v)
198- # elseif s === :d # not mutable
204+ # elseif s === :d || s === :prec # not mutable
199205 else
200206 return throw (FieldError (x, s))
201207 end
@@ -208,7 +214,11 @@ Base.cconvert(::Type{Ref{BigFloat}}, x::BigFloat) = x.d # BigFloatData is the Re
208214function Base. unsafe_convert (:: Type{Ref{BigFloat}} , x:: BigFloatData )
209215 d = getfield (x, :d )
210216 p = Base. unsafe_convert (Ptr{Limb}, d)
211- GC. @preserve d unsafe_store! (Ptr {Ptr{Limb}} (p) + offset_d, p + offset_p, :monotonic ) # :monotonic ensure that TSAN knows that this isn't a data race
217+ dptrptr = Ptr {Ptr{Limb}} (p) + offset_d
218+ dptr = p + offset_p
219+ GC. @preserve d if unsafe_load (dptrptr, :monotonic ) != dptr # make sure this pointer value was recomputed after any deserialization or copying
220+ unsafe_store! (dptrptr, dptr, :monotonic ) # :monotonic ensure that TSAN knows that this isn't a data race
221+ end
212222 return Ptr {BigFloat} (p)
213223end
214224Base. unsafe_convert (:: Type{Ptr{Limb}} , fd:: BigFloatData ) = Base. unsafe_convert (Ptr{Limb}, getfield (fd, :d )) + offset_p
0 commit comments