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:
nalmt
2020-02-05 18:12:56 +01:00
committed by Benjamin Bouvier
parent 5e05aa1b03
commit 830bdd5127

View File

@@ -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 {