Skip to content

Commit e93446c

Browse files
committed
Callable: name is optimized out in disengaged mode (not Release)
1 parent d410487 commit e93446c

File tree

1 file changed

+48
-64
lines changed

1 file changed

+48
-64
lines changed

godot-core/src/builtin/callable.rs

Lines changed: 48 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
77

8+
use std::thread::ThreadId;
89
use std::{fmt, ptr};
910

1011
use godot_ffi as sys;
@@ -162,16 +163,7 @@ impl Callable {
162163
F: 'static + FnMut(&[&Variant]) -> R,
163164
S: meta::AsArg<GString>,
164165
{
165-
#[cfg(debug_assertions)]
166-
meta::arg_into_owned!(name);
167-
168-
Self::from_fn_wrapper::<F, R>(FnWrapper {
169-
rust_function,
170-
#[cfg(debug_assertions)]
171-
name,
172-
thread_id: Some(std::thread::current().id()),
173-
linked_obj_id: None,
174-
})
166+
Self::from_fn_wrapper(name, rust_function, Some(std::thread::current().id()), None)
175167
}
176168

177169
/// Creates a new callable linked to the given object from **single-threaded** Rust function or closure.
@@ -189,16 +181,12 @@ impl Callable {
189181
F: 'static + FnMut(&[&Variant]) -> R,
190182
S: meta::AsArg<GString>,
191183
{
192-
#[cfg(debug_assertions)]
193-
meta::arg_into_owned!(name);
194-
195-
Self::from_fn_wrapper::<F, R>(FnWrapper {
196-
rust_function,
197-
#[cfg(debug_assertions)]
184+
Self::from_fn_wrapper(
198185
name,
199-
thread_id: Some(std::thread::current().id()),
200-
linked_obj_id: Some(linked_object.instance_id()),
201-
})
186+
rust_function,
187+
Some(std::thread::current().id()),
188+
Some(linked_object.instance_id()),
189+
)
202190
}
203191

204192
/// This constructor is being phased out in favor of [`from_fn()`][Self::from_fn], but kept through v0.4 for smoother migration.
@@ -258,16 +246,8 @@ impl Callable {
258246
F: FnMut(&[&Variant]) -> Variant,
259247
Fc: FnOnce(&Callable) -> R,
260248
{
261-
#[cfg(debug_assertions)]
262-
meta::arg_into_owned!(name);
263-
264-
let callable = Self::from_fn_wrapper::<F, Variant>(FnWrapper {
265-
rust_function,
266-
#[cfg(debug_assertions)]
267-
name,
268-
thread_id: Some(std::thread::current().id()),
269-
linked_obj_id: None,
270-
});
249+
let callable =
250+
Self::from_fn_wrapper(name, rust_function, Some(std::thread::current().id()), None);
271251

272252
callable_usage(&callable)
273253
}
@@ -298,16 +278,7 @@ impl Callable {
298278
F: 'static + Send + Sync + FnMut(&[&Variant]) -> R,
299279
S: meta::AsArg<GString>,
300280
{
301-
#[cfg(debug_assertions)]
302-
meta::arg_into_owned!(name);
303-
304-
Self::from_fn_wrapper::<F, R>(FnWrapper {
305-
rust_function,
306-
#[cfg(debug_assertions)]
307-
name,
308-
thread_id: None,
309-
linked_obj_id: None,
310-
})
281+
Self::from_fn_wrapper(name, rust_function, None, None)
311282
}
312283

313284
/// Create a highly configurable callable from Rust.
@@ -334,21 +305,37 @@ impl Callable {
334305
Self::from_custom_info(info)
335306
}
336307

337-
fn from_fn_wrapper<F, R>(inner: FnWrapper<F>) -> Self
308+
fn from_fn_wrapper<F, R, S>(
309+
_name: S,
310+
rust_function: F,
311+
thread_id: Option<ThreadId>,
312+
linked_obj_id: Option<InstanceId>,
313+
) -> Self
338314
where
339315
F: FnMut(&[&Variant]) -> R,
340316
R: ToGodot,
317+
S: meta::AsArg<GString>,
341318
{
342-
let object_id = inner.linked_object_id();
319+
#[cfg(safeguards_balanced)]
320+
meta::arg_into_owned!(_name);
321+
322+
let wrapper = FnWrapper {
323+
rust_function,
324+
#[cfg(safeguards_balanced)]
325+
name: _name,
326+
thread_id,
327+
linked_obj_id,
328+
};
343329

344-
let userdata = CallableUserdata { inner };
330+
let object_id = wrapper.linked_object_id();
331+
let userdata = CallableUserdata { inner: wrapper };
345332

346333
let info = CallableCustomInfo {
347334
object_id,
348335
callable_userdata: Box::into_raw(Box::new(userdata)) as *mut std::ffi::c_void,
349336
call_func: Some(rust_callable_call_fn::<F, R>),
350337
free_func: Some(rust_callable_destroy::<FnWrapper<F>>),
351-
#[cfg(debug_assertions)]
338+
#[cfg(safeguards_balanced)]
352339
to_string_func: Some(rust_callable_to_string_named::<F>),
353340
is_valid_func: Some(rust_callable_is_valid),
354341
..Self::default_callable_custom_info()
@@ -617,7 +604,7 @@ mod custom_callable {
617604

618605
pub(crate) struct FnWrapper<F> {
619606
pub(super) rust_function: F,
620-
#[cfg(debug_assertions)]
607+
#[cfg(safeguards_balanced)]
621608
pub(super) name: GString,
622609

623610
/// `None` if the callable is multi-threaded ([`Callable::from_sync_fn`]).
@@ -668,12 +655,12 @@ mod custom_callable {
668655
) {
669656
let arg_refs: &[&Variant] = Variant::borrow_ref_slice(p_args, p_argument_count as usize);
670657

671-
#[cfg(debug_assertions)]
658+
#[cfg(safeguards_balanced)]
672659
let name = &{
673660
let c: &C = CallableUserdata::inner_from_raw(callable_userdata);
674661
c.to_string()
675662
};
676-
#[cfg(not(debug_assertions))]
663+
#[cfg(not(safeguards_balanced))]
677664
let name = "<optimized out>";
678665
let ctx = meta::CallContext::custom_callable(name);
679666

@@ -698,34 +685,31 @@ mod custom_callable {
698685
{
699686
let arg_refs: &[&Variant] = Variant::borrow_ref_slice(p_args, p_argument_count as usize);
700687

701-
#[cfg(debug_assertions)]
688+
#[cfg(safeguards_balanced)]
702689
let name = &{
703690
let w: &FnWrapper<F> = CallableUserdata::inner_from_raw(callable_userdata);
704691
w.name.to_string()
705692
};
706-
#[cfg(not(debug_assertions))]
693+
#[cfg(not(safeguards_balanced))]
707694
let name = "<optimized out>";
708695
let ctx = meta::CallContext::custom_callable(name);
709696

710697
crate::private::handle_fallible_varcall(&ctx, &mut *r_error, move || {
711698
// Get the FnWrapper again inside closure so the FnMut doesn't have to be UnwindSafe.
712699
let w: &mut FnWrapper<F> = CallableUserdata::inner_from_raw(callable_userdata);
713700

714-
if w.thread_id
715-
.is_some_and(|tid| tid != std::thread::current().id())
716-
{
717-
#[cfg(debug_assertions)]
718-
let name = &w.name;
719-
#[cfg(not(debug_assertions))]
720-
let name = "<optimized out>";
721-
// NOTE: this panic is currently not propagated to the caller, but results in an error message and Nil return.
722-
// See comments in itest callable_call() for details.
723-
panic!(
724-
"Callable '{}' created with from_fn() must be called from the same thread it was created in.\n\
725-
If you need to call it from any thread, use from_sync_fn() instead (requires `experimental-threads` feature).",
726-
name
727-
);
728-
}
701+
#[cfg(safeguards_balanced)]
702+
let name = &w.name;
703+
#[cfg(not(safeguards_balanced))]
704+
let name = "<optimized out>";
705+
706+
// NOTE: this panic is currently not propagated to the caller, but results in an error message and Nil return.
707+
// See comments in itest callable_call() for details.
708+
sys::balanced_assert!(
709+
w.thread_id.is_none() || w.thread_id == Some(std::thread::current().id()),
710+
"Callable '{name}' created with from_fn() must be called from the same thread it was created in.\n\
711+
If you need to call it from any thread, use from_sync_fn() instead (requires `experimental-threads` feature)."
712+
);
729713

730714
let result = (w.rust_function)(arg_refs).to_variant();
731715
meta::varcall_return_checked(Ok(result), r_return, r_error);
@@ -769,7 +753,7 @@ mod custom_callable {
769753
*r_is_valid = sys::conv::SYS_TRUE;
770754
}
771755

772-
#[cfg(debug_assertions)]
756+
#[cfg(safeguards_balanced)]
773757
pub unsafe extern "C" fn rust_callable_to_string_named<F>(
774758
callable_userdata: *mut std::ffi::c_void,
775759
r_is_valid: *mut sys::GDExtensionBool,

0 commit comments

Comments
 (0)