]> git.lizzy.rs Git - rust.git/blob - src/libcore/sys.rs
core: Wire up the unwinder to newsched again
[rust.git] / src / libcore / sys.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Misc low level stuff
12
13 use option::{Some, None};
14 use cast;
15 use cmp::{Eq, Ord};
16 use gc;
17 use io;
18 use libc;
19 use libc::{c_void, c_char, size_t};
20 use repr;
21 use str;
22
23 pub type FreeGlue<'self> = &'self fn(*TypeDesc, *c_void);
24
25 // Corresponds to runtime type_desc type
26 pub struct TypeDesc {
27     size: uint,
28     align: uint,
29     take_glue: uint,
30     drop_glue: uint,
31     free_glue: uint
32     // Remaining fields not listed
33 }
34
35 /// The representation of a Rust closure
36 pub struct Closure {
37     code: *(),
38     env: *(),
39 }
40
41 pub mod rusti {
42     #[abi = "rust-intrinsic"]
43     pub extern "rust-intrinsic" {
44         fn get_tydesc<T>() -> *();
45         fn size_of<T>() -> uint;
46         fn pref_align_of<T>() -> uint;
47         fn min_align_of<T>() -> uint;
48     }
49 }
50
51 pub mod rustrt {
52     use libc::{c_char, size_t};
53
54     pub extern {
55         #[rust_stack]
56         unsafe fn rust_upcall_fail(expr: *c_char,
57                                    file: *c_char,
58                                    line: size_t);
59     }
60 }
61
62 /// Compares contents of two pointers using the default method.
63 /// Equivalent to `*x1 == *x2`.  Useful for hashtables.
64 pub fn shape_eq<T:Eq>(x1: &T, x2: &T) -> bool {
65     *x1 == *x2
66 }
67
68 pub fn shape_lt<T:Ord>(x1: &T, x2: &T) -> bool {
69     *x1 < *x2
70 }
71
72 pub fn shape_le<T:Ord>(x1: &T, x2: &T) -> bool {
73     *x1 <= *x2
74 }
75
76 /**
77  * Returns a pointer to a type descriptor.
78  *
79  * Useful for calling certain function in the Rust runtime or otherwise
80  * performing dark magick.
81  */
82 #[inline(always)]
83 pub fn get_type_desc<T>() -> *TypeDesc {
84     unsafe { rusti::get_tydesc::<T>() as *TypeDesc }
85 }
86
87 /// Returns a pointer to a type descriptor.
88 #[inline(always)]
89 pub fn get_type_desc_val<T>(_val: &T) -> *TypeDesc {
90     get_type_desc::<T>()
91 }
92
93 /// Returns the size of a type
94 #[inline(always)]
95 pub fn size_of<T>() -> uint {
96     unsafe { rusti::size_of::<T>() }
97 }
98
99 /// Returns the size of the type that `_val` points to
100 #[inline(always)]
101 pub fn size_of_val<T>(_val: &T) -> uint {
102     size_of::<T>()
103 }
104
105 /**
106  * Returns the size of a type, or 1 if the actual size is zero.
107  *
108  * Useful for building structures containing variable-length arrays.
109  */
110 #[inline(always)]
111 pub fn nonzero_size_of<T>() -> uint {
112     let s = size_of::<T>();
113     if s == 0 { 1 } else { s }
114 }
115
116 /// Returns the size of the type of the value that `_val` points to
117 #[inline(always)]
118 pub fn nonzero_size_of_val<T>(_val: &T) -> uint {
119     nonzero_size_of::<T>()
120 }
121
122
123 /**
124  * Returns the ABI-required minimum alignment of a type
125  *
126  * This is the alignment used for struct fields. It may be smaller
127  * than the preferred alignment.
128  */
129 #[inline(always)]
130 pub fn min_align_of<T>() -> uint {
131     unsafe { rusti::min_align_of::<T>() }
132 }
133
134 /// Returns the ABI-required minimum alignment of the type of the value that
135 /// `_val` points to
136 #[inline(always)]
137 pub fn min_align_of_val<T>(_val: &T) -> uint {
138     min_align_of::<T>()
139 }
140
141 /// Returns the preferred alignment of a type
142 #[inline(always)]
143 pub fn pref_align_of<T>() -> uint {
144     unsafe { rusti::pref_align_of::<T>() }
145 }
146
147 /// Returns the preferred alignment of the type of the value that
148 /// `_val` points to
149 #[inline(always)]
150 pub fn pref_align_of_val<T>(_val: &T) -> uint {
151     pref_align_of::<T>()
152 }
153
154 /// Returns the refcount of a shared box (as just before calling this)
155 #[inline(always)]
156 pub fn refcount<T>(t: @T) -> uint {
157     unsafe {
158         let ref_ptr: *uint = cast::transmute_copy(&t);
159         *ref_ptr - 1
160     }
161 }
162
163 pub fn log_str<T>(t: &T) -> ~str {
164     do io::with_str_writer |wr| {
165         repr::write_repr(wr, t)
166     }
167 }
168
169 /// Trait for initiating task failure.
170 pub trait FailWithCause {
171     /// Fail the current task, taking ownership of `cause`
172     fn fail_with(cause: Self, file: &'static str, line: uint) -> !;
173 }
174
175 impl FailWithCause for ~str {
176     fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! {
177         do str::as_buf(cause) |msg_buf, _msg_len| {
178             do str::as_buf(file) |file_buf, _file_len| {
179                 unsafe {
180                     let msg_buf = cast::transmute(msg_buf);
181                     let file_buf = cast::transmute(file_buf);
182                     begin_unwind_(msg_buf, file_buf, line as libc::size_t)
183                 }
184             }
185         }
186     }
187 }
188
189 impl FailWithCause for &'static str {
190     fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
191         do str::as_buf(cause) |msg_buf, _msg_len| {
192             do str::as_buf(file) |file_buf, _file_len| {
193                 unsafe {
194                     let msg_buf = cast::transmute(msg_buf);
195                     let file_buf = cast::transmute(file_buf);
196                     begin_unwind_(msg_buf, file_buf, line as libc::size_t)
197                 }
198             }
199         }
200     }
201 }
202
203 // NOTE: remove function after snapshot
204 #[cfg(stage0)]
205 pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! {
206
207     do str::as_buf(msg) |msg_buf, _msg_len| {
208         do str::as_buf(file) |file_buf, _file_len| {
209             unsafe {
210                 let msg_buf = cast::transmute(msg_buf);
211                 let file_buf = cast::transmute(file_buf);
212                 begin_unwind_(msg_buf, file_buf, line as libc::size_t)
213             }
214         }
215     }
216 }
217
218 // FIXME #4427: Temporary until rt::rt_fail_ goes away
219 pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
220     use rt::{context, OldTaskContext};
221     use rt::local_services::unsafe_borrow_local_services;
222
223     match context() {
224         OldTaskContext => {
225             unsafe {
226                 gc::cleanup_stack_for_failure();
227                 rustrt::rust_upcall_fail(msg, file, line);
228                 cast::transmute(())
229             }
230         }
231         _ => {
232             // XXX: Need to print the failure message
233             gc::cleanup_stack_for_failure();
234             unsafe {
235                 let local_services = unsafe_borrow_local_services();
236                 match local_services.unwinder {
237                     Some(ref mut unwinder) => unwinder.begin_unwind(),
238                     None => abort!("failure without unwinder. aborting process")
239                 }
240             }
241         }
242     }
243 }
244
245 // NOTE: remove function after snapshot
246 #[cfg(stage0)]
247 pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! {
248     let (msg, file) = (msg.to_owned(), file.to_owned());
249     begin_unwind(~"assertion failed: " + msg, file, line)
250 }
251
252 #[cfg(test)]
253 mod tests {
254     use cast;
255     use sys::*;
256
257     #[test]
258     fn size_of_basic() {
259         assert!(size_of::<u8>() == 1u);
260         assert!(size_of::<u16>() == 2u);
261         assert!(size_of::<u32>() == 4u);
262         assert!(size_of::<u64>() == 8u);
263     }
264
265     #[test]
266     #[cfg(target_arch = "x86")]
267     #[cfg(target_arch = "arm")]
268     #[cfg(target_arch = "mips")]
269     fn size_of_32() {
270         assert!(size_of::<uint>() == 4u);
271         assert!(size_of::<*uint>() == 4u);
272     }
273
274     #[test]
275     #[cfg(target_arch = "x86_64")]
276     fn size_of_64() {
277         assert!(size_of::<uint>() == 8u);
278         assert!(size_of::<*uint>() == 8u);
279     }
280
281     #[test]
282     fn size_of_val_basic() {
283         assert_eq!(size_of_val(&1u8), 1);
284         assert_eq!(size_of_val(&1u16), 2);
285         assert_eq!(size_of_val(&1u32), 4);
286         assert_eq!(size_of_val(&1u64), 8);
287     }
288
289     #[test]
290     fn nonzero_size_of_basic() {
291         type Z = [i8, ..0];
292         assert!(size_of::<Z>() == 0u);
293         assert!(nonzero_size_of::<Z>() == 1u);
294         assert!(nonzero_size_of::<uint>() == size_of::<uint>());
295     }
296
297     #[test]
298     fn nonzero_size_of_val_basic() {
299         let z = [0u8, ..0];
300         assert_eq!(size_of_val(&z), 0u);
301         assert_eq!(nonzero_size_of_val(&z), 1u);
302         assert_eq!(nonzero_size_of_val(&1u), size_of_val(&1u));
303     }
304
305     #[test]
306     fn align_of_basic() {
307         assert!(pref_align_of::<u8>() == 1u);
308         assert!(pref_align_of::<u16>() == 2u);
309         assert!(pref_align_of::<u32>() == 4u);
310     }
311
312     #[test]
313     #[cfg(target_arch = "x86")]
314     #[cfg(target_arch = "arm")]
315     #[cfg(target_arch = "mips")]
316     fn align_of_32() {
317         assert!(pref_align_of::<uint>() == 4u);
318         assert!(pref_align_of::<*uint>() == 4u);
319     }
320
321     #[test]
322     #[cfg(target_arch = "x86_64")]
323     fn align_of_64() {
324         assert!(pref_align_of::<uint>() == 8u);
325         assert!(pref_align_of::<*uint>() == 8u);
326     }
327
328     #[test]
329     fn align_of_val_basic() {
330         assert_eq!(pref_align_of_val(&1u8), 1u);
331         assert_eq!(pref_align_of_val(&1u16), 2u);
332         assert_eq!(pref_align_of_val(&1u32), 4u);
333     }
334
335     #[test]
336     fn synthesize_closure() {
337         unsafe {
338             let x = 10;
339             let f: &fn(int) -> int = |y| x + y;
340
341             assert!(f(20) == 30);
342
343             let original_closure: Closure = cast::transmute(f);
344
345             let actual_function_pointer = original_closure.code;
346             let environment = original_closure.env;
347
348             let new_closure = Closure {
349                 code: actual_function_pointer,
350                 env: environment
351             };
352
353             let new_f: &fn(int) -> int = cast::transmute(new_closure);
354             assert!(new_f(20) == 30);
355         }
356     }
357
358     #[test]
359     #[should_fail]
360     fn fail_static() { FailWithCause::fail_with("cause", file!(), line!())  }
361
362     #[test]
363     #[should_fail]
364     fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!())  }
365 }
366
367 // Local Variables:
368 // mode: rust;
369 // fill-column: 78;
370 // indent-tabs-mode: nil
371 // c-basic-offset: 4
372 // buffer-file-coding-system: utf-8-unix
373 // End: