Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Reduce specialization in GLib methods #552

Merged
merged 3 commits into from
Jan 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/GLib/GLib.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export GConnectFlags
export @sigatom, cfunction_


cfunction_(f, r, a::Tuple) = cfunction_(f, r, Tuple{a...})
cfunction_(@nospecialize(f), r, a::Tuple) = cfunction_(f, r, Tuple{a...})

@generated function cfunction_(f, R::Type{rt}, A::Type{at}) where {rt, at<:Tuple}
quote
Expand Down
19 changes: 12 additions & 7 deletions src/GLib/gtype.jl
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,12 @@ convert(::Type{GBoxed}, unbox::Ptr{T}) where {T <: GBoxed} = GBoxedUnkown(unbox)
convert(::Type{T}, unbox::Ptr{GBoxed}) where {T <: GBoxed} = convert(T, convert(Ptr{T}, unbox))
convert(::Type{T}, unbox::Ptr{T}) where {T <: GBoxed} = T(unbox)

cconvert(::Type{Ptr{GObject}}, @nospecialize(x::GObject)) = x

# All GObjects are expected to have a 'handle' field
# of type Ptr{GObject} corresponding to the GLib object
# or to override this method (e.g. GtkNullContainer, AbstractString)
unsafe_convert(::Type{Ptr{GObject}}, w::GObject) = w.handle
unsafe_convert(::Type{Ptr{GObject}}, w::GObject) = getfield(w, :handle)

# this method should be used by gtk methods returning widgets of unknown type
# and/or that might have been wrapped by julia before,
Expand Down Expand Up @@ -366,6 +368,7 @@ function gc_unref(@nospecialize(x))
nothing
end
_gc_unref(@nospecialize(x), ::Ptr{Nothing}) = gc_unref(x)
gc_ref_closure(@nospecialize(cb::Function)) = (invoke(gc_ref, Tuple{Any}, cb), @cfunction(_gc_unref, Nothing, (Any, Ptr{Nothing})))
gc_ref_closure(x::T) where {T} = (gc_ref(x), @cfunction(_gc_unref, Nothing, (Any, Ptr{Nothing})))

# generally, you shouldn't be calling gc_ref(::Ptr{GObject})
Expand All @@ -377,15 +380,17 @@ const gc_preserve_glib_lock = Ref(false) # to satisfy this lock, must never decr
const topfinalizer = Ref(true) # keep recursion to a minimum by only iterating from the top
const await_finalize = Any[]

function finalize_gc_unref(@nospecialize(x))
Base.isequal(x::GObject, w::WeakRef) = x === w.value # cuts the number of MethodInstances from O(N^2) to O(N)

function finalize_gc_unref(@nospecialize(x::GObject))
# this records that the are no user references left to the object from Julia
# and notifies GLib that it can free the object (if no reference exist from C)
# it is intended to be called by GC, not in user code function
istop = topfinalizer[]
topfinalizer[] = false
gc_preserve_glib_lock[] = true
delete!(gc_preserve_glib, x)
if x.handle != C_NULL
if getfield(x, :handle) != C_NULL
gc_preserve_glib[x] = true # convert to a strong-reference
gc_preserve_glib_lock[] = false
gc_unref(unsafe_convert(Ptr{GObject}, x)) # may clear the strong reference
Expand All @@ -397,7 +402,7 @@ function finalize_gc_unref(@nospecialize(x))
nothing
end

function delref(@nospecialize(x))
function delref(@nospecialize(x::GObject))
# internal helper function
exiting[] && return # unnecessary to cleanup if we are about to die anyways
if gc_preserve_glib_lock[] || g_yielded[]
Expand All @@ -407,7 +412,7 @@ function delref(@nospecialize(x))
finalize_gc_unref(x)
nothing
end
function addref(@nospecialize(x))
function addref(@nospecialize(x::GObject))
# internal helper function
ccall((:g_object_ref_sink, libgobject), Ptr{GObject}, (Ptr{GObject},), x)
finalizer(delref, x)
Expand All @@ -424,10 +429,10 @@ function gobject_ref(x::T) where T <: GObject
ccall((:g_object_set_qdata_full, libgobject), Nothing,
(Ptr{GObject}, UInt32, Any, Ptr{Nothing}), x, jlref_quark::UInt32, x,
deref) # add a circular reference to the Julia object in the GObject
addref(x)
addref(Ref{GObject}(x)[])
elseif strong
# oops, we previously deleted the link, but now it's back
addref(x)
addref(Ref{GObject}(x)[])
else
# already gc-protected, nothing to do
end
Expand Down
16 changes: 9 additions & 7 deletions src/GLib/gvalues.jl
Original file line number Diff line number Diff line change
Expand Up @@ -159,21 +159,23 @@ function getindex(gv::GV, ::Type{Any})
end
#end

get_gtk_property(w::GObject, name::AbstractString, ::Type{T}) where T = get_gtk_property(w, Symbol(name), T)
function get_gtk_property(w::GObject, name::Symbol, ::Type{T}) where T
get_gtk_property(w::GObject, name::AbstractString, ::Type{T}) where T = get_gtk_property(w, String(name)::String, T)
get_gtk_property(w::GObject, name::Symbol, ::Type{T}) where T = get_gtk_property(w, String(name), T)
function get_gtk_property(w::GObject, name::String, ::Type{T}) where T
v = gvalue(T)
ccall((:g_object_get_property, libgobject), Nothing,
(Ptr{GObject}, Ptr{UInt8}, Ptr{GValue}), w, GLib.bytestring(name), v)
(Ptr{GObject}, Ptr{UInt8}, Ptr{GValue}), w, name, v)
val = v[T]
ccall((:g_value_unset, libgobject), Nothing, (Ptr{GValue},), v)
return val
end

set_gtk_property!(w::GObject, name, ::Type{T}, value) where T = set_gtk_property!(w, name, convert(T, value))
set_gtk_property!(w::GObject, name::AbstractString, value) = set_gtk_property!(w::GObject, Symbol(name), value)
function set_gtk_property!(w::GObject, name::Symbol, value)
set_gtk_property!(w::GObject, name::AbstractString, value) = set_gtk_property!(w::GObject, String(name)::String, value)
set_gtk_property!(w::GObject, name::Symbol, value) = set_gtk_property!(w::GObject, String(name), value)
function set_gtk_property!(w::GObject, name::String, value)
ccall((:g_object_set_property, libgobject), Nothing,
(Ptr{GObject}, Ptr{UInt8}, Ptr{GValue}), w, GLib.bytestring(name), gvalue(value))
(Ptr{GObject}, Ptr{UInt8}, Ptr{GValue}), w, name, gvalue(value))

w
end
Expand All @@ -186,7 +188,7 @@ struct FieldRef{T}
isdefined(obj, field) && return getfield(obj, field)
new{T}(obj, field)
end

FieldRef(obj::T, field::Symbol) where T = new{T}(obj, field)
end

Expand Down
16 changes: 8 additions & 8 deletions src/GLib/signals.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# id = VERSION >= v"0.4-"get, :event, Nothing, (ArgsT...)) do ptr, evt_args..., closure
# stuff
# end
function signal_connect(cb::Function, w::GObject, sig::AbstractStringLike,
function signal_connect(@nospecialize(cb::Function), w::GObject, sig::AbstractStringLike,
::Type{RT}, param_types::Tuple, after::Bool = false, user_data::CT = w) where {CT, RT}
signal_connect_generic(cb, w, sig, RT, param_types, after, user_data)
end

function signal_connect_generic(cb::Function, w::GObject, sig::AbstractStringLike,
function signal_connect_generic(@nospecialize(cb::Function), w::GObject, sig::AbstractStringLike,
::Type{RT}, param_types::Tuple, after::Bool = false, user_data::CT = w) where {CT, RT} #TODO: assert that length(param_types) is correct
callback = cfunction_(cb, RT, tuple(Ptr{GObject}, param_types..., Ref{CT}))
ref, deref = gc_ref_closure(user_data)
Expand All @@ -23,10 +23,10 @@ end
# id = signal_connect(widget, :event) do obj, evt_args...
# stuff
# end
function signal_connect(cb::Function, w::GObject, sig::AbstractStringLike, after::Bool = false)
function signal_connect(@nospecialize(cb::Function), w::GObject, sig::AbstractStringLike, after::Bool = false)
_signal_connect(cb, w, sig, after, false, nothing, nothing)
end
function _signal_connect(cb::Function, w::GObject, sig::AbstractStringLike, after::Bool, gtk_call_conv::Bool, param_types, user_data)
function _signal_connect(@nospecialize(cb::Function), w::GObject, sig::AbstractStringLike, after::Bool, gtk_call_conv::Bool, param_types, user_data)
@assert sizeof_gclosure > 0
closuref = ccall((:g_closure_new_object, libgobject), Ptr{Nothing}, (Cuint, Ptr{GObject}), sizeof_gclosure::Int + GLib.WORD_SIZE * 2, w)
closure_env = convert(Ptr{Ptr{Nothing}}, closuref + sizeof_gclosure)
Expand All @@ -39,7 +39,7 @@ function _signal_connect(cb::Function, w::GObject, sig::AbstractStringLike, afte
else
unsafe_store!(convert(Ptr{Int}, closure_env), 0, 2)
end
ref_cb, deref_cb = gc_ref_closure(cb)
ref_cb, deref_cb = invoke(gc_ref_closure, Tuple{Function}, cb)
unsafe_store!(closure_env, ref_cb, 1)
ccall((:g_closure_add_invalidate_notifier, libgobject), Nothing,
(Ptr{Nothing}, Ptr{Nothing}, Ptr{Nothing}), closuref, ref_cb, deref_cb)
Expand Down Expand Up @@ -102,7 +102,7 @@ function GClosureMarshal(closuref::Ptr{Nothing}, return_value::Ptr{GValue}, n_pa
return nothing
end

function blame(cb)
function blame(@nospecialize(cb))
warn("Executing ", cb, ":")
end

Expand Down Expand Up @@ -132,7 +132,7 @@ the given `id`.
signal_handler_is_connected(w::GObject, handler_id::Culong) =
ccall((:g_signal_handler_is_connected, libgobject), Cint, (Ptr{GObject}, Culong), w, handler_id) == 1

function signal_emit(w::GObject, sig::AbstractStringLike, RT::Type, args...)
function signal_emit(w::GObject, sig::AbstractStringLike, ::Type{RT}, args...) where RT
i = isa(sig, AbstractString) ? something(findfirst("::", sig), 0:-1) : (0:-1)
if !isempty(i)
detail = @quark_str sig[last(i) + 1:end]
Expand Down Expand Up @@ -202,7 +202,7 @@ macro sigatom(f)
end
end

function g_siginterruptible(f::Base.Callable, cb) # calls f (which may throw), but this function never throws
function g_siginterruptible(f::Base.Callable, @nospecialize(cb)) # calls f (which may throw), but this function never throws
global g_sigatom_flag, g_stack
prev = g_sigatom_flag[]
@assert xor(prev, (current_task() !== g_stack))
Expand Down
6 changes: 3 additions & 3 deletions src/cairo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ mutable struct GtkCanvas <: GtkDrawingArea # NOT an @GType
ids = Vector{Culong}(undef, 0)
widget = new(da, false, false, MouseHandler(ids), nothing, nothing)
widget.mouse.widget = widget
signal_connect(notify_realize, widget, "realize", Nothing, ())
signal_connect(notify_unrealize, widget, "unrealize", Nothing, ())
signal_connect(Base.inferencebarrier(notify_realize), widget, "realize", Nothing, ())
signal_connect(Base.inferencebarrier(notify_unrealize), widget, "unrealize", Nothing, ())
on_signal_resize(notify_resize, widget)
signal_connect(canvas_on_draw_event, widget, "draw", Cint, (Ptr{Nothing},))
signal_connect(Base.inferencebarrier(canvas_on_draw_event), widget, "draw", Cint, (Ptr{Nothing},))
push!(ids, on_signal_button_press(mousedown_cb, widget, false, widget.mouse))
push!(ids, on_signal_button_release(mouseup_cb, widget, false, widget.mouse))
push!(ids, on_signal_motion(mousemove_cb, widget, 0, 0, false, widget.mouse))
Expand Down
8 changes: 4 additions & 4 deletions src/events.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ add_events(widget::GtkWidget, mask::Integer) = ccall((:gtk_widget_add_events, li
#end


function on_signal_resize(resize_cb::Function, widget::GtkWidget, vargs...)
function on_signal_resize(@nospecialize(resize_cb::Function), widget::GtkWidget, vargs...)
signal_connect(resize_cb, widget, "size-allocate", Nothing, (Ptr{GdkRectangle},), vargs...)
end

function on_signal_destroy(destroy_cb::Function, widget::GObject, vargs...)
function on_signal_destroy(@nospecialize(destroy_cb::Function), widget::GObject, vargs...)
signal_connect(destroy_cb, widget, "destroy", Nothing, (), vargs...)
end

function on_signal_button_press(press_cb::Function, widget::GtkWidget, vargs...)
function on_signal_button_press(@nospecialize(press_cb::Function), widget::GtkWidget, vargs...)
add_events(widget, GdkEventMask.BUTTON_PRESS)
signal_connect(press_cb, widget, "button-press-event", Cint, (Ptr{GdkEventButton},), vargs...)
end
function on_signal_button_release(release_cb::Function, widget::GtkWidget, vargs...)
function on_signal_button_release(@nospecialize(release_cb::Function), widget::GtkWidget, vargs...)
add_events(widget, GdkEventMask.BUTTON_RELEASE)
signal_connect(release_cb, widget, "button-release-event", Cint, (Ptr{GdkEventButton},), vargs...)
end
Expand Down
4 changes: 4 additions & 0 deletions src/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ function _precompile_()
precompile(Tuple{Type{GtkBox},Symbol})
precompile(Tuple{Type{GtkButtonLeaf},Ptr{GObject}})
precompile(Tuple{Type{GtkToolButton},String})
precompile(Tuple{Type{GtkToolbar}})
precompile(Tuple{Type{GtkCanvas},Int,Int})
precompile(Tuple{typeof(signal_emit),GtkCanvas,String,Type,GdkEventScroll})
precompile(Tuple{typeof(signal_emit),GtkCanvas,String,Type,GdkEventMotion})
Expand All @@ -27,6 +28,9 @@ function _precompile_()
precompile(Tuple{typeof(open_dialog),String,GtkWidget,Tuple{String}})
precompile(Tuple{typeof(open_dialog),String,GtkWidget,Tuple{String,String}})
precompile(Tuple{typeof(save_dialog),String,GtkWidget,Tuple{String}})
precompile(Tuple{Type{GtkFileChooserDialogLeaf},String,GtkContainer,Int32,Tuple{Tuple{String, Int32}, Tuple{String, Int32}}})
precompile(Tuple{Type{GtkFileFilterLeaf},String})
precompile(Tuple{typeof(makefilters!),GtkFileChooser,Tuple{String, String}})
precompile(Tuple{typeof(draw),GtkCanvas,Bool})
for T in Any[
GtkWindowLeaf,
Expand Down