@@ -38,12 +38,29 @@ impl Interpreter {
38
38
39
39
pub fn load_table ( & self , stream : & [ u8 ] ) -> Result < ( ) , AmlError > {
40
40
// TODO: probs needs to do more stuff
41
- self . execute_method ( stream)
41
+ let context = unsafe { MethodContext :: new_from_table ( stream) } ;
42
+ self . do_execute_method ( context) ?;
43
+ Ok ( ( ) )
42
44
}
43
45
44
- pub fn execute_method ( & self , stream : & [ u8 ] ) -> Result < ( ) , AmlError > {
45
- let mut context = unsafe { MethodContext :: new_from_table ( stream) } ;
46
+ /// Invoke a method by its name, with the given set of arguments. If the referenced object is
47
+ /// not a method, the object will instead be returned - this is useful for objects that can
48
+ /// either be defined directly, or through a method (e.g. a `_CRS` object).
49
+ pub fn invoke_method ( & self , path : AmlName , args : Vec < Arc < Object > > ) -> Result < Arc < Object > , AmlError > {
50
+ info ! ( "Invoking AML method: {}" , path) ;
51
+
52
+ let object = self . namespace . lock ( ) . get ( path. clone ( ) ) ?. clone ( ) ;
53
+ match object. typ ( ) {
54
+ ObjectType :: Method => {
55
+ self . namespace . lock ( ) . add_level ( path. clone ( ) , NamespaceLevelKind :: MethodLocals ) ?;
56
+ let context = MethodContext :: new_from_method ( object, args, path) ?;
57
+ self . do_execute_method ( context)
58
+ }
59
+ _ => Ok ( object) ,
60
+ }
61
+ }
46
62
63
+ fn do_execute_method ( & self , mut context : MethodContext ) -> Result < Arc < Object > , AmlError > {
47
64
/*
48
65
* TODO
49
66
*
@@ -277,9 +294,12 @@ impl Interpreter {
277
294
self . handler . stall ( usec) ;
278
295
}
279
296
Opcode :: InternalMethodCall => {
280
- let Argument :: Object ( method) = & op. arguments [ 0 ] else { panic ! ( ) } ;
297
+ let [ Argument :: Object ( method) , Argument :: Namestring ( method_scope) ] = & op. arguments [ 0 ..2 ]
298
+ else {
299
+ panic ! ( )
300
+ } ;
281
301
282
- let args = op. arguments [ 1 ..]
302
+ let args = op. arguments [ 2 ..]
283
303
. iter ( )
284
304
. map ( |arg| {
285
305
if let Argument :: Object ( arg) = arg {
@@ -290,18 +310,30 @@ impl Interpreter {
290
310
} )
291
311
. collect ( ) ;
292
312
293
- let new_context = MethodContext :: new_from_method ( method. clone ( ) , args) ?;
313
+ self . namespace . lock ( ) . add_level ( method_scope. clone ( ) , NamespaceLevelKind :: MethodLocals ) ?;
314
+
315
+ let new_context =
316
+ MethodContext :: new_from_method ( method. clone ( ) , args, method_scope. clone ( ) ) ?;
294
317
let old_context = mem:: replace ( & mut context, new_context) ;
295
318
self . context_stack . lock ( ) . push ( old_context) ;
296
319
}
297
320
Opcode :: Return => {
298
321
let [ Argument :: Object ( object) ] = & op. arguments [ ..] else { panic ! ( ) } ;
299
- context = self . context_stack . lock ( ) . pop ( ) . unwrap ( ) ;
300
322
301
- if let Some ( prev_op) = context. in_flight . last_mut ( ) {
302
- if prev_op. arguments . len ( ) < prev_op. expected_arguments {
303
- prev_op. arguments . push ( Argument :: Object ( object. clone ( ) ) ) ;
323
+ if let Some ( last) = self . context_stack . lock ( ) . pop ( ) {
324
+ context = last;
325
+
326
+ if let Some ( prev_op) = context. in_flight . last_mut ( ) {
327
+ if prev_op. arguments . len ( ) < prev_op. expected_arguments {
328
+ prev_op. arguments . push ( Argument :: Object ( object. clone ( ) ) ) ;
329
+ }
304
330
}
331
+ } else {
332
+ /*
333
+ * If this is the top-most context, this is a `Return` from the actual
334
+ * method.
335
+ */
336
+ return Ok ( object. clone ( ) ) ;
305
337
}
306
338
}
307
339
Opcode :: ObjectType => {
@@ -353,13 +385,21 @@ impl Interpreter {
353
385
*/
354
386
match context. current_block . kind {
355
387
BlockKind :: Table => {
356
- break Ok ( ( ) ) ;
388
+ break Ok ( Arc :: new ( Object :: Uninitialized ) ) ;
357
389
}
358
- BlockKind :: Method => {
359
- // TODO: not sure how to handle no explicit return. Result is undefined
360
- // but we might still need to handle sticking it in an in-flight op?
361
- context = self . context_stack . lock ( ) . pop ( ) . unwrap ( ) ;
362
- continue ;
390
+ BlockKind :: Method { method_scope } => {
391
+ self . namespace . lock ( ) . remove_level ( method_scope) ?;
392
+
393
+ if let Some ( prev_context) = self . context_stack . lock ( ) . pop ( ) {
394
+ context = prev_context;
395
+ continue ;
396
+ } else {
397
+ /*
398
+ * If there is no explicit `Return` op, the result is undefined. We
399
+ * just return an uninitialized object.
400
+ */
401
+ return Ok ( Arc :: new ( Object :: Uninitialized ) ) ;
402
+ }
363
403
}
364
404
BlockKind :: Scope { old_scope } => {
365
405
assert ! ( context. block_stack. len( ) > 0 ) ;
@@ -691,11 +731,11 @@ impl Interpreter {
691
731
if let Object :: Method { flags, .. } = * object {
692
732
context. start_in_flight_op ( OpInFlight :: new_with (
693
733
Opcode :: InternalMethodCall ,
694
- vec ! [ Argument :: Object ( object) ] ,
695
734
flags. arg_count ( ) ,
696
735
) )
697
736
} else {
698
737
context. last_op ( ) ?. arguments . push ( Argument :: Object ( object) ) ;
738
+ vec ! [ Argument :: Object ( object) , Argument :: Namestring ( resolved_name) ] ,
699
739
}
700
740
}
701
741
@@ -915,10 +955,9 @@ impl Interpreter {
915
955
/// ### Safety
916
956
/// `MethodContext` does not keep the lifetime of the underlying AML stream, which for tables is
917
957
/// borrowed from the underlying physical mapping. This is because the interpreter needs to
918
- /// pre-empt method contexts that execute other methods, storing pre-empted contexts.
919
- ///
920
- /// This is made safe in the case of methods by the context holding a reference to the method
921
- /// object, but must be handled manually for AML tables.
958
+ /// preempt method contexts that execute other methods, and these contexts may have disparate
959
+ /// lifetimes. This is made safe in the case of methods by the context holding a reference to the
960
+ /// method object, but must be handled manually for AML tables.
922
961
struct MethodContext {
923
962
current_block : Block ,
924
963
block_stack : Vec < Block > ,
@@ -963,7 +1002,9 @@ impl Block {
963
1002
#[ derive( PartialEq , Debug ) ]
964
1003
pub enum BlockKind {
965
1004
Table ,
966
- Method ,
1005
+ Method {
1006
+ method_scope : AmlName ,
1007
+ } ,
967
1008
Scope {
968
1009
old_scope : AmlName ,
969
1010
} ,
@@ -997,12 +1038,20 @@ impl MethodContext {
997
1038
}
998
1039
}
999
1040
1000
- fn new_from_method ( method : Arc < Object > , args : Vec < Arc < Object > > ) -> Result < MethodContext , AmlError > {
1041
+ fn new_from_method (
1042
+ method : Arc < Object > ,
1043
+ args : Vec < Arc < Object > > ,
1044
+ scope : AmlName ,
1045
+ ) -> Result < MethodContext , AmlError > {
1001
1046
if let Object :: Method { code, flags } = & * method {
1002
1047
if args. len ( ) != flags. arg_count ( ) {
1003
1048
return Err ( AmlError :: MethodArgCountIncorrect ) ;
1004
1049
}
1005
- let block = Block { stream : code as & [ u8 ] as * const [ u8 ] , pc : 0 , kind : BlockKind :: Method } ;
1050
+ let block = Block {
1051
+ stream : code as & [ u8 ] as * const [ u8 ] ,
1052
+ pc : 0 ,
1053
+ kind : BlockKind :: Method { method_scope : scope. clone ( ) } ,
1054
+ } ;
1006
1055
let args = core:: array:: from_fn ( |i| {
1007
1056
if let Some ( arg) = args. get ( i) { arg. clone ( ) } else { Arc :: new ( Object :: Uninitialized ) }
1008
1057
} ) ;
@@ -1012,7 +1061,7 @@ impl MethodContext {
1012
1061
in_flight : Vec :: new ( ) ,
1013
1062
args,
1014
1063
locals : core:: array:: from_fn ( |_| Arc :: new ( Object :: Uninitialized ) ) ,
1015
- current_scope : AmlName :: root ( ) ,
1064
+ current_scope : scope ,
1016
1065
_method : Some ( method. clone ( ) ) ,
1017
1066
} ;
1018
1067
Ok ( context)
@@ -1530,9 +1579,9 @@ mod tests {
1530
1579
fn add_op ( ) {
1531
1580
let interpreter = Interpreter :: new ( TestHandler ) ;
1532
1581
// AddOp 0x0e 0x06 => Local2
1533
- interpreter. execute_method ( & [ 0x72 , 0x0b , 0x0e , 0x00 , 0x0a , 0x06 , 0x62 ] ) . unwrap ( ) ;
1582
+ interpreter. load_table ( & [ 0x72 , 0x0b , 0x0e , 0x00 , 0x0a , 0x06 , 0x62 ] ) . unwrap ( ) ;
1534
1583
// AddOp 0x0e (AddOp 0x01 0x03 => Local1) => Local1
1535
- interpreter. execute_method ( & [ 0x72 , 0x0a , 0x0e , 0x72 , 0x0a , 0x01 , 0x0a , 0x03 , 0x61 , 0x61 ] ) . unwrap ( ) ;
1584
+ interpreter. load_table ( & [ 0x72 , 0x0a , 0x0e , 0x72 , 0x0a , 0x01 , 0x0a , 0x03 , 0x61 , 0x61 ] ) . unwrap ( ) ;
1536
1585
}
1537
1586
1538
1587
#[ test]
@@ -1541,9 +1590,5 @@ mod tests {
1541
1590
unsafe { MethodContext :: new_from_table( b"\\ \x2e ABC_DEF_\0 " ) } . namestring( ) ,
1542
1591
Ok ( AmlName :: from_str( "\\ ABC.DEF" ) . unwrap( ) )
1543
1592
) ;
1544
- assert_eq ! (
1545
- unsafe { MethodContext :: new_from_table( b"\x2e ABC_DEF_^_GHI" ) } . namestring( ) ,
1546
- Ok ( AmlName :: from_str( "ABC.DEF.^_GHI" ) . unwrap( ) )
1547
- ) ;
1548
1593
}
1549
1594
}
0 commit comments