Skip to content

Commit f4f95a4

Browse files
committed
Implement send_unverified for each platform
This allows fixing an issue where gnustep was not returning correctly zeroed floating point results when messaging nil.
1 parent eba44b7 commit f4f95a4

File tree

7 files changed

+127
-135
lines changed

7 files changed

+127
-135
lines changed

src/message/apple/arm.rs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,40 @@
11
use std::any::{Any, TypeId};
22
use std::mem;
33

4-
use runtime::{Object, Imp, Sel};
5-
use super::Super;
4+
use runtime::Imp;
65

7-
pub fn msg_send_fn<R: Any>(obj: *mut Object, _: Sel) -> (Imp, *mut Object) {
6+
extern {
7+
fn objc_msgSend();
8+
fn objc_msgSend_stret();
9+
10+
fn objc_msgSendSuper();
11+
fn objc_msgSendSuper_stret();
12+
}
13+
14+
pub fn msg_send_fn<R: Any>() -> Imp {
815
// Double-word sized fundamental data types don't use stret,
916
// but any composite type larger than 4 bytes does.
1017
// <http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf>
1118

12-
extern {
13-
fn objc_msgSend();
14-
fn objc_msgSend_stret();
15-
}
16-
1719
let type_id = TypeId::of::<R>();
18-
let msg_fn = if mem::size_of::<R>() <= 4 ||
20+
if mem::size_of::<R>() <= 4 ||
1921
type_id == TypeId::of::<i64>() ||
2022
type_id == TypeId::of::<u64>() ||
2123
type_id == TypeId::of::<f64>() {
2224
objc_msgSend
2325
} else {
2426
objc_msgSend_stret
25-
};
26-
27-
(msg_fn, obj)
28-
}
29-
30-
pub fn msg_send_super_fn<R: Any>(sup: &Super, _: Sel) -> (Imp, *mut Object) {
31-
extern {
32-
fn objc_msgSendSuper();
33-
fn objc_msgSendSuper_stret();
3427
}
28+
}
3529

30+
pub fn msg_send_super_fn<R: Any>() -> Imp {
3631
let type_id = TypeId::of::<R>();
37-
let msg_fn = if mem::size_of::<R>() <= 4 ||
32+
if mem::size_of::<R>() <= 4 ||
3833
type_id == TypeId::of::<i64>() ||
3934
type_id == TypeId::of::<u64>() ||
4035
type_id == TypeId::of::<f64>() {
4136
objc_msgSendSuper
4237
} else {
4338
objc_msgSendSuper_stret
44-
};
45-
46-
(msg_fn, sup as *const Super as *mut Object)
39+
}
4740
}

src/message/apple/arm64.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
1-
use runtime::{Object, Imp, Sel};
2-
use super::Super;
1+
use runtime::Imp;
32

4-
pub fn msg_send_fn<R>(obj: *mut Object, _: Sel) -> (Imp, *mut Object) {
3+
extern {
4+
fn objc_msgSend();
5+
6+
fn objc_msgSendSuper();
7+
}
8+
9+
pub fn msg_send_fn<R>() -> Imp {
510
// stret is not even available in arm64.
611
// <https://twitter.com/gparker/status/378079715824660480>
712

8-
extern {
9-
fn objc_msgSend();
10-
}
11-
12-
(objc_msgSend, obj)
13+
objc_msgSend
1314
}
1415

15-
pub fn msg_send_super_fn<R>(sup: &Super, _: Sel) -> (Imp, *mut Object) {
16-
extern {
17-
fn objc_msgSendSuper();
18-
}
19-
20-
(objc_msgSendSuper, sup as *const Super as *mut Object)
16+
pub fn msg_send_super_fn<R>() -> Imp {
17+
objc_msgSendSuper
2118
}

src/message/apple/mod.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use super::Super;
1+
use std::any::Any;
2+
3+
use runtime::{Class, Object, Sel};
4+
use super::{Message, MessageArguments, MessageError, Super};
25

36
#[cfg(target_arch = "x86")]
47
#[path = "x86.rs"]
@@ -13,4 +16,25 @@ mod arch;
1316
#[path = "arm64.rs"]
1417
mod arch;
1518

16-
pub use self::arch::{msg_send_fn, msg_send_super_fn};
19+
use self::arch::{msg_send_fn, msg_send_super_fn};
20+
21+
pub unsafe fn send_unverified<T, A, R>(obj: *const T, sel: Sel, args: A)
22+
-> Result<R, MessageError>
23+
where T: Message, A: MessageArguments, R: Any {
24+
let receiver = obj as *mut T as *mut Object;
25+
let msg_send_fn = msg_send_fn::<R>();
26+
objc_try!({
27+
A::invoke(msg_send_fn, receiver, sel, args)
28+
})
29+
}
30+
31+
pub unsafe fn send_super_unverified<T, A, R>(obj: *const T, superclass: &Class,
32+
sel: Sel, args: A) -> Result<R, MessageError>
33+
where T: Message, A: MessageArguments, R: Any {
34+
let sup = Super { receiver: obj as *mut T as *mut Object, superclass: superclass };
35+
let receiver = &sup as *const Super as *mut Object;
36+
let msg_send_fn = msg_send_super_fn::<R>();
37+
objc_try!({
38+
A::invoke(msg_send_fn, receiver, sel, args)
39+
})
40+
}

src/message/apple/x86.rs

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,40 @@
11
use std::any::{Any, TypeId};
22
use std::mem;
33

4-
use runtime::{Object, Imp, Sel};
5-
use super::Super;
4+
use runtime::Imp;
65

7-
pub fn msg_send_fn<R: Any>(obj: *mut Object, _: Sel) -> (Imp, *mut Object) {
6+
extern {
7+
fn objc_msgSend();
8+
fn objc_msgSend_fpret();
9+
fn objc_msgSend_stret();
10+
11+
fn objc_msgSendSuper();
12+
fn objc_msgSendSuper_stret();
13+
}
14+
15+
pub fn msg_send_fn<R: Any>() -> Imp {
816
// Structures 1 or 2 bytes in size are placed in EAX.
917
// Structures 4 or 8 bytes in size are placed in: EAX and EDX.
1018
// Structures of other sizes are placed at the address supplied by the caller.
1119
// <https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html>
1220

13-
extern {
14-
fn objc_msgSend();
15-
fn objc_msgSend_fpret();
16-
fn objc_msgSend_stret();
17-
}
18-
1921
let type_id = TypeId::of::<R>();
2022
let size = mem::size_of::<R>();
21-
let msg_fn = if type_id == TypeId::of::<f32>() ||
23+
if type_id == TypeId::of::<f32>() ||
2224
type_id == TypeId::of::<f64>() {
2325
objc_msgSend_fpret
2426
} else if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
2527
objc_msgSend
2628
} else {
2729
objc_msgSend_stret
28-
};
29-
30-
(msg_fn, obj)
31-
}
32-
33-
pub fn msg_send_super_fn<R: Any>(sup: &Super, _: Sel) -> (Imp, *mut Object) {
34-
extern {
35-
fn objc_msgSendSuper();
36-
fn objc_msgSendSuper_stret();
3730
}
31+
}
3832

33+
pub fn msg_send_super_fn<R: Any>() -> Imp {
3934
let size = mem::size_of::<R>();
40-
let msg_fn = if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
35+
if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
4136
objc_msgSendSuper
4237
} else {
4338
objc_msgSendSuper_stret
44-
};
45-
46-
(msg_fn, sup as *const Super as *mut Object)
39+
}
4740
}

src/message/apple/x86_64.rs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,32 @@
11
use std::mem;
22

3-
use runtime::{Object, Imp, Sel};
4-
use super::Super;
3+
use runtime::Imp;
54

6-
pub fn msg_send_fn<R>(obj: *mut Object, _: Sel) -> (Imp, *mut Object) {
5+
extern {
6+
fn objc_msgSend();
7+
fn objc_msgSend_stret();
8+
9+
fn objc_msgSendSuper();
10+
fn objc_msgSendSuper_stret();
11+
}
12+
13+
pub fn msg_send_fn<R>() -> Imp {
714
// If the size of an object is larger than two eightbytes, it has class MEMORY.
815
// If the type has class MEMORY, then the caller provides space for the return
916
// value and passes the address of this storage.
1017
// <http://people.freebsd.org/~obrien/amd64-elf-abi.pdf>
1118

12-
extern {
13-
fn objc_msgSend();
14-
fn objc_msgSend_stret();
15-
}
16-
17-
let msg_fn = if mem::size_of::<R>() <= 16 {
19+
if mem::size_of::<R>() <= 16 {
1820
objc_msgSend
1921
} else {
2022
objc_msgSend_stret
21-
};
22-
23-
(msg_fn, obj)
24-
}
25-
26-
pub fn msg_send_super_fn<R>(sup: &Super, _: Sel) -> (Imp, *mut Object) {
27-
extern {
28-
fn objc_msgSendSuper();
29-
fn objc_msgSendSuper_stret();
3023
}
24+
}
3125

32-
let msg_fn = if mem::size_of::<R>() <= 16 {
26+
pub fn msg_send_super_fn<R>() -> Imp {
27+
if mem::size_of::<R>() <= 16 {
3328
objc_msgSendSuper
3429
} else {
3530
objc_msgSendSuper_stret
36-
};
37-
38-
(msg_fn, sup as *const Super as *mut Object)
31+
}
3932
}

src/message/gnustep.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,35 @@
1-
use runtime::{Object, Imp, Sel};
2-
use super::Super;
1+
use std::any::Any;
2+
use std::mem;
33

4-
pub fn msg_send_fn<R>(obj: *mut Object, sel: Sel) -> (Imp, *mut Object) {
5-
extern {
6-
fn objc_msg_lookup(receiver: *mut Object, op: Sel) -> Imp;
7-
}
4+
use runtime::{Class, Object, Imp, Sel};
5+
use super::{Message, MessageArguments, MessageError, Super};
86

9-
let imp_fn = unsafe {
10-
objc_msg_lookup(obj, sel)
11-
};
12-
(imp_fn, obj)
7+
extern {
8+
fn objc_msg_lookup(receiver: *mut Object, op: Sel) -> Imp;
9+
fn objc_msg_lookup_super(sup: *const Super, sel: Sel) -> Imp;
1310
}
1411

15-
pub fn msg_send_super_fn<R>(sup: &Super, sel: Sel) -> (Imp, *mut Object) {
16-
extern {
17-
fn objc_msg_lookup_super(sup: *const Super, sel: Sel) -> Imp;
12+
pub unsafe fn send_unverified<T, A, R>(obj: *const T, sel: Sel, args: A)
13+
-> Result<R, MessageError>
14+
where T: Message, A: MessageArguments, R: Any {
15+
if obj.is_null() {
16+
return mem::zeroed();
1817
}
1918

20-
let imp_fn = unsafe {
21-
objc_msg_lookup_super(sup, sel)
22-
};
23-
(imp_fn, sup.receiver)
19+
let receiver = obj as *mut T as *mut Object;
20+
let msg_send_fn = objc_msg_lookup(receiver, sel);
21+
objc_try!({
22+
A::invoke(msg_send_fn, receiver, sel, args)
23+
})
24+
}
25+
26+
pub unsafe fn send_super_unverified<T, A, R>(obj: *const T, superclass: &Class,
27+
sel: Sel, args: A) -> Result<R, MessageError>
28+
where T: Message, A: MessageArguments, R: Any {
29+
let receiver = obj as *mut T as *mut Object;
30+
let sup = Super { receiver: receiver, superclass: superclass };
31+
let msg_send_fn = objc_msg_lookup_super(&sup, sel);
32+
objc_try!({
33+
A::invoke(msg_send_fn, receiver, sel, args)
34+
})
2435
}

src/message/mod.rs

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,21 @@ use std::mem;
66
use runtime::{Class, Imp, Object, Sel};
77
use {Encode, EncodeArguments};
88

9+
#[cfg(feature = "exception")]
10+
macro_rules! objc_try {
11+
($b:block) => (
12+
$crate::exception::try(|| $b).map_err(|exception| match exception {
13+
Some(exception) => MessageError(format!("Uncaught exception {:?}", &*exception)),
14+
None => MessageError("Uncaught exception nil".to_owned()),
15+
})
16+
)
17+
}
18+
19+
#[cfg(not(feature = "exception"))]
20+
macro_rules! objc_try {
21+
($b:block) => (Ok($b))
22+
}
23+
924
mod verify;
1025

1126
#[cfg(any(target_os = "macos", target_os = "ios"))]
@@ -15,7 +30,7 @@ mod platform;
1530
#[path = "gnustep.rs"]
1631
mod platform;
1732

18-
use self::platform::{msg_send_fn, msg_send_super_fn};
33+
use self::platform::{send_unverified, send_super_unverified};
1934
use self::verify::verify_message_signature;
2035

2136
/// Specifies the superclass of an instance.
@@ -151,30 +166,6 @@ impl Error for MessageError {
151166
}
152167
}
153168

154-
#[cfg(feature = "exception")]
155-
macro_rules! objc_try {
156-
($b:block) => (
157-
$crate::exception::try(|| $b).map_err(|exception| match exception {
158-
Some(exception) => MessageError(format!("Uncaught exception {:?}", &*exception)),
159-
None => MessageError("Uncaught exception nil".to_owned()),
160-
})
161-
)
162-
}
163-
164-
#[cfg(not(feature = "exception"))]
165-
macro_rules! objc_try {
166-
($b:block) => (Ok($b))
167-
}
168-
169-
unsafe fn send_unverified<T, A, R>(obj: *const T, sel: Sel, args: A)
170-
-> Result<R, MessageError>
171-
where T: Message, A: MessageArguments, R: Any {
172-
let (msg_send_fn, receiver) = msg_send_fn::<R>(obj as *mut T as *mut Object, sel);
173-
objc_try!({
174-
A::invoke(msg_send_fn, receiver, sel, args)
175-
})
176-
}
177-
178169
#[doc(hidden)]
179170
#[inline(always)]
180171
#[cfg(not(feature = "verify_message"))]
@@ -202,16 +193,6 @@ pub unsafe fn send_message<T, A, R>(obj: *const T, sel: Sel, args: A)
202193
})
203194
}
204195

205-
unsafe fn send_super_unverified<T, A, R>(obj: *const T, superclass: &Class,
206-
sel: Sel, args: A) -> Result<R, MessageError>
207-
where T: Message, A: MessageArguments, R: Any {
208-
let sup = Super { receiver: obj as *mut T as *mut Object, superclass: superclass };
209-
let (msg_send_fn, receiver) = msg_send_super_fn::<R>(&sup, sel);
210-
objc_try!({
211-
A::invoke(msg_send_fn, receiver, sel, args)
212-
})
213-
}
214-
215196
#[doc(hidden)]
216197
#[inline(always)]
217198
#[cfg(not(feature = "verify_message"))]

0 commit comments

Comments
 (0)