From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- third_party/rust/wast/src/core/expr.rs | 53 +++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'third_party/rust/wast/src/core/expr.rs') diff --git a/third_party/rust/wast/src/core/expr.rs b/third_party/rust/wast/src/core/expr.rs index 489ac205af..b45950b896 100644 --- a/third_party/rust/wast/src/core/expr.rs +++ b/third_party/rust/wast/src/core/expr.rs @@ -1,3 +1,4 @@ +use crate::annotation; use crate::core::*; use crate::encode::Encode; use crate::kw; @@ -14,6 +15,20 @@ use std::mem; #[allow(missing_docs)] pub struct Expression<'a> { pub instrs: Box<[Instruction<'a>]>, + pub branch_hints: Vec, +} + +/// A `@metadata.code.branch_hint` in the code, associated with a If or BrIf +/// This instruction is a placeholder and won't produce anything. Its purpose +/// is to store the offset of the following instruction and check that +/// it's followed by `br_if` or `if`. +#[derive(Debug)] +pub struct BranchHint { + /// Index of instructions in `instrs` field of `Expression` that this hint + /// appplies to. + pub instr_index: usize, + /// The value of this branch hint + pub value: u32, } impl<'a> Parse<'a> for Expression<'a> { @@ -22,6 +37,7 @@ impl<'a> Parse<'a> for Expression<'a> { exprs.parse(parser)?; Ok(Expression { instrs: exprs.instrs.into(), + branch_hints: exprs.branch_hints, }) } } @@ -47,6 +63,7 @@ impl<'a> Expression<'a> { exprs.parse_folded_instruction(parser)?; Ok(Expression { instrs: exprs.instrs.into(), + branch_hints: exprs.branch_hints, }) } } @@ -66,6 +83,11 @@ struct ExpressionParser<'a> { /// Descriptor of all our nested s-expr blocks. This only happens when /// instructions themselves are nested. stack: Vec>, + + /// Related to the branch hints proposal. + /// Will be used later to collect the offsets in the final binary. + /// <(index of branch instructions, BranchHintAnnotation)> + branch_hints: Vec, } enum Paren { @@ -89,6 +111,9 @@ enum Level<'a> { /// which don't correspond to terminating instructions, we're just in a /// nested block. IfArm, + + /// This means we are finishing the parsing of a branch hint annotation. + BranchHint, } /// Possible states of "what is currently being parsed?" in an `if` expression. @@ -145,6 +170,14 @@ impl<'a> ExpressionParser<'a> { if self.handle_if_lparen(parser)? { continue; } + + // Handle the case of a branch hint annotation + if parser.peek::()? { + self.parse_branch_hint(parser)?; + self.stack.push(Level::BranchHint); + continue; + } + match parser.parse()? { // If block/loop show up then we just need to be sure to // push an `end` instruction whenever the `)` token is @@ -177,6 +210,7 @@ impl<'a> ExpressionParser<'a> { Paren::Right => match self.stack.pop().unwrap() { Level::EndWith(i) => self.instrs.push(i), Level::IfArm => {} + Level::BranchHint => {} // If an `if` statement hasn't parsed the clause or `then` // block, then that's an error because there weren't enough @@ -191,7 +225,6 @@ impl<'a> ExpressionParser<'a> { }, } } - Ok(()) } @@ -287,6 +320,24 @@ impl<'a> ExpressionParser<'a> { If::Else => Err(parser.error("unexpected token: too many payloads inside of `(if)`")), } } + + fn parse_branch_hint(&mut self, parser: Parser<'a>) -> Result<()> { + parser.parse::()?; + + let hint = parser.parse::()?; + + let value = match hint.as_bytes() { + [0] => 0, + [1] => 1, + _ => return Err(parser.error("invalid value for branch hint")), + }; + + self.branch_hints.push(BranchHint { + instr_index: self.instrs.len(), + value, + }); + Ok(()) + } } // TODO: document this obscenity -- cgit v1.2.3