Add maximum threshold for number of blocks per function #951
To fix this case that may take forever to compile:
function %a(){
ebb477777777:
}
We decide to define a maximum threshold for the number of blocks in functions.
Based on a large WASM program (https://github.com/mozilla/perf-automation/blob/master/benchmarks/wasm-misc/AngryBots.wasm),
its IR functions does not exceed 1414 blocks. A number 100 times greater (100,000 blocks) seems (currently) enough to define our maximum threshold.
To make this quick benchmark the cranelift-wasm/src/func_translator.rs file has been modified like this:
static mut MAX: usize = 0;
pub fn translate_from_reader<FE: FuncEnvironment + ?Sized>(...) {
[...]
builder.finalize();
// the compiler is single threaded
unsafe {
if func.dfg.num_ebbs() > MAX {
MAX = func.dfg.num_ebbs();
println!("MAX {}", MAX);
}
}
Ok(())
}
This commit is contained in:
@@ -27,6 +27,9 @@ use std::str::FromStr;
|
|||||||
use std::{u16, u32};
|
use std::{u16, u32};
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
|
/// After some quick benchmarks a program should never have more than 100,000 blocks.
|
||||||
|
const MAX_BLOCKS_IN_A_FUNCTION: u32 = 100_000;
|
||||||
|
|
||||||
/// Parse the entire `text` into a list of functions.
|
/// Parse the entire `text` into a list of functions.
|
||||||
///
|
///
|
||||||
/// Any test commands or target declarations are ignored.
|
/// Any test commands or target declarations are ignored.
|
||||||
@@ -1768,6 +1771,10 @@ impl<'a> Parser<'a> {
|
|||||||
let block_num = self.match_block("expected block header")?;
|
let block_num = self.match_block("expected block header")?;
|
||||||
let block = ctx.add_block(block_num, self.loc)?;
|
let block = ctx.add_block(block_num, self.loc)?;
|
||||||
|
|
||||||
|
if block_num.as_u32() >= MAX_BLOCKS_IN_A_FUNCTION {
|
||||||
|
return Err(self.error("too many blocks"));
|
||||||
|
}
|
||||||
|
|
||||||
if !self.optional(Token::Colon) {
|
if !self.optional(Token::Colon) {
|
||||||
// block-header ::= Block(block) [ * block-params ] ":"
|
// block-header ::= Block(block) [ * block-params ] ":"
|
||||||
self.parse_block_params(ctx, block)?;
|
self.parse_block_params(ctx, block)?;
|
||||||
@@ -2979,6 +2986,24 @@ mod tests {
|
|||||||
assert!(!is_warning);
|
assert!(!is_warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn number_of_blocks() {
|
||||||
|
let ParseError {
|
||||||
|
location,
|
||||||
|
message,
|
||||||
|
is_warning,
|
||||||
|
} = Parser::new(
|
||||||
|
"function %a() {
|
||||||
|
block100000:",
|
||||||
|
)
|
||||||
|
.parse_function(None)
|
||||||
|
.unwrap_err();
|
||||||
|
|
||||||
|
assert_eq!(location.line_number, 2);
|
||||||
|
assert_eq!(message, "too many blocks");
|
||||||
|
assert!(!is_warning);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn duplicate_jt() {
|
fn duplicate_jt() {
|
||||||
let ParseError {
|
let ParseError {
|
||||||
|
|||||||
Reference in New Issue
Block a user