1+ use std:: collections:: { HashMap , HashSet } ;
2+
13use crate :: bytecode:: {
2- BYTECODE_WORD_SIZE , CallOwnership , CodeAddr , Effect , Nav , NodeKindConstraint , PredicateOp ,
3- SuccessorAddr , SwitchEntry ,
4+ BYTECODE_WORD_SIZE , CallOwnership , CodeAddr , Effect , Nav , PredicateOp , SuccessorAddr ,
5+ SwitchEntry ,
46} ;
5- use crate :: core:: NodeFieldId ;
7+ use crate :: core:: { NodeFieldId , NodeKindId } ;
68use plotnik_runtime:: PortId ;
79
810use super :: super :: instructions:: header_byte;
9- use super :: { Instruction , Module } ;
11+ use super :: { Instruction , Module , ModuleError } ;
1012
1113#[ derive( Clone , Copy , Debug ) ]
1214pub ( crate ) enum DecodedInstr {
@@ -26,16 +28,22 @@ pub(crate) struct DecodedSwitch {
2628#[ derive( Clone , Copy , Debug ) ]
2729pub ( crate ) struct DecodedMatch {
2830 pub ( crate ) nav : Nav ,
29- pub ( crate ) node_kind : NodeKindConstraint ,
31+ pub ( crate ) kind : Option < NodeKindId > ,
32+ pub ( crate ) candidate : DecodedCandidate ,
33+ effects_base : u32 ,
34+ succ_base : u32 ,
35+ effects_len : u8 ,
36+ succ_len : u8 ,
37+ }
38+
39+ #[ derive( Clone , Copy , Debug ) ]
40+ pub ( crate ) struct DecodedCandidate {
41+ pub ( crate ) named : Option < bool > ,
3042 pub ( crate ) node_field : Option < NodeFieldId > ,
3143 pub ( crate ) missing : bool ,
3244 pub ( crate ) predicate : Option < DecodedPredicate > ,
33- effects_base : u32 ,
3445 neg_base : u32 ,
35- succ_base : u32 ,
36- effects_len : u8 ,
3746 neg_len : u8 ,
38- succ_len : u8 ,
3947}
4048
4149impl DecodedMatch {
@@ -67,18 +75,50 @@ impl DecodedCall {
6775 }
6876}
6977
78+ #[ derive( Clone , Copy , Debug ) ]
79+ pub ( crate ) struct DecodedSwitchEntry {
80+ pub ( crate ) kind : NodeKindId ,
81+ action : u16 ,
82+ }
83+
84+ #[ derive( Debug ) ]
85+ pub ( crate ) struct DecodedAction {
86+ pub ( crate ) entry : CodeAddr ,
87+ pub ( crate ) matched_at : CodeAddr ,
88+ pub ( crate ) matched : DecodedMatch ,
89+ pub ( crate ) prefix : Vec < DecodedPrefix > ,
90+ }
91+
92+ #[ derive( Debug ) ]
93+ pub ( crate ) struct DecodedPrefix {
94+ pub ( crate ) ip : CodeAddr ,
95+ effects_base : u32 ,
96+ effects_len : u8 ,
97+ }
98+
7099#[ derive( Debug , Default ) ]
71100pub ( crate ) struct DecodedProgram {
72101 words : Vec < DecodedInstr > ,
73102 effects : Vec < Effect > ,
74103 neg_fields : Vec < NodeFieldId > ,
75104 successors : Vec < SuccessorAddr > ,
76- switch_entries : Vec < SwitchEntry > ,
105+ switch_entries : Vec < DecodedSwitchEntry > ,
106+ actions : Vec < DecodedAction > ,
77107}
78108
79109impl DecodedProgram {
80- pub ( crate ) fn switch_entries ( & self , switch : & DecodedSwitch ) -> & [ SwitchEntry ] {
81- & self . switch_entries [ switch. base as usize ..] [ ..switch. len as usize ]
110+ #[ inline]
111+ pub ( crate ) fn switch_entries ( & self , switch : & DecodedSwitch ) -> & [ DecodedSwitchEntry ] {
112+ & self . switch_entries [ switch. base as usize ..] [ ..usize:: from ( switch. len ) ]
113+ }
114+
115+ #[ inline]
116+ pub ( crate ) fn switch_action ( & self , entry : & DecodedSwitchEntry ) -> & DecodedAction {
117+ & self . actions [ usize:: from ( entry. action ) ]
118+ }
119+
120+ pub ( crate ) fn prefix_effects ( & self , prefix : & DecodedPrefix ) -> & [ Effect ] {
121+ & self . effects [ prefix. effects_base as usize ..] [ ..prefix. effects_len as usize ]
82122 }
83123
84124 #[ inline]
@@ -98,8 +138,8 @@ impl DecodedProgram {
98138 }
99139
100140 #[ inline]
101- pub ( crate ) fn neg_fields ( & self , m : & DecodedMatch ) -> & [ NodeFieldId ] {
102- & self . neg_fields [ m . neg_base as usize ..] [ ..m . neg_len as usize ]
141+ pub ( crate ) fn neg_fields ( & self , candidate : & DecodedCandidate ) -> & [ NodeFieldId ] {
142+ & self . neg_fields [ candidate . neg_base as usize ..] [ ..candidate . neg_len as usize ]
103143 }
104144
105145 #[ inline]
@@ -118,13 +158,10 @@ impl DecodedProgram {
118158 }
119159}
120160
121- pub ( crate ) fn build ( module : & Module ) -> DecodedProgram {
161+ pub ( crate ) fn build ( module : & Module ) -> Result < DecodedProgram , ModuleError > {
122162 let instructions = module. instructions_slice ( ) ;
123163 let word_count = instructions. len ( ) / BYTECODE_WORD_SIZE ;
124- let mut program = DecodedProgram {
125- switch_entries : module. switch_tables ( ) . iter ( ) . collect ( ) ,
126- ..Default :: default ( )
127- } ;
164+ let mut program = DecodedProgram :: default ( ) ;
128165 program. words . reserve ( word_count) ;
129166
130167 let mut word_addr = 0usize ;
@@ -154,15 +191,18 @@ pub(crate) fn build(module: &Module) -> DecodedProgram {
154191
155192 program. words . push ( DecodedInstr :: Match ( DecodedMatch {
156193 nav : m. nav ,
157- node_kind : m. node_kind ,
158- node_field : m. node_field ,
159- missing : m. missing ( ) ,
160- predicate,
194+ kind : m. node_kind . kind_id ( ) ,
195+ candidate : DecodedCandidate {
196+ named : ( !m. node_kind . is_any ( ) ) . then_some ( m. node_kind . is_named ( ) ) ,
197+ node_field : m. node_field ,
198+ missing : m. missing ( ) ,
199+ predicate,
200+ neg_base,
201+ neg_len : ( program. neg_fields . len ( ) - neg_base as usize ) as u8 ,
202+ } ,
161203 effects_base,
162- neg_base,
163204 succ_base,
164205 effects_len : ( program. effects . len ( ) - effects_base as usize ) as u8 ,
165- neg_len : ( program. neg_fields . len ( ) - neg_base as usize ) as u8 ,
166206 succ_len : ( program. successors . len ( ) - succ_base as usize ) as u8 ,
167207 } ) ) ;
168208 for _ in 1 ..opcode. word_count ( ) {
@@ -192,7 +232,68 @@ pub(crate) fn build(module: &Module) -> DecodedProgram {
192232 }
193233 }
194234 }
195- program
235+ let mut actions = HashMap :: new ( ) ;
236+ for entry in module. switch_tables ( ) . iter ( ) {
237+ let target = CodeAddr :: from ( u16:: from ( entry. target ) ) ;
238+ let action = if let Some ( & index) = actions. get ( & ( target, entry. kind ) ) {
239+ index
240+ } else {
241+ let action = program. selected_entry ( target, entry. kind ) ?;
242+ let index = u16:: try_from ( program. actions . len ( ) )
243+ . expect ( "selected entries are bounded by instruction count" ) ;
244+ program. actions . push ( action) ;
245+ actions. insert ( ( target, entry. kind ) , index) ;
246+ index
247+ } ;
248+ program. switch_entries . push ( DecodedSwitchEntry {
249+ kind : entry. kind ,
250+ action,
251+ } ) ;
252+ }
253+ Ok ( program)
254+ }
255+
256+ impl DecodedProgram {
257+ fn selected_entry (
258+ & self ,
259+ entry : CodeAddr ,
260+ kind : NodeKindId ,
261+ ) -> Result < DecodedAction , ModuleError > {
262+ let mut ip = entry;
263+ let mut visited = HashSet :: new ( ) ;
264+ let mut prefix = Vec :: new ( ) ;
265+ loop {
266+ if !visited. insert ( ip) {
267+ return Err ( ModuleError :: MalformedSwitchTable ) ;
268+ }
269+
270+ let DecodedInstr :: Match ( matched) = self . instruction_at ( ip) else {
271+ return Err ( ModuleError :: MalformedSwitchTable ) ;
272+ } ;
273+ if !matched. is_epsilon ( ) {
274+ if matched. nav != Nav :: StayExact || matched. kind != Some ( kind) {
275+ return Err ( ModuleError :: MalformedSwitchTable ) ;
276+ }
277+
278+ return Ok ( DecodedAction {
279+ entry,
280+ matched_at : ip,
281+ matched,
282+ prefix,
283+ } ) ;
284+ }
285+
286+ let [ next] = self . successors ( & matched) else {
287+ return Err ( ModuleError :: MalformedSwitchTable ) ;
288+ } ;
289+ prefix. push ( DecodedPrefix {
290+ ip,
291+ effects_base : matched. effects_base ,
292+ effects_len : matched. effects_len ,
293+ } ) ;
294+ ip = CodeAddr :: from ( u16:: from ( * next) ) ;
295+ }
296+ }
196297}
197298
198299fn pool_base ( len : usize ) -> u32 {
0 commit comments