@@ -516,7 +516,7 @@ The following `setting`s are supported.
516516- `:foldable`
517517- `:removable`
518518- `:total`
519-
519+ - `:gc_safe`
520520# Extended help
521521
522522---
@@ -750,6 +750,13 @@ the following other `setting`s:
750750 number of effect overrides apply to a set of functions, a custom macro is
751751 recommended over the use of `:total`.
752752
753+ ---
754+ ## `:gc_safe`
755+
756+ This `setting` can only be applied to `@ccall` expressions. It asserts that the
757+ `@ccall` is safe to execute concurrently with the garbage collector. This means that it must not
758+ call into the julia runtime.
759+
753760---
754761## Negated effects
755762
@@ -759,12 +766,13 @@ the call is generally total, it may however throw.
759766"""
760767macro assume_effects (args... )
761768 lastex = args[end ]
762- override = compute_assumed_settings (args[begin : end - 1 ])
769+ override, gc_safe = compute_assumed_settings (args[begin : end - 1 ])
763770 if is_function_def (unwrap_macrocalls (lastex))
764771 return esc (pushmeta! (lastex:: Expr , form_purity_expr (override)))
765772 elseif isexpr (lastex, :macrocall ) && lastex. args[1 ] === Symbol (" @ccall" )
766773 lastex. args[1 ] = GlobalRef (Base, Symbol (" @ccall_effects" ))
767774 insert! (lastex. args, 3 , encode_effects_override (override))
775+ insert! (lastex. args, 4 , gc_safe)
768776 return esc (lastex)
769777 end
770778 override′ = compute_assumed_setting (override, lastex)
@@ -783,12 +791,19 @@ end
783791
784792function compute_assumed_settings (settings)
785793 override = EffectsOverride ()
794+ gc_safe = false
786795 for setting in settings
796+ # This way of parsing is slightly annoying, but it's to avoid extra complexity for EffectOverride
797+ gc_safe2, found = compute_gc_safe (setting)
798+ if found
799+ gc_safe = gc_safe2
800+ continue
801+ end
787802 override = compute_assumed_setting (override, setting)
788803 override === nothing &&
789804 throw (ArgumentError (" `@assume_effects $setting ` not supported" ))
790805 end
791- return override
806+ return override, gc_safe
792807end
793808
794809struct EffectsOverride
835850
836851const NUM_EFFECTS_OVERRIDES = 11 # sync with julia.h
837852
853+ function compute_gc_safe (setting)
854+ if setting === :gc_safe
855+ return (gc_safe= true , found= true )
856+ elseif isexpr (setting, :call ) && setting. args[1 ] === :(! )
857+ gc_safe2, found2 = compute_gc_safe (setting. args[2 ])
858+ return (gc_safe= (! gc_safe2), found= found2)
859+ elseif isa (setting, QuoteNode)
860+ return compute_gc_safe (setting. value)
861+ end
862+ return (gc_safe= false , found= false )
863+ end
864+
838865function compute_assumed_setting (override:: EffectsOverride , @nospecialize (setting), val:: Bool = true )
839866 if isexpr (setting, :call ) && setting. args[1 ] === :(! )
840867 return compute_assumed_setting (override, setting. args[2 ], ! val)
0 commit comments