Skip to content

Commit 8c3839d

Browse files
committed
Improve monomorphization of message sending with debug assertions
1 parent 19cc39d commit 8c3839d

File tree

4 files changed

+65
-37
lines changed

4 files changed

+65
-37
lines changed

crates/objc2/src/declare.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -357,30 +357,32 @@ impl ClassBuilder {
357357
T: Message + ?Sized,
358358
F: MethodImplementation<Callee = T>,
359359
{
360-
let encs = F::Args::ENCODINGS;
360+
let enc_args = F::Args::ENCODINGS;
361+
let enc_ret = F::Ret::ENCODING;
362+
361363
let sel_args = count_args(sel);
362364
assert_eq!(
363365
sel_args,
364-
encs.len(),
366+
enc_args.len(),
365367
"Selector {:?} accepts {} arguments, but function accepts {}",
366368
sel,
367369
sel_args,
368-
encs.len(),
370+
enc_args.len(),
369371
);
370372

371373
// Verify that, if the method is present on the superclass, that the
372374
// encoding is correct.
373375
#[cfg(debug_assertions)]
374376
if let Some(superclass) = self.superclass() {
375377
if let Some(method) = superclass.instance_method(sel) {
376-
if let Err(err) = crate::verify::verify_method_signature::<F::Args, F::Ret>(method)
378+
if let Err(err) = crate::verify::verify_method_signature(method, enc_args, &enc_ret)
377379
{
378380
panic!("declared invalid method -[{} {sel:?}]: {err}", self.name())
379381
}
380382
}
381383
}
382384

383-
let types = method_type_encoding(&F::Ret::ENCODING, encs);
385+
let types = method_type_encoding(&enc_ret, enc_args);
384386
let success = Bool::from_raw(unsafe {
385387
ffi::class_addMethod(
386388
self.as_mut_ptr(),
@@ -412,30 +414,32 @@ impl ClassBuilder {
412414
where
413415
F: MethodImplementation<Callee = Class>,
414416
{
415-
let encs = F::Args::ENCODINGS;
417+
let enc_args = F::Args::ENCODINGS;
418+
let enc_ret = F::Ret::ENCODING;
419+
416420
let sel_args = count_args(sel);
417421
assert_eq!(
418422
sel_args,
419-
encs.len(),
423+
enc_args.len(),
420424
"Selector {:?} accepts {} arguments, but function accepts {}",
421425
sel,
422426
sel_args,
423-
encs.len(),
427+
enc_args.len(),
424428
);
425429

426430
// Verify that, if the method is present on the superclass, that the
427431
// encoding is correct.
428432
#[cfg(debug_assertions)]
429433
if let Some(superclass) = self.superclass() {
430434
if let Some(method) = superclass.class_method(sel) {
431-
if let Err(err) = crate::verify::verify_method_signature::<F::Args, F::Ret>(method)
435+
if let Err(err) = crate::verify::verify_method_signature(method, enc_args, &enc_ret)
432436
{
433437
panic!("declared invalid method +[{} {sel:?}]: {err}", self.name())
434438
}
435439
}
436440
}
437441

438-
let types = method_type_encoding(&F::Ret::ENCODING, encs);
442+
let types = method_type_encoding(&enc_ret, enc_args);
439443
let success = Bool::from_raw(unsafe {
440444
ffi::class_addMethod(
441445
self.metaclass_mut(),

crates/objc2/src/message/mod.rs

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,48 @@ unsafe fn conditional_try<R: EncodeConvert>(f: impl FnOnce() -> R) -> R {
3030
f()
3131
}
3232

33+
/// Help with monomorphizing in `icrate`
34+
#[cfg(debug_assertions)]
35+
#[track_caller]
36+
fn msg_send_check(
37+
obj: Option<&Object>,
38+
sel: Sel,
39+
args: &[crate::encode::Encoding],
40+
ret: &crate::encode::Encoding,
41+
) {
42+
use crate::verify::{verify_method_signature, Inner, VerificationError};
43+
44+
let cls = if let Some(obj) = obj {
45+
obj.class()
46+
} else {
47+
panic_null(sel)
48+
};
49+
50+
let err = if let Some(method) = cls.instance_method(sel) {
51+
if let Err(err) = verify_method_signature(method, args, ret) {
52+
err
53+
} else {
54+
return;
55+
}
56+
} else {
57+
VerificationError::from(Inner::MethodNotFound)
58+
};
59+
60+
panic_verify(cls, sel, err);
61+
}
62+
63+
#[cfg(debug_assertions)]
64+
#[track_caller]
65+
fn panic_null(sel: Sel) -> ! {
66+
panic!("messsaging {sel:?} to nil")
67+
}
68+
3369
#[cfg(debug_assertions)]
3470
#[track_caller]
3571
fn panic_verify(cls: &Class, sel: Sel, err: crate::VerificationError) -> ! {
3672
panic!(
37-
"invalid message send to {}[{:?} {:?}]: {}",
73+
"invalid message send to {}[{cls:?} {sel:?}]: {err}",
3874
if cls.is_metaclass() { "+" } else { "-" },
39-
cls,
40-
sel,
41-
err
4275
)
4376
}
4477

@@ -183,16 +216,8 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
183216
#[cfg(debug_assertions)]
184217
{
185218
// SAFETY: Caller ensures only valid or NULL pointers.
186-
let this = unsafe { this.as_ref() };
187-
let cls = if let Some(this) = this {
188-
this.class()
189-
} else {
190-
panic!("messsaging {:?} to nil", sel);
191-
};
192-
193-
if let Err(err) = cls.verify_sel::<A, R>(sel) {
194-
panic_verify(cls, sel, err);
195-
}
219+
let obj = unsafe { this.as_ref() };
220+
msg_send_check(obj, sel, A::ENCODINGS, &R::__Inner::ENCODING);
196221
}
197222
unsafe { EncodeConvert::__from_inner(send_unverified(this, sel, args)) }
198223
}
@@ -230,7 +255,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
230255
#[cfg(debug_assertions)]
231256
{
232257
if this.is_null() {
233-
panic!("messsaging {:?} to nil", sel);
258+
panic_null(sel);
234259
}
235260
if let Err(err) = superclass.verify_sel::<A, R>(sel) {
236261
panic_verify(superclass, sel, err);

crates/objc2/src/runtime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ impl Class {
619619
R: EncodeConvert,
620620
{
621621
let method = self.instance_method(sel).ok_or(Inner::MethodNotFound)?;
622-
verify_method_signature::<A, R>(method)
622+
verify_method_signature(method, A::ENCODINGS, &R::__Inner::ENCODING)
623623
}
624624
}
625625

crates/objc2/src/verify.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use core::fmt;
22
use core::hash::Hash;
33
use std::error::Error;
44

5-
use crate::encode::{Encode, EncodeArguments, EncodeConvert, Encoding, EncodingBox};
5+
use crate::encode::{Encoding, EncodingBox};
66
use crate::runtime::{EncodingParseError, Method};
77

88
#[derive(Debug, PartialEq, Eq, Hash)]
@@ -71,26 +71,25 @@ impl fmt::Display for VerificationError {
7171

7272
impl Error for VerificationError {}
7373

74-
pub(crate) fn verify_method_signature<A, R>(method: &Method) -> Result<(), VerificationError>
75-
where
76-
A: EncodeArguments,
77-
R: EncodeConvert,
78-
{
74+
pub(crate) fn verify_method_signature(
75+
method: &Method,
76+
args: &[Encoding],
77+
ret: &Encoding,
78+
) -> Result<(), VerificationError> {
7979
let mut iter = method.types();
8080

8181
// TODO: Verify stack layout
8282
let (expected, _stack_layout) = iter.extract_return()?;
83-
let actual = R::__Inner::ENCODING;
84-
if !actual.equivalent_to_box(&expected) {
85-
return Err(Inner::MismatchedReturn(expected, actual).into());
83+
if !ret.equivalent_to_box(&expected) {
84+
return Err(Inner::MismatchedReturn(expected, ret.clone()).into());
8685
}
8786

8887
iter.verify_receiver()?;
8988
iter.verify_sel()?;
9089

91-
let actual_count = A::ENCODINGS.len();
90+
let actual_count = args.len();
9291

93-
for (i, actual) in A::ENCODINGS.iter().enumerate() {
92+
for (i, actual) in args.iter().enumerate() {
9493
if let Some(res) = iter.next() {
9594
// TODO: Verify stack layout
9695
let (expected, _stack_layout) = res?;

0 commit comments

Comments
 (0)