Skip to content

Commit 54120d9

Browse files
committed
---
yaml --- r: 89784 b: refs/heads/master c: 7755ffd h: refs/heads/master v: v3
1 parent 47003b3 commit 54120d9

File tree

113 files changed

+263
-1053
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+263
-1053
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: 4d9b95fada7c97ac1c63099bab1d45ba120958ec
2+
refs/heads/master: 7755ffd0131fa99ca5d58bdd5eab443b44d5a1ff
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: a6d3e57dca68fde4effdda3e4ae2887aa535fcd6
55
refs/heads/try: b160761e35efcd1207112b3b782c06633cf441a8

trunk/doc/tutorial-ffi.md

Lines changed: 25 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@ extern {
1919
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
2020
}
2121
22-
#[fixed_stack_segment]
2322
fn main() {
2423
let x = unsafe { snappy_max_compressed_length(100) };
25-
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
24+
println!("max compressed length of a 100 byte buffer: {}", x);
2625
}
2726
~~~~
2827

@@ -36,11 +35,6 @@ interfaces that aren't thread-safe, and almost any function that takes a pointer
3635
valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of
3736
Rust's safe memory model.
3837

39-
Finally, the `#[fixed_stack_segment]` annotation that appears on
40-
`main()` instructs the Rust compiler that when `main()` executes, it
41-
should request a "very large" stack segment. More details on
42-
stack management can be found in the following sections.
43-
4438
When declaring the argument types to a foreign function, the Rust compiler will not check if the
4539
declaration is correct, so specifying it correctly is part of keeping the binding correct at
4640
runtime.
@@ -81,8 +75,6 @@ length is number of elements currently contained, and the capacity is the total
8175
the allocated memory. The length is less than or equal to the capacity.
8276

8377
~~~~ {.xfail-test}
84-
#[fixed_stack_segment]
85-
#[inline(never)]
8678
pub fn validate_compressed_buffer(src: &[u8]) -> bool {
8779
unsafe {
8880
snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0
@@ -94,36 +86,6 @@ The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, b
9486
guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
9587
signature.
9688

97-
The `validate_compressed_buffer` wrapper is also annotated with two
98-
attributes `#[fixed_stack_segment]` and `#[inline(never)]`. The
99-
purpose of these attributes is to guarantee that there will be
100-
sufficient stack for the C function to execute. This is necessary
101-
because Rust, unlike C, does not assume that the stack is allocated in
102-
one continuous chunk. Instead, we rely on a *segmented stack* scheme,
103-
in which the stack grows and shrinks as necessary. C code, however,
104-
expects one large stack, and so callers of C functions must request a
105-
large stack segment to ensure that the C routine will not run off the
106-
end of the stack.
107-
108-
The compiler includes a lint mode that will report an error if you
109-
call a C function without a `#[fixed_stack_segment]` attribute. More
110-
details on the lint mode are given in a later section.
111-
112-
You may be wondering why we include a `#[inline(never)]` directive.
113-
This directive informs the compiler never to inline this function.
114-
While not strictly necessary, it is usually a good idea to use an
115-
`#[inline(never)]` directive in concert with `#[fixed_stack_segment]`.
116-
The reason is that if a fn annotated with `fixed_stack_segment` is
117-
inlined, then its caller also inherits the `fixed_stack_segment`
118-
annotation. This means that rather than requesting a large stack
119-
segment only for the duration of the call into C, the large stack
120-
segment would be used for the entire duration of the caller. This is
121-
not necessarily *bad* -- it can for example be more efficient,
122-
particularly if `validate_compressed_buffer()` is called multiple
123-
times in a row -- but it does work against the purpose of the
124-
segmented stack scheme, which is to keep stacks small and thus
125-
conserve address space.
126-
12789
The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
12890
allocated to hold the output too.
12991

@@ -134,8 +96,6 @@ the true length after compression for setting the length.
13496

13597
~~~~ {.xfail-test}
13698
pub fn compress(src: &[u8]) -> ~[u8] {
137-
#[fixed_stack_segment]; #[inline(never)];
138-
13999
unsafe {
140100
let srclen = src.len() as size_t;
141101
let psrc = vec::raw::to_ptr(src);
@@ -156,8 +116,6 @@ format and `snappy_uncompressed_length` will retrieve the exact buffer size requ
156116

157117
~~~~ {.xfail-test}
158118
pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
159-
#[fixed_stack_segment]; #[inline(never)];
160-
161119
unsafe {
162120
let srclen = src.len() as size_t;
163121
let psrc = vec::raw::to_ptr(src);
@@ -181,98 +139,28 @@ pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
181139
For reference, the examples used here are also available as an [library on
182140
GitHub](https://github.com/thestinger/rust-snappy).
183141

184-
# Automatic wrappers
185-
186-
Sometimes writing Rust wrappers can be quite tedious. For example, if
187-
function does not take any pointer arguments, often there is no need
188-
for translating types. In such cases, it is usually still a good idea
189-
to have a Rust wrapper so as to manage the segmented stacks, but you
190-
can take advantage of the (standard) `externfn!` macro to remove some
191-
of the tedium.
192-
193-
In the initial section, we showed an extern block that added a call
194-
to a specific snappy API:
195-
196-
~~~~ {.xfail-test}
197-
use std::libc::size_t;
198-
199-
#[link_args = "-lsnappy"]
200-
extern {
201-
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
202-
}
203-
204-
#[fixed_stack_segment]
205-
fn main() {
206-
let x = unsafe { snappy_max_compressed_length(100) };
207-
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
208-
}
209-
~~~~
210-
211-
To avoid the need to create a wrapper fn for `snappy_max_compressed_length()`,
212-
and also to avoid the need to think about `#[fixed_stack_segment]`, we
213-
could simply use the `externfn!` macro instead, as shown here:
214-
215-
~~~~ {.xfail-test}
216-
use std::libc::size_t;
217-
218-
externfn!(#[link_args = "-lsnappy"]
219-
fn snappy_max_compressed_length(source_length: size_t) -> size_t)
220-
221-
fn main() {
222-
let x = unsafe { snappy_max_compressed_length(100) };
223-
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
224-
}
225-
~~~~
226-
227-
As you can see from the example, `externfn!` replaces the extern block
228-
entirely. After macro expansion, it will create something like this:
229-
230-
~~~~ {.xfail-test}
231-
use std::libc::size_t;
232-
233-
// Automatically generated by
234-
// externfn!(#[link_args = "-lsnappy"]
235-
// fn snappy_max_compressed_length(source_length: size_t) -> size_t)
236-
unsafe fn snappy_max_compressed_length(source_length: size_t) -> size_t {
237-
#[fixed_stack_segment]; #[inline(never)];
238-
return snappy_max_compressed_length(source_length);
239-
240-
#[link_args = "-lsnappy"]
241-
extern {
242-
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
243-
}
244-
}
245-
246-
fn main() {
247-
let x = unsafe { snappy_max_compressed_length(100) };
248-
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
249-
}
250-
~~~~
251-
252-
# Segmented stacks and the linter
253-
254-
By default, whenever you invoke a non-Rust fn, the `cstack` lint will
255-
check that one of the following conditions holds:
256-
257-
1. The call occurs inside of a fn that has been annotated with
258-
`#[fixed_stack_segment]`;
259-
2. The call occurs inside of an `extern fn`;
260-
3. The call occurs within a stack closure created by some other
261-
safe fn.
262-
263-
All of these conditions ensure that you are running on a large stack
264-
segment. However, they are sometimes too strict. If your application
265-
will be making many calls into C, it is often beneficial to promote
266-
the `#[fixed_stack_segment]` attribute higher up the call chain. For
267-
example, the Rust compiler actually labels main itself as requiring a
268-
`#[fixed_stack_segment]`. In such cases, the linter is just an
269-
annoyance, because all C calls that occur from within the Rust
270-
compiler are made on a large stack. Another situation where this
271-
frequently occurs is on a 64-bit architecture, where large stacks are
272-
the default. In cases, you can disable the linter by including a
273-
`#[allow(cstack)]` directive somewhere, which permits violations of
274-
the "cstack" rules given above (you can also use `#[warn(cstack)]` to
275-
convert the errors into warnings, if you prefer).
142+
# Stack management
143+
144+
Rust tasks by default run on a "large stack". This is actually implemented as a
145+
reserving a large segment of the address space and then lazily mapping in pages
146+
as they are needed. When calling an external C function, the code is invoked on
147+
the same stack as the rust stack. This means that there is no extra
148+
stack-switching mechanism in place because it is assumed that the large stack
149+
for the rust task is plenty for the C function to have.
150+
151+
A planned future improvement (net yet implemented at the time of this writing)
152+
is to have a guard page at the end of every rust stack. No rust function will
153+
hit this guard page (due to rust's usage of LLVM's __morestack). The intention
154+
for this unmapped page is to prevent infinite recursion in C from overflowing
155+
onto other rust stacks. If the guard page is hit, then the process will be
156+
terminated with a message saying that the guard page was hit.
157+
158+
For normal external function usage, this all means that there shouldn't be any
159+
need for any extra effort on a user's perspective. The C stack naturally
160+
interleaves with the rust stack, and it's "large enough" for both to
161+
interoperate. If, however, it is determined that a larger stack is necessary,
162+
there are appropriate functions in the task spawning API to control the size of
163+
the stack of the task which is spawned.
276164

277165
# Destructors
278166

@@ -296,9 +184,6 @@ pub struct Unique<T> {
296184
297185
impl<T: Send> Unique<T> {
298186
pub fn new(value: T) -> Unique<T> {
299-
#[fixed_stack_segment];
300-
#[inline(never)];
301-
302187
unsafe {
303188
let ptr = malloc(std::mem::size_of::<T>() as size_t) as *mut T;
304189
assert!(!ptr::is_null(ptr));
@@ -322,9 +207,6 @@ impl<T: Send> Unique<T> {
322207
#[unsafe_destructor]
323208
impl<T: Send> Drop for Unique<T> {
324209
fn drop(&mut self) {
325-
#[fixed_stack_segment];
326-
#[inline(never)];
327-
328210
unsafe {
329211
let x = intrinsics::init(); // dummy value to swap in
330212
// moving the object out is needed to call the destructor
@@ -384,8 +266,8 @@ extern {
384266
}
385267
386268
fn main() {
387-
println(fmt!("You have readline version %d installed.",
388-
rl_readline_version as int));
269+
println!("You have readline version {} installed.",
270+
rl_readline_version as int);
389271
}
390272
~~~
391273

trunk/src/libextra/c_vec.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ mod tests {
162162
}
163163

164164
impl Runnable for LibcFree {
165-
#[fixed_stack_segment]
166165
fn run(~self) {
167166
unsafe {
168167
libc::free(self.mem)
@@ -171,9 +170,6 @@ mod tests {
171170
}
172171

173172
fn malloc(n: size_t) -> CVec<u8> {
174-
#[fixed_stack_segment];
175-
#[inline(never)];
176-
177173
unsafe {
178174
let mem = libc::malloc(n);
179175

trunk/src/libextra/flate.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adle
4747
static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
4848

4949
fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
50-
#[fixed_stack_segment]; #[inline(never)];
51-
5250
do bytes.as_imm_buf |b, len| {
5351
unsafe {
5452
let mut outsz : size_t = 0;
@@ -75,8 +73,6 @@ pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
7573
}
7674

7775
fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
78-
#[fixed_stack_segment]; #[inline(never)];
79-
8076
do bytes.as_imm_buf |b, len| {
8177
unsafe {
8278
let mut outsz : size_t = 0;

trunk/src/libextra/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ Rust extras are part of the standard Rust distribution.
3838

3939
#[deny(non_camel_case_types)];
4040
#[deny(missing_doc)];
41+
#[allow(unrecognized_lint)]; // NOTE: remove after the next snapshot
42+
#[allow(cstack)]; // NOTE: remove after the next snapshot.
4143

4244
use std::str::{StrSlice, OwnedStr};
4345

trunk/src/libextra/test.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,6 @@ fn optgroups() -> ~[getopts::groups::OptGroup] {
220220
}
221221

222222
fn usage(binary: &str, helpstr: &str) {
223-
#[fixed_stack_segment]; #[inline(never)];
224-
225223
let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
226224
println(groups::usage(message, optgroups()));
227225
println("");

trunk/src/libextra/time.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ impl Ord for Timespec {
6363
* nanoseconds since 1970-01-01T00:00:00Z.
6464
*/
6565
pub fn get_time() -> Timespec {
66-
#[fixed_stack_segment]; #[inline(never)];
67-
6866
unsafe {
6967
let mut sec = 0i64;
7068
let mut nsec = 0i32;
@@ -79,8 +77,6 @@ pub fn get_time() -> Timespec {
7977
* in nanoseconds since an unspecified epoch.
8078
*/
8179
pub fn precise_time_ns() -> u64 {
82-
#[fixed_stack_segment]; #[inline(never)];
83-
8480
unsafe {
8581
let mut ns = 0u64;
8682
rustrt::precise_time_ns(&mut ns);
@@ -98,8 +94,6 @@ pub fn precise_time_s() -> f64 {
9894
}
9995

10096
pub fn tzset() {
101-
#[fixed_stack_segment]; #[inline(never)];
102-
10397
unsafe {
10498
rustrt::rust_tzset();
10599
}
@@ -143,8 +137,6 @@ pub fn empty_tm() -> Tm {
143137

144138
/// Returns the specified time in UTC
145139
pub fn at_utc(clock: Timespec) -> Tm {
146-
#[fixed_stack_segment]; #[inline(never)];
147-
148140
unsafe {
149141
let Timespec { sec, nsec } = clock;
150142
let mut tm = empty_tm();
@@ -160,8 +152,6 @@ pub fn now_utc() -> Tm {
160152

161153
/// Returns the specified time in the local timezone
162154
pub fn at(clock: Timespec) -> Tm {
163-
#[fixed_stack_segment]; #[inline(never)];
164-
165155
unsafe {
166156
let Timespec { sec, nsec } = clock;
167157
let mut tm = empty_tm();
@@ -179,8 +169,6 @@ pub fn now() -> Tm {
179169
impl Tm {
180170
/// Convert time to the seconds from January 1, 1970
181171
pub fn to_timespec(&self) -> Timespec {
182-
#[fixed_stack_segment]; #[inline(never)];
183-
184172
unsafe {
185173
let sec = match self.tm_gmtoff {
186174
0_i32 => rustrt::rust_timegm(self),
@@ -969,7 +957,6 @@ mod tests {
969957
use std::libc;
970958
971959
#[cfg(windows)]
972-
#[fixed_stack_segment]
973960
fn set_time_zone() {
974961
// Windows crt doesn't see any environment variable set by
975962
// `SetEnvironmentVariable`, which `os::setenv` internally uses.

trunk/src/librustc/driver/driver.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,6 @@ pub fn phase_3_run_analysis_passes(sess: Session,
278278
time(time_passes, "loop checking", (), |_|
279279
middle::check_loop::check_crate(ty_cx, crate));
280280

281-
time(time_passes, "stack checking", (), |_|
282-
middle::stack_check::stack_check_crate(ty_cx, crate));
283-
284281
let middle::moves::MoveMaps {moves_map, moved_variables_set,
285282
capture_map} =
286283
time(time_passes, "compute moves", (), |_|
@@ -428,7 +425,6 @@ pub fn stop_after_phase_5(sess: Session) -> bool {
428425
return false;
429426
}
430427

431-
#[fixed_stack_segment]
432428
pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
433429
outdir: &Option<Path>, output: &Option<Path>) {
434430
// We need nested scopes here, because the intermediate results can keep
@@ -703,12 +699,7 @@ pub fn build_session_options(binary: @str,
703699
}
704700

705701
if debugging_opts & session::debug_llvm != 0 {
706-
set_llvm_debug();
707-
708-
fn set_llvm_debug() {
709-
#[fixed_stack_segment]; #[inline(never)];
710-
unsafe { llvm::LLVMSetDebug(1); }
711-
}
702+
unsafe { llvm::LLVMSetDebug(1); }
712703
}
713704

714705
let output_type =

0 commit comments

Comments
 (0)