From: Alex Crichton Date: Thu, 15 Jan 2015 22:11:53 +0000 (-0800) Subject: rollup merge of #21127: erickt/opt-stack X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=b1a7e34fc0b5e27891eec8920b063b9453d6a14f;hp=4c4092d73695fd162522e6b481d17a0b37b40e64;p=rust.git rollup merge of #21127: erickt/opt-stack libsyntax compiled without optimization uses a lot of stack, which can cause it to run out of stack space. This PR factors out some arm handlers from `print_expr` as well as converts `advance_left` into a loop. This helps to cut down on the stack usage. --- diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index b69b812c958..06d510d37bd 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -59,10 +59,6 @@ //! line (which it can't) and so naturally place the content on its own line to //! avoid combining it with other lines and making matters even worse. -pub use self::PrintStackBreak::*; -pub use self::Breaks::*; -pub use self::Token::*; - use std::io; use std::string; use std::iter::repeat; @@ -87,7 +83,7 @@ pub struct BeginToken { #[derive(Clone)] pub enum Token { - String(string::String, int), + String(String, int), Break(BreakToken), Begin(BeginToken), End, @@ -96,12 +92,15 @@ pub enum Token { impl Token { pub fn is_eof(&self) -> bool { - match *self { Eof => true, _ => false } + match *self { + Token::Eof => true, + _ => false, + } } pub fn is_hardbreak_tok(&self) -> bool { match *self { - Break(BreakToken { + Token::Break(BreakToken { offset: 0, blank_space: bs }) if bs == SIZE_INFINITY => @@ -112,22 +111,22 @@ pub fn is_hardbreak_tok(&self) -> bool { } } -pub fn tok_str(t: Token) -> string::String { - match t { - String(s, len) => return format!("STR({},{})", s, len), - Break(_) => return "BREAK".to_string(), - Begin(_) => return "BEGIN".to_string(), - End => return "END".to_string(), - Eof => return "EOF".to_string() +pub fn tok_str(token: &Token) -> String { + match *token { + Token::String(ref s, len) => format!("STR({},{})", s, len), + Token::Break(_) => "BREAK".to_string(), + Token::Begin(_) => "BEGIN".to_string(), + Token::End => "END".to_string(), + Token::Eof => "EOF".to_string() } } -pub fn buf_str(toks: Vec, - szs: Vec, +pub fn buf_str(toks: &[Token], + szs: &[int], left: uint, right: uint, lim: uint) - -> string::String { + -> String { let n = toks.len(); assert_eq!(n, szs.len()); let mut i = left; @@ -140,7 +139,7 @@ pub fn buf_str(toks: Vec, } s.push_str(&format!("{}={}", szs[i], - tok_str(toks[i].clone()))[]); + tok_str(&toks[i]))[]); i += 1u; i %= n; } @@ -167,7 +166,7 @@ pub fn mk_printer(out: Box, linewidth: uint) -> Printer { // fall behind. let n: uint = 3 * linewidth; debug!("mk_printer {}", linewidth); - let token: Vec = repeat(Eof).take(n).collect(); + let token: Vec = repeat(Token::Eof).take(n).collect(); let size: Vec = repeat(0i).take(n).collect(); let scan_stack: Vec = repeat(0u).take(n).collect(); Printer { @@ -312,20 +311,18 @@ pub fn last_token(&mut self) -> Token { pub fn replace_last_token(&mut self, t: Token) { self.token[self.right] = t; } - pub fn pretty_print(&mut self, t: Token) -> io::IoResult<()> { + pub fn pretty_print(&mut self, token: Token) -> io::IoResult<()> { debug!("pp ~[{},{}]", self.left, self.right); - match t { - Eof => { + match token { + Token::Eof => { if !self.scan_stack_empty { self.check_stack(0); - let left = self.token[self.left].clone(); - let left_size = self.size[self.left]; - try!(self.advance_left(left, left_size)); + try!(self.advance_left()); } self.indent(0); Ok(()) } - Begin(b) => { + Token::Begin(b) => { if self.scan_stack_empty { self.left_total = 1; self.right_total = 1; @@ -334,27 +331,27 @@ pub fn pretty_print(&mut self, t: Token) -> io::IoResult<()> { } else { self.advance_right(); } debug!("pp Begin({})/buffer ~[{},{}]", b.offset, self.left, self.right); - self.token[self.right] = t; + self.token[self.right] = token; self.size[self.right] = -self.right_total; let right = self.right; self.scan_push(right); Ok(()) } - End => { + Token::End => { if self.scan_stack_empty { debug!("pp End/print ~[{},{}]", self.left, self.right); - self.print(t, 0) + self.print(token, 0) } else { debug!("pp End/buffer ~[{},{}]", self.left, self.right); self.advance_right(); - self.token[self.right] = t; + self.token[self.right] = token; self.size[self.right] = -1; let right = self.right; self.scan_push(right); Ok(()) } } - Break(b) => { + Token::Break(b) => { if self.scan_stack_empty { self.left_total = 1; self.right_total = 1; @@ -366,21 +363,21 @@ pub fn pretty_print(&mut self, t: Token) -> io::IoResult<()> { self.check_stack(0); let right = self.right; self.scan_push(right); - self.token[self.right] = t; + self.token[self.right] = token; self.size[self.right] = -self.right_total; self.right_total += b.blank_space; Ok(()) } - String(ref s, len) => { + Token::String(s, len) => { if self.scan_stack_empty { debug!("pp String('{}')/print ~[{},{}]", - *s, self.left, self.right); - self.print(t.clone(), len) + s, self.left, self.right); + self.print(Token::String(s, len), len) } else { debug!("pp String('{}')/buffer ~[{},{}]", - *s, self.left, self.right); + s, self.left, self.right); self.advance_right(); - self.token[self.right] = t.clone(); + self.token[self.right] = Token::String(s, len); self.size[self.right] = len; self.right_total += len; self.check_stream() @@ -401,9 +398,7 @@ pub fn check_stream(&mut self) -> io::IoResult<()> { self.size[scanned] = SIZE_INFINITY; } } - let left = self.token[self.left].clone(); - let left_size = self.size[self.left]; - try!(self.advance_left(left, left_size)); + try!(self.advance_left()); if self.left != self.right { try!(self.check_stream()); } @@ -450,42 +445,52 @@ pub fn advance_right(&mut self) { self.right %= self.buf_len; assert!((self.right != self.left)); } - pub fn advance_left(&mut self, x: Token, l: int) -> io::IoResult<()> { + pub fn advance_left(&mut self) -> io::IoResult<()> { debug!("advance_left ~[{},{}], sizeof({})={}", self.left, self.right, - self.left, l); - if l >= 0 { - let ret = self.print(x.clone(), l); - match x { - Break(b) => self.left_total += b.blank_space, - String(_, len) => { - assert_eq!(len, l); self.left_total += len; - } - _ => () - } - if self.left != self.right { - self.left += 1u; - self.left %= self.buf_len; - let left = self.token[self.left].clone(); - let left_size = self.size[self.left]; - try!(self.advance_left(left, left_size)); + self.left, self.size[self.left]); + + let mut left_size = self.size[self.left]; + + while left_size >= 0 { + let left = self.token[self.left].clone(); + + let len = match left { + Token::Break(b) => b.blank_space, + Token::String(_, len) => { + assert_eq!(len, left_size); + len + } + _ => 0 + }; + + try!(self.print(left, left_size)); + + self.left_total += len; + + if self.left == self.right { + break; } - ret - } else { - Ok(()) + + self.left += 1u; + self.left %= self.buf_len; + + left_size = self.size[self.left]; } + + Ok(()) } pub fn check_stack(&mut self, k: int) { if !self.scan_stack_empty { let x = self.scan_top(); match self.token[x] { - Begin(_) => { + Token::Begin(_) => { if k > 0 { let popped = self.scan_pop(); self.size[popped] = self.size[x] + self.right_total; self.check_stack(k - 1); } } - End => { + Token::End => { // paper says + not =, but that makes no sense. let popped = self.scan_pop(); self.size[popped] = 1; @@ -520,7 +525,7 @@ pub fn get_top(&mut self) -> PrintStackElem { } else { PrintStackElem { offset: 0, - pbreak: Broken(Inconsistent) + pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) } } } @@ -531,56 +536,56 @@ pub fn print_str(&mut self, s: &str) -> io::IoResult<()> { } write!(self.out, "{}", s) } - pub fn print(&mut self, x: Token, l: int) -> io::IoResult<()> { - debug!("print {} {} (remaining line space={})", tok_str(x.clone()), l, + pub fn print(&mut self, token: Token, l: int) -> io::IoResult<()> { + debug!("print {} {} (remaining line space={})", tok_str(&token), l, self.space); - debug!("{}", buf_str(self.token.clone(), - self.size.clone(), + debug!("{}", buf_str(&self.token[], + &self.size[], self.left, self.right, 6)); - match x { - Begin(b) => { + match token { + Token::Begin(b) => { if l > self.space { let col = self.margin - self.space + b.offset; debug!("print Begin -> push broken block at col {}", col); self.print_stack.push(PrintStackElem { offset: col, - pbreak: Broken(b.breaks) + pbreak: PrintStackBreak::Broken(b.breaks) }); } else { debug!("print Begin -> push fitting block"); self.print_stack.push(PrintStackElem { offset: 0, - pbreak: Fits + pbreak: PrintStackBreak::Fits }); } Ok(()) } - End => { + Token::End => { debug!("print End -> pop End"); let print_stack = &mut self.print_stack; assert!((print_stack.len() != 0u)); print_stack.pop().unwrap(); Ok(()) } - Break(b) => { + Token::Break(b) => { let top = self.get_top(); match top.pbreak { - Fits => { + PrintStackBreak::Fits => { debug!("print Break({}) in fitting block", b.blank_space); self.space -= b.blank_space; self.indent(b.blank_space); Ok(()) } - Broken(Consistent) => { + PrintStackBreak::Broken(Breaks::Consistent) => { debug!("print Break({}+{}) in consistent block", top.offset, b.offset); let ret = self.print_newline(top.offset + b.offset); self.space = self.margin - (top.offset + b.offset); ret } - Broken(Inconsistent) => { + PrintStackBreak::Broken(Breaks::Inconsistent) => { if l > self.space { debug!("print Break({}+{}) w/ newline in inconsistent", top.offset, b.offset); @@ -597,14 +602,14 @@ pub fn print(&mut self, x: Token, l: int) -> io::IoResult<()> { } } } - String(s, len) => { + Token::String(s, len) => { debug!("print String({})", s); assert_eq!(l, len); // assert!(l <= space); self.space -= len; self.print_str(&s[]) } - Eof => { + Token::Eof => { // Eof should never get here. panic!(); } @@ -616,41 +621,45 @@ pub fn print(&mut self, x: Token, l: int) -> io::IoResult<()> { // // "raw box" pub fn rbox(p: &mut Printer, indent: uint, b: Breaks) -> io::IoResult<()> { - p.pretty_print(Begin(BeginToken { + p.pretty_print(Token::Begin(BeginToken { offset: indent as int, breaks: b })) } pub fn ibox(p: &mut Printer, indent: uint) -> io::IoResult<()> { - rbox(p, indent, Inconsistent) + rbox(p, indent, Breaks::Inconsistent) } pub fn cbox(p: &mut Printer, indent: uint) -> io::IoResult<()> { - rbox(p, indent, Consistent) + rbox(p, indent, Breaks::Consistent) } pub fn break_offset(p: &mut Printer, n: uint, off: int) -> io::IoResult<()> { - p.pretty_print(Break(BreakToken { + p.pretty_print(Token::Break(BreakToken { offset: off, blank_space: n as int })) } -pub fn end(p: &mut Printer) -> io::IoResult<()> { p.pretty_print(End) } +pub fn end(p: &mut Printer) -> io::IoResult<()> { + p.pretty_print(Token::End) +} -pub fn eof(p: &mut Printer) -> io::IoResult<()> { p.pretty_print(Eof) } +pub fn eof(p: &mut Printer) -> io::IoResult<()> { + p.pretty_print(Token::Eof) +} pub fn word(p: &mut Printer, wrd: &str) -> io::IoResult<()> { - p.pretty_print(String(/* bad */ wrd.to_string(), wrd.len() as int)) + p.pretty_print(Token::String(/* bad */ wrd.to_string(), wrd.len() as int)) } pub fn huge_word(p: &mut Printer, wrd: &str) -> io::IoResult<()> { - p.pretty_print(String(/* bad */ wrd.to_string(), SIZE_INFINITY)) + p.pretty_print(Token::String(/* bad */ wrd.to_string(), SIZE_INFINITY)) } pub fn zero_word(p: &mut Printer, wrd: &str) -> io::IoResult<()> { - p.pretty_print(String(/* bad */ wrd.to_string(), 0)) + p.pretty_print(Token::String(/* bad */ wrd.to_string(), 0)) } pub fn spaces(p: &mut Printer, n: uint) -> io::IoResult<()> { @@ -670,7 +679,9 @@ pub fn hardbreak(p: &mut Printer) -> io::IoResult<()> { } pub fn hardbreak_tok_offset(off: int) -> Token { - Break(BreakToken {offset: off, blank_space: SIZE_INFINITY}) + Token::Break(BreakToken {offset: off, blank_space: SIZE_INFINITY}) } -pub fn hardbreak_tok() -> Token { return hardbreak_tok_offset(0); } +pub fn hardbreak_tok() -> Token { + hardbreak_tok_offset(0) +} diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ec6672d22a9..5d76dc71006 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -25,7 +25,8 @@ use parse::lexer::comments; use parse; use print::pp::{self, break_offset, word, space, zerobreak, hardbreak}; -use print::pp::{Breaks, Consistent, Inconsistent, eof}; +use print::pp::{Breaks, eof}; +use print::pp::Breaks::{Consistent, Inconsistent}; use ptr::P; use std::{ascii, mem}; @@ -459,7 +460,7 @@ fn needs_parentheses(expr: &ast::Expr) -> bool { impl<'a> State<'a> { pub fn ibox(&mut self, u: uint) -> IoResult<()> { - self.boxes.push(pp::Inconsistent); + self.boxes.push(pp::Breaks::Inconsistent); pp::ibox(&mut self.s, u) } @@ -469,7 +470,7 @@ pub fn end(&mut self) -> IoResult<()> { } pub fn cbox(&mut self, u: uint) -> IoResult<()> { - self.boxes.push(pp::Consistent); + self.boxes.push(pp::Breaks::Consistent); pp::cbox(&mut self.s, u) } @@ -531,11 +532,17 @@ pub fn bclose(&mut self, span: codemap::Span) -> IoResult<()> { } pub fn is_begin(&mut self) -> bool { - match self.s.last_token() { pp::Begin(_) => true, _ => false } + match self.s.last_token() { + pp::Token::Begin(_) => true, + _ => false, + } } pub fn is_end(&mut self) -> bool { - match self.s.last_token() { pp::End => true, _ => false } + match self.s.last_token() { + pp::Token::End => true, + _ => false, + } } // is this the beginning of a line? @@ -545,7 +552,7 @@ pub fn is_bol(&mut self) -> bool { pub fn in_cbox(&self) -> bool { match self.boxes.last() { - Some(&last_box) => last_box == pp::Consistent, + Some(&last_box) => last_box == pp::Breaks::Consistent, None => false } } @@ -1497,108 +1504,168 @@ pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr) -> IoResult<()> { Ok(()) } + fn print_expr_box(&mut self, + place: &Option>, + expr: &ast::Expr) -> IoResult<()> { + try!(word(&mut self.s, "box")); + try!(word(&mut self.s, "(")); + try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e))); + try!(self.word_space(")")); + self.print_expr(expr) + } + + fn print_expr_vec(&mut self, exprs: &[P]) -> IoResult<()> { + try!(self.ibox(indent_unit)); + try!(word(&mut self.s, "[")); + try!(self.commasep_exprs(Inconsistent, &exprs[])); + try!(word(&mut self.s, "]")); + self.end() + } + + fn print_expr_repeat(&mut self, + element: &ast::Expr, + count: &ast::Expr) -> IoResult<()> { + try!(self.ibox(indent_unit)); + try!(word(&mut self.s, "[")); + try!(self.print_expr(element)); + try!(self.word_space(";")); + try!(self.print_expr(count)); + try!(word(&mut self.s, "]")); + self.end() + } + + fn print_expr_struct(&mut self, + path: &ast::Path, + fields: &[ast::Field], + wth: &Option>) -> IoResult<()> { + try!(self.print_path(path, true)); + if !(fields.is_empty() && wth.is_none()) { + try!(word(&mut self.s, "{")); + try!(self.commasep_cmnt( + Consistent, + &fields[], + |s, field| { + try!(s.ibox(indent_unit)); + try!(s.print_ident(field.ident.node)); + try!(s.word_space(":")); + try!(s.print_expr(&*field.expr)); + s.end() + }, + |f| f.span)); + match *wth { + Some(ref expr) => { + try!(self.ibox(indent_unit)); + if !fields.is_empty() { + try!(word(&mut self.s, ",")); + try!(space(&mut self.s)); + } + try!(word(&mut self.s, "..")); + try!(self.print_expr(&**expr)); + try!(self.end()); + } + _ => try!(word(&mut self.s, ",")), + } + try!(word(&mut self.s, "}")); + } + Ok(()) + } + + fn print_expr_tup(&mut self, exprs: &[P]) -> IoResult<()> { + try!(self.popen()); + try!(self.commasep_exprs(Inconsistent, &exprs[])); + if exprs.len() == 1 { + try!(word(&mut self.s, ",")); + } + self.pclose() + } + + fn print_expr_call(&mut self, + func: &ast::Expr, + args: &[P]) -> IoResult<()> { + try!(self.print_expr_maybe_paren(func)); + self.print_call_post(args) + } + + fn print_expr_method_call(&mut self, + ident: ast::SpannedIdent, + tys: &[P], + args: &[P]) -> IoResult<()> { + let base_args = args.slice_from(1); + try!(self.print_expr(&*args[0])); + try!(word(&mut self.s, ".")); + try!(self.print_ident(ident.node)); + if tys.len() > 0u { + try!(word(&mut self.s, "::<")); + try!(self.commasep(Inconsistent, tys, + |s, ty| s.print_type(&**ty))); + try!(word(&mut self.s, ">")); + } + self.print_call_post(base_args) + } + + fn print_expr_binary(&mut self, + op: ast::BinOp, + lhs: &ast::Expr, + rhs: &ast::Expr) -> IoResult<()> { + try!(self.print_expr(lhs)); + try!(space(&mut self.s)); + try!(self.word_space(ast_util::binop_to_string(op))); + self.print_expr(rhs) + } + + fn print_expr_unary(&mut self, + op: ast::UnOp, + expr: &ast::Expr) -> IoResult<()> { + try!(word(&mut self.s, ast_util::unop_to_string(op))); + self.print_expr_maybe_paren(expr) + } + + fn print_expr_addr_of(&mut self, + mutability: ast::Mutability, + expr: &ast::Expr) -> IoResult<()> { + try!(word(&mut self.s, "&")); + try!(self.print_mutability(mutability)); + self.print_expr_maybe_paren(expr) + } + pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> { try!(self.maybe_print_comment(expr.span.lo)); try!(self.ibox(indent_unit)); try!(self.ann.pre(self, NodeExpr(expr))); match expr.node { - ast::ExprBox(ref p, ref e) => { - try!(word(&mut self.s, "box")); - try!(word(&mut self.s, "(")); - try!(p.as_ref().map_or(Ok(()), |e|self.print_expr(&**e))); - try!(self.word_space(")")); - try!(self.print_expr(&**e)); + ast::ExprBox(ref place, ref expr) => { + try!(self.print_expr_box(place, &**expr)); } ast::ExprVec(ref exprs) => { - try!(self.ibox(indent_unit)); - try!(word(&mut self.s, "[")); - try!(self.commasep_exprs(Inconsistent, &exprs[])); - try!(word(&mut self.s, "]")); - try!(self.end()); + try!(self.print_expr_vec(&exprs[])); } - ast::ExprRepeat(ref element, ref count) => { - try!(self.ibox(indent_unit)); - try!(word(&mut self.s, "[")); - try!(self.print_expr(&**element)); - try!(self.word_space(";")); - try!(self.print_expr(&**count)); - try!(word(&mut self.s, "]")); - try!(self.end()); + try!(self.print_expr_repeat(&**element, &**count)); } - ast::ExprStruct(ref path, ref fields, ref wth) => { - try!(self.print_path(path, true)); - if !(fields.is_empty() && wth.is_none()) { - try!(word(&mut self.s, "{")); - try!(self.commasep_cmnt( - Consistent, - &fields[], - |s, field| { - try!(s.ibox(indent_unit)); - try!(s.print_ident(field.ident.node)); - try!(s.word_space(":")); - try!(s.print_expr(&*field.expr)); - s.end() - }, - |f| f.span)); - match *wth { - Some(ref expr) => { - try!(self.ibox(indent_unit)); - if !fields.is_empty() { - try!(word(&mut self.s, ",")); - try!(space(&mut self.s)); - } - try!(word(&mut self.s, "..")); - try!(self.print_expr(&**expr)); - try!(self.end()); - } - _ => try!(word(&mut self.s, ",")), - } - try!(word(&mut self.s, "}")); - } + try!(self.print_expr_struct(path, &fields[], wth)); } ast::ExprTup(ref exprs) => { - try!(self.popen()); - try!(self.commasep_exprs(Inconsistent, &exprs[])); - if exprs.len() == 1 { - try!(word(&mut self.s, ",")); - } - try!(self.pclose()); + try!(self.print_expr_tup(&exprs[])); } ast::ExprCall(ref func, ref args) => { - try!(self.print_expr_maybe_paren(&**func)); - try!(self.print_call_post(&args[])); + try!(self.print_expr_call(&**func, &args[])); } ast::ExprMethodCall(ident, ref tys, ref args) => { - let base_args = args.slice_from(1); - try!(self.print_expr(&*args[0])); - try!(word(&mut self.s, ".")); - try!(self.print_ident(ident.node)); - if tys.len() > 0u { - try!(word(&mut self.s, "::<")); - try!(self.commasep(Inconsistent, &tys[], - |s, ty| s.print_type(&**ty))); - try!(word(&mut self.s, ">")); - } - try!(self.print_call_post(base_args)); + try!(self.print_expr_method_call(ident, &tys[], &args[])); } ast::ExprBinary(op, ref lhs, ref rhs) => { - try!(self.print_expr(&**lhs)); - try!(space(&mut self.s)); - try!(self.word_space(ast_util::binop_to_string(op))); - try!(self.print_expr(&**rhs)); + try!(self.print_expr_binary(op, &**lhs, &**rhs)); } ast::ExprUnary(op, ref expr) => { - try!(word(&mut self.s, ast_util::unop_to_string(op))); - try!(self.print_expr_maybe_paren(&**expr)); + try!(self.print_expr_unary(op, &**expr)); } ast::ExprAddrOf(m, ref expr) => { - try!(word(&mut self.s, "&")); - try!(self.print_mutability(m)); - try!(self.print_expr_maybe_paren(&**expr)); + try!(self.print_expr_addr_of(m, &**expr)); + } + ast::ExprLit(ref lit) => { + try!(self.print_literal(&**lit)); } - ast::ExprLit(ref lit) => try!(self.print_literal(&**lit)), ast::ExprCast(ref expr, ref ty) => { try!(self.print_expr(&**expr)); try!(space(&mut self.s)); @@ -2891,7 +2958,7 @@ pub fn print_comment(&mut self, comments::BlankLine => { // We need to do at least one, possibly two hardbreaks. let is_semi = match self.s.last_token() { - pp::String(s, _) => ";" == s, + pp::Token::String(s, _) => ";" == s, _ => false }; if is_semi || self.is_begin() || self.is_end() {