@@ -111,32 +111,27 @@ where
111111
112112 fn do_execute_method ( & self , mut context : MethodContext ) -> Result < Arc < Object > , AmlError > {
113113 /*
114- * TODO
114+ * This is the main loop that executes operations. Every op is handled at the top-level of
115+ * the loop to prevent pathological stack growth from nested operations.
115116 *
116- * This is the main loop that executes ops. Every op is handled at the top-level loop to
117- * prevent pathological stack depths.
117+ * The loop has three main stages:
118+ * 1) Check if any in-flight operations are ready to be executed (i.e. have collected all
119+ * their arguments). An operation completing may contribute the last required argument
120+ * of the one above, so this is repeated for as many operations as are ready to be
121+ * retired.
122+ * 2) Look at the next opcode in the stream. If we've run out of opcodes in the current
123+ * block, run logic to determine where in the stream we should move to next. Special
124+ * logic at this level handles things like moving in/out of package definitions, and
125+ * performing control flow.
126+ * 3) When the next opcode is determined, use it to interpret the next portion of the
127+ * stream. If that is data, the correct number of bytes can be consumed and
128+ * contributed to the current in-flight operation. If it's an opcode, a new in-flight
129+ * operation is started, and we go round the loop again.
118130 *
119- * Worked example: AddOp TermArg TermArg Target
120- * - We go round the loop 4 times to interpret this.
121- * - We encounter the AddOp. We add a new in-flight operation with 3 expected arguments.
122- * - We go round again and find some sort of TermArg. This may create new in-flight ops
123- * which we then go round again to complete. Once we're finished, we add this to the
124- * AddOp's record. We then need to detect that all 3 arguments are ready and retire the
125- * AddOp *before* moving on.
126- *
127- * My thoughts are that we can go round and round a loop with two big stages. First, we
128- * check if in-flight ops are ready to be executed (e.g. have collected all their
129- * arguments) and execute them. This can in turn complete the next op up, so this should
130- * complete as many in-flight ops as possible at a time.
131- *
132- * Once all possible in-flight ops have been executed, we then need to move forward in the
133- * stream. Depending on the next op, this could create a new in-flight op that is then
134- * pre-empted, or could parse an argument to an existing in-flight op, which may then be
135- * able to be completed. This stage should not do any executing in its own right, really.
136- * It's just about consuming the next however-many bytes of the stream and setting things
137- * up.
131+ * This scheme is what allows the interpreter to use a loop that somewhat resembles a
132+ * traditional fast bytecode VM, but also provides enough flexibility to handle the
133+ * quirkier parts of the AML grammar, particularly the left-to-right encoding of operands.
138134 */
139-
140135 loop {
141136 /*
142137 * First, see if we've gathered enough arguments to complete some in-flight operations.
@@ -207,7 +202,7 @@ where
207202 Arc :: new ( Object :: Buffer ( buffer) )
208203 } ;
209204 // TODO: use potentially-updated result for return value here
210- self . do_store ( & mut context , target, result. clone ( ) ) ?;
205+ self . do_store ( target, result. clone ( ) ) ?;
211206 context. contribute_arg ( Argument :: Object ( result) ) ;
212207 }
213208 Opcode :: FromBCD => self . do_from_bcd ( & mut context, op) ?,
@@ -393,7 +388,7 @@ where
393388 }
394389 Opcode :: Store => {
395390 let [ Argument :: Object ( object) , target] = & op. arguments [ ..] else { panic ! ( ) } ;
396- self . do_store ( & mut context , & target, object. clone ( ) ) ?;
391+ self . do_store ( & target, object. clone ( ) ) ?;
397392 }
398393 Opcode :: RefOf => {
399394 let [ Argument :: Object ( object) ] = & op. arguments [ ..] else { panic ! ( ) } ;
@@ -408,7 +403,7 @@ where
408403 } else {
409404 let reference =
410405 Arc :: new ( Object :: Reference { kind : ReferenceKind :: RefOf , inner : object. clone ( ) } ) ;
411- self . do_store ( & mut context , target, reference) ?;
406+ self . do_store ( target, reference) ?;
412407 Object :: Integer ( u64:: MAX )
413408 } ;
414409 context. contribute_arg ( Argument :: Object ( Arc :: new ( result) ) ) ;
@@ -1193,7 +1188,7 @@ where
11931188 Opcode :: Multiply => left. wrapping_mul ( right) ,
11941189 Opcode :: Divide => {
11951190 if let Some ( remainder) = target2 {
1196- self . do_store ( context , remainder, Arc :: new ( Object :: Integer ( left. wrapping_rem ( right) ) ) ) ?;
1191+ self . do_store ( remainder, Arc :: new ( Object :: Integer ( left. wrapping_rem ( right) ) ) ) ?;
11971192 }
11981193 left. wrapping_div_euclid ( right)
11991194 }
@@ -1210,7 +1205,7 @@ where
12101205
12111206 let result = Arc :: new ( Object :: Integer ( result) ) ;
12121207 // TODO: use result for arg
1213- self . do_store ( context , target, result. clone ( ) ) ?;
1208+ self . do_store ( target, result. clone ( ) ) ?;
12141209 context. contribute_arg ( Argument :: Object ( result) ) ;
12151210 Ok ( ( ) )
12161211 }
@@ -1360,7 +1355,7 @@ where
13601355 _ => Err ( AmlError :: InvalidOperationOnObject { op : Operation :: Mid , typ : source. typ ( ) } ) ?,
13611356 } ) ;
13621357
1363- self . do_store ( context , target, result. clone ( ) ) ?;
1358+ self . do_store ( target, result. clone ( ) ) ?;
13641359 context. contribute_arg ( Argument :: Object ( result) ) ;
13651360
13661361 Ok ( ( ) )
@@ -1417,7 +1412,7 @@ where
14171412 }
14181413 } ;
14191414 // TODO: use result of store
1420- self . do_store ( context , target, result. clone ( ) ) ?;
1415+ self . do_store ( target, result. clone ( ) ) ?;
14211416 context. contribute_arg ( Argument :: Object ( result) ) ;
14221417 Ok ( ( ) )
14231418 }
@@ -1511,21 +1506,22 @@ where
15111506 _ => Err ( AmlError :: IndexOutOfBounds ) ?,
15121507 } ) ;
15131508
1514- self . do_store ( context , target, result. clone ( ) ) ?;
1509+ self . do_store ( target, result. clone ( ) ) ?;
15151510 context. contribute_arg ( Argument :: Object ( result) ) ;
15161511 Ok ( ( ) )
15171512 }
1518- fn do_store (
1519- & self ,
1520- context : & mut MethodContext ,
1521- target : & Argument ,
1522- object : Arc < Object > ,
1523- ) -> Result < ( ) , AmlError > {
1513+
1514+ // TODO: this might actually do weird stuff to your data if written to a field with BufferAcc
1515+ // access. I guess we need to return something here really and use it instead of the result
1516+ // when returning?? We need to look carefully at all use-sites to make sure it actually returns
1517+ // the result of the store, not the object it passed to us.
1518+ fn do_store ( & self , target : & Argument , object : Arc < Object > ) -> Result < ( ) , AmlError > {
15241519 // TODO: find the destination (need to handle references, debug objects, etc.)
15251520 // TODO: convert object to be of the type of destination, in line with 19.3.5 of the spec
15261521 // TODO: write the object to the destination, including e.g. field writes that then lead to
15271522 // literally god knows what.
15281523 let object = object. unwrap_transparent_reference ( ) ;
1524+
15291525 match target {
15301526 Argument :: Object ( target) => match target. gain_mut ( ) {
15311527 Object :: Integer ( target) => match object. gain_mut ( ) {
@@ -2581,6 +2577,12 @@ mod tests {
25812577 fn release ( & self , _mutex : Handle ) { }
25822578 }
25832579
2580+ #[ test]
2581+ fn verify_interpreter_send_sync ( ) {
2582+ fn test_send_sync < T : Send + Sync > ( ) { }
2583+ test_send_sync :: < Interpreter < TestHandler > > ( ) ;
2584+ }
2585+
25842586 #[ test]
25852587 fn add_op ( ) {
25862588 let interpreter = Interpreter :: new ( TestHandler , 2 ) ;
0 commit comments