asltree.c revision 1.7 1 /******************************************************************************
2 *
3 * Module Name: asltree - parse tree management
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44 #include "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "acapps.h"
47 #include <time.h>
48
49 #define _COMPONENT ACPI_COMPILER
50 ACPI_MODULE_NAME ("asltree")
51
52 /* Local prototypes */
53
54 static ACPI_PARSE_OBJECT *
55 TrGetNextNode (
56 void);
57
58
59 /*******************************************************************************
60 *
61 * FUNCTION: TrSetParent
62 *
63 * PARAMETERS: Op - To be set to new parent
64 * ParentOp - The parent
65 *
66 * RETURN: None, sets Op parent directly
67 *
68 * DESCRIPTION: Change the parent of a parse op.
69 *
70 ******************************************************************************/
71
72 void
73 TrSetParent (
74 ACPI_PARSE_OBJECT *Op,
75 ACPI_PARSE_OBJECT *ParentOp)
76 {
77
78 Op->Asl.Parent = ParentOp;
79 }
80
81
82 /*******************************************************************************
83 *
84 * FUNCTION: TrGetNextNode
85 *
86 * PARAMETERS: None
87 *
88 * RETURN: New parse node. Aborts on allocation failure
89 *
90 * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local
91 * dynamic memory manager for performance reasons (This has a
92 * major impact on the speed of the compiler.)
93 *
94 ******************************************************************************/
95
96 static ACPI_PARSE_OBJECT *
97 TrGetNextNode (
98 void)
99 {
100 ASL_CACHE_INFO *Cache;
101
102
103 if (Gbl_ParseOpCacheNext >= Gbl_ParseOpCacheLast)
104 {
105 /* Allocate a new buffer */
106
107 Cache = UtLocalCalloc (sizeof (Cache->Next) +
108 (sizeof (ACPI_PARSE_OBJECT) * ASL_PARSEOP_CACHE_SIZE));
109
110 /* Link new cache buffer to head of list */
111
112 Cache->Next = Gbl_ParseOpCacheList;
113 Gbl_ParseOpCacheList = Cache;
114
115 /* Setup cache management pointers */
116
117 Gbl_ParseOpCacheNext = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, Cache->Buffer);
118 Gbl_ParseOpCacheLast = Gbl_ParseOpCacheNext + ASL_PARSEOP_CACHE_SIZE;
119 }
120
121 Gbl_ParseOpCount++;
122 return (Gbl_ParseOpCacheNext++);
123 }
124
125
126 /*******************************************************************************
127 *
128 * FUNCTION: TrAllocateNode
129 *
130 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node
131 *
132 * RETURN: New parse node. Aborts on allocation failure
133 *
134 * DESCRIPTION: Allocate and initialize a new parse node for the parse tree
135 *
136 ******************************************************************************/
137
138 ACPI_PARSE_OBJECT *
139 TrAllocateNode (
140 UINT32 ParseOpcode)
141 {
142 ACPI_PARSE_OBJECT *Op;
143
144
145 Op = TrGetNextNode ();
146
147 Op->Asl.ParseOpcode = (UINT16) ParseOpcode;
148 Op->Asl.Filename = Gbl_Files[ASL_FILE_INPUT].Filename;
149 Op->Asl.LineNumber = Gbl_CurrentLineNumber;
150 Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber;
151 Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset;
152 Op->Asl.Column = Gbl_CurrentColumn;
153
154 UtSetParseOpName (Op);
155 return (Op);
156 }
157
158
159 /*******************************************************************************
160 *
161 * FUNCTION: TrReleaseNode
162 *
163 * PARAMETERS: Op - Op to be released
164 *
165 * RETURN: None
166 *
167 * DESCRIPTION: "release" a node. In truth, nothing is done since the node
168 * is part of a larger buffer
169 *
170 ******************************************************************************/
171
172 void
173 TrReleaseNode (
174 ACPI_PARSE_OBJECT *Op)
175 {
176
177 return;
178 }
179
180
181 /*******************************************************************************
182 *
183 * FUNCTION: TrSetCurrentFilename
184 *
185 * PARAMETERS: Op - An existing parse node
186 *
187 * RETURN: None
188 *
189 * DESCRIPTION: Save the include file filename. Used for debug output only.
190 *
191 ******************************************************************************/
192
193 void
194 TrSetCurrentFilename (
195 ACPI_PARSE_OBJECT *Op)
196 {
197 Op->Asl.Filename = Gbl_PreviousIncludeFilename;
198 }
199
200
201 /*******************************************************************************
202 *
203 * FUNCTION: TrUpdateNode
204 *
205 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node
206 * Op - An existing parse node
207 *
208 * RETURN: The updated node
209 *
210 * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to
211 * change an opcode to DEFAULT_ARG so that the node is ignored
212 * during the code generation. Also used to set generic integers
213 * to a specific size (8, 16, 32, or 64 bits)
214 *
215 ******************************************************************************/
216
217 ACPI_PARSE_OBJECT *
218 TrUpdateNode (
219 UINT32 ParseOpcode,
220 ACPI_PARSE_OBJECT *Op)
221 {
222
223 if (!Op)
224 {
225 return (NULL);
226 }
227
228 DbgPrint (ASL_PARSE_OUTPUT,
229 "\nUpdateNode: Old - %s, New - %s\n",
230 UtGetOpName (Op->Asl.ParseOpcode),
231 UtGetOpName (ParseOpcode));
232
233 /* Assign new opcode and name */
234
235 if (Op->Asl.ParseOpcode == PARSEOP_ONES)
236 {
237 switch (ParseOpcode)
238 {
239 case PARSEOP_BYTECONST:
240
241 Op->Asl.Value.Integer = ACPI_UINT8_MAX;
242 break;
243
244 case PARSEOP_WORDCONST:
245
246 Op->Asl.Value.Integer = ACPI_UINT16_MAX;
247 break;
248
249 case PARSEOP_DWORDCONST:
250
251 Op->Asl.Value.Integer = ACPI_UINT32_MAX;
252 break;
253
254 /* Don't need to do the QWORD case */
255
256 default:
257
258 /* Don't care about others */
259 break;
260 }
261 }
262
263 Op->Asl.ParseOpcode = (UINT16) ParseOpcode;
264 UtSetParseOpName (Op);
265
266 /*
267 * For the BYTE, WORD, and DWORD constants, make sure that the integer
268 * that was passed in will actually fit into the data type
269 */
270 switch (ParseOpcode)
271 {
272 case PARSEOP_BYTECONST:
273
274 UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX);
275 Op->Asl.Value.Integer &= ACPI_UINT8_MAX;
276 break;
277
278 case PARSEOP_WORDCONST:
279
280 UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX);
281 Op->Asl.Value.Integer &= ACPI_UINT16_MAX;
282 break;
283
284 case PARSEOP_DWORDCONST:
285
286 UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX);
287 Op->Asl.Value.Integer &= ACPI_UINT32_MAX;
288 break;
289
290 default:
291
292 /* Don't care about others, don't need to check QWORD */
293
294 break;
295 }
296
297 return (Op);
298 }
299
300
301 /*******************************************************************************
302 *
303 * FUNCTION: TrPrintNodeCompileFlags
304 *
305 * PARAMETERS: Flags - Flags word to be decoded
306 *
307 * RETURN: None
308 *
309 * DESCRIPTION: Decode a flags word to text. Displays all flags that are set.
310 *
311 ******************************************************************************/
312
313 void
314 TrPrintNodeCompileFlags (
315 UINT32 Flags)
316 {
317 UINT32 i;
318 UINT32 FlagBit = 1;
319 char *FlagName = NULL;
320
321
322 for (i = 0; i < 32; i++)
323 {
324 switch (Flags & FlagBit)
325 {
326 case NODE_VISITED:
327
328 FlagName = "NODE_VISITED";
329 break;
330
331 case NODE_AML_PACKAGE:
332
333 FlagName = "NODE_AML_PACKAGE";
334 break;
335
336 case NODE_IS_TARGET:
337
338 FlagName = "NODE_IS_TARGET";
339 break;
340
341 case NODE_IS_RESOURCE_DESC:
342
343 FlagName = "NODE_IS_RESOURCE_DESC";
344 break;
345
346 case NODE_IS_RESOURCE_FIELD:
347
348 FlagName = "NODE_IS_RESOURCE_FIELD";
349 break;
350
351 case NODE_HAS_NO_EXIT:
352
353 FlagName = "NODE_HAS_NO_EXIT";
354 break;
355
356 case NODE_IF_HAS_NO_EXIT:
357
358 FlagName = "NODE_IF_HAS_NO_EXIT";
359 break;
360
361 case NODE_NAME_INTERNALIZED:
362
363 FlagName = "NODE_NAME_INTERNALIZED";
364 break;
365
366 case NODE_METHOD_NO_RETVAL:
367
368 FlagName = "NODE_METHOD_NO_RETVAL";
369 break;
370
371 case NODE_METHOD_SOME_NO_RETVAL:
372
373 FlagName = "NODE_METHOD_SOME_NO_RETVAL";
374 break;
375
376 case NODE_RESULT_NOT_USED:
377
378 FlagName = "NODE_RESULT_NOT_USED";
379 break;
380
381 case NODE_METHOD_TYPED:
382
383 FlagName = "NODE_METHOD_TYPED";
384 break;
385
386 case NODE_COULD_NOT_REDUCE:
387
388 FlagName = "NODE_COULD_NOT_REDUCE";
389 break;
390
391 case NODE_COMPILE_TIME_CONST:
392
393 FlagName = "NODE_COMPILE_TIME_CONST";
394 break;
395
396 case NODE_IS_TERM_ARG:
397
398 FlagName = "NODE_IS_TERM_ARG";
399 break;
400
401 case NODE_WAS_ONES_OP:
402
403 FlagName = "NODE_WAS_ONES_OP";
404 break;
405
406 case NODE_IS_NAME_DECLARATION:
407
408 FlagName = "NODE_IS_NAME_DECLARATION";
409 break;
410
411 case NODE_COMPILER_EMITTED:
412
413 FlagName = "NODE_COMPILER_EMITTED";
414 break;
415
416 case NODE_IS_DUPLICATE:
417
418 FlagName = "NODE_IS_DUPLICATE";
419 break;
420
421 case NODE_IS_RESOURCE_DATA:
422
423 FlagName = "NODE_IS_RESOURCE_DATA";
424 break;
425
426 case NODE_IS_NULL_RETURN:
427
428 FlagName = "NODE_IS_NULL_RETURN";
429 break;
430
431 default:
432 break;
433 }
434
435 if (FlagName)
436 {
437 DbgPrint (ASL_PARSE_OUTPUT, " %s", FlagName);
438 FlagName = NULL;
439 }
440
441 FlagBit <<= 1;
442 }
443 }
444
445
446 /*******************************************************************************
447 *
448 * FUNCTION: TrSetNodeFlags
449 *
450 * PARAMETERS: Op - An existing parse node
451 * Flags - New flags word
452 *
453 * RETURN: The updated parser op
454 *
455 * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set
456 *
457 ******************************************************************************/
458
459 ACPI_PARSE_OBJECT *
460 TrSetNodeFlags (
461 ACPI_PARSE_OBJECT *Op,
462 UINT32 Flags)
463 {
464
465 if (!Op)
466 {
467 return (NULL);
468 }
469
470 DbgPrint (ASL_PARSE_OUTPUT,
471 "\nSetNodeFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags);
472
473 TrPrintNodeCompileFlags (Flags);
474 DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
475
476 Op->Asl.CompileFlags |= Flags;
477 return (Op);
478 }
479
480
481 /*******************************************************************************
482 *
483 * FUNCTION: TrSetNodeAmlLength
484 *
485 * PARAMETERS: Op - An existing parse node
486 * Length - AML Length
487 *
488 * RETURN: The updated parser op
489 *
490 * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate
491 * the presence of a node that must be reduced to a fixed length
492 * constant.
493 *
494 ******************************************************************************/
495
496 ACPI_PARSE_OBJECT *
497 TrSetNodeAmlLength (
498 ACPI_PARSE_OBJECT *Op,
499 UINT32 Length)
500 {
501
502 DbgPrint (ASL_PARSE_OUTPUT,
503 "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length);
504
505 if (!Op)
506 {
507 return (NULL);
508 }
509
510 Op->Asl.AmlLength = Length;
511 return (Op);
512 }
513
514
515 /*******************************************************************************
516 *
517 * FUNCTION: TrSetEndLineNumber
518 *
519 * PARAMETERS: Op - An existing parse node
520 *
521 * RETURN: None.
522 *
523 * DESCRIPTION: Set the ending line numbers (file line and logical line) of a
524 * parse node to the current line numbers.
525 *
526 ******************************************************************************/
527
528 void
529 TrSetEndLineNumber (
530 ACPI_PARSE_OBJECT *Op)
531 {
532
533 /* If the end line # is already set, just return */
534
535 if (Op->Asl.EndLine)
536 {
537 return;
538 }
539
540 Op->Asl.EndLine = Gbl_CurrentLineNumber;
541 Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber;
542 }
543
544
545 /*******************************************************************************
546 *
547 * FUNCTION: TrCreateAssignmentNode
548 *
549 * PARAMETERS: Target - Assignment target
550 * Source - Assignment source
551 *
552 * RETURN: Pointer to the new node. Aborts on allocation failure
553 *
554 * DESCRIPTION: Implements the C-style '=' operator. It changes the parse
555 * tree if possible to utilize the last argument of the math
556 * operators which is a target operand -- thus saving invocation
557 * of and additional Store() operator. An optimization.
558 *
559 ******************************************************************************/
560
561 ACPI_PARSE_OBJECT *
562 TrCreateAssignmentNode (
563 ACPI_PARSE_OBJECT *Target,
564 ACPI_PARSE_OBJECT *Source)
565 {
566 ACPI_PARSE_OBJECT *TargetOp;
567 ACPI_PARSE_OBJECT *SourceOp1;
568 ACPI_PARSE_OBJECT *SourceOp2;
569 ACPI_PARSE_OBJECT *Operator;
570
571
572 DbgPrint (ASL_PARSE_OUTPUT,
573 "\nTrCreateAssignmentNode Line [%u to %u] Source %s Target %s\n",
574 Source->Asl.LineNumber, Source->Asl.EndLine,
575 UtGetOpName (Source->Asl.ParseOpcode),
576 UtGetOpName (Target->Asl.ParseOpcode));
577
578 TrSetNodeFlags (Target, NODE_IS_TARGET);
579
580 switch (Source->Asl.ParseOpcode)
581 {
582 /*
583 * Only these operators can be optimized because they have
584 * a target operand
585 */
586 case PARSEOP_ADD:
587 case PARSEOP_AND:
588 case PARSEOP_DIVIDE:
589 case PARSEOP_INDEX:
590 case PARSEOP_MOD:
591 case PARSEOP_MULTIPLY:
592 case PARSEOP_NOT:
593 case PARSEOP_OR:
594 case PARSEOP_SHIFTLEFT:
595 case PARSEOP_SHIFTRIGHT:
596 case PARSEOP_SUBTRACT:
597 case PARSEOP_XOR:
598
599 break;
600
601 /* Otherwise, just create a normal Store operator */
602
603 default:
604
605 goto CannotOptimize;
606 }
607
608 /*
609 * Transform the parse tree such that the target is moved to the
610 * last operand of the operator
611 */
612 SourceOp1 = Source->Asl.Child;
613 SourceOp2 = SourceOp1->Asl.Next;
614
615 /* NOT only has one operand, but has a target */
616
617 if (Source->Asl.ParseOpcode == PARSEOP_NOT)
618 {
619 SourceOp2 = SourceOp1;
620 }
621
622 /* DIVIDE has an extra target operand (remainder) */
623
624 if (Source->Asl.ParseOpcode == PARSEOP_DIVIDE)
625 {
626 SourceOp2 = SourceOp2->Asl.Next;
627 }
628
629 TargetOp = SourceOp2->Asl.Next;
630
631 /*
632 * Can't perform this optimization if there already is a target
633 * for the operator (ZERO is a "no target" placeholder).
634 */
635 if (TargetOp->Asl.ParseOpcode != PARSEOP_ZERO)
636 {
637 goto CannotOptimize;
638 }
639
640 /* Link in the target as the final operand */
641
642 SourceOp2->Asl.Next = Target;
643 Target->Asl.Parent = Source;
644
645 return (Source);
646
647
648 CannotOptimize:
649
650 Operator = TrAllocateNode (PARSEOP_STORE);
651 TrLinkChildren (Operator, 2, Source, Target);
652
653 /* Set the appropriate line numbers for the new node */
654
655 Operator->Asl.LineNumber = Target->Asl.LineNumber;
656 Operator->Asl.LogicalLineNumber = Target->Asl.LogicalLineNumber;
657 Operator->Asl.LogicalByteOffset = Target->Asl.LogicalByteOffset;
658 Operator->Asl.Column = Target->Asl.Column;
659
660 return (Operator);
661 }
662
663
664 /*******************************************************************************
665 *
666 * FUNCTION: TrCreateLeafNode
667 *
668 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node
669 *
670 * RETURN: Pointer to the new node. Aborts on allocation failure
671 *
672 * DESCRIPTION: Create a simple leaf node (no children or peers, and no value
673 * assigned to the node)
674 *
675 ******************************************************************************/
676
677 ACPI_PARSE_OBJECT *
678 TrCreateLeafNode (
679 UINT32 ParseOpcode)
680 {
681 ACPI_PARSE_OBJECT *Op;
682
683
684 Op = TrAllocateNode (ParseOpcode);
685
686 DbgPrint (ASL_PARSE_OUTPUT,
687 "\nCreateLeafNode Ln/Col %u/%u NewNode %p Op %s\n\n",
688 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode));
689
690 return (Op);
691 }
692
693
694 /*******************************************************************************
695 *
696 * FUNCTION: TrCreateNullTarget
697 *
698 * PARAMETERS: None
699 *
700 * RETURN: Pointer to the new node. Aborts on allocation failure
701 *
702 * DESCRIPTION: Create a "null" target node. This is defined by the ACPI
703 * specification to be a zero AML opcode, and indicates that
704 * no target has been specified for the parent operation
705 *
706 ******************************************************************************/
707
708 ACPI_PARSE_OBJECT *
709 TrCreateNullTarget (
710 void)
711 {
712 ACPI_PARSE_OBJECT *Op;
713
714
715 Op = TrAllocateNode (PARSEOP_ZERO);
716 Op->Asl.CompileFlags |= (NODE_IS_TARGET | NODE_COMPILE_TIME_CONST);
717
718 DbgPrint (ASL_PARSE_OUTPUT,
719 "\nCreateNullTarget Ln/Col %u/%u NewNode %p Op %s\n",
720 Op->Asl.LineNumber, Op->Asl.Column, Op,
721 UtGetOpName (Op->Asl.ParseOpcode));
722
723 return (Op);
724 }
725
726
727 /*******************************************************************************
728 *
729 * FUNCTION: TrCreateConstantLeafNode
730 *
731 * PARAMETERS: ParseOpcode - The constant opcode
732 *
733 * RETURN: Pointer to the new node. Aborts on allocation failure
734 *
735 * DESCRIPTION: Create a leaf node (no children or peers) for one of the
736 * special constants - __LINE__, __FILE__, and __DATE__.
737 *
738 * Note: An implemenation of __FUNC__ cannot happen here because we don't
739 * have a full parse tree at this time and cannot find the parent control
740 * method. If it is ever needed, __FUNC__ must be implemented later, after
741 * the parse tree has been fully constructed.
742 *
743 ******************************************************************************/
744
745 ACPI_PARSE_OBJECT *
746 TrCreateConstantLeafNode (
747 UINT32 ParseOpcode)
748 {
749 ACPI_PARSE_OBJECT *Op = NULL;
750 time_t CurrentTime;
751 char *StaticTimeString;
752 char *TimeString;
753 char *Filename;
754
755
756 switch (ParseOpcode)
757 {
758 case PARSEOP___LINE__:
759
760 Op = TrAllocateNode (PARSEOP_INTEGER);
761 Op->Asl.Value.Integer = Op->Asl.LineNumber;
762 break;
763
764 case PARSEOP___PATH__:
765
766 Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
767
768 /* Op.Asl.Filename contains the full pathname to the file */
769
770 Op->Asl.Value.String = Op->Asl.Filename;
771 break;
772
773 case PARSEOP___FILE__:
774
775 Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
776
777 /* Get the simple filename from the full path */
778
779 FlSplitInputPathname (Op->Asl.Filename, NULL, &Filename);
780 Op->Asl.Value.String = Filename;
781 break;
782
783 case PARSEOP___DATE__:
784
785 Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
786
787 /* Get a copy of the current time */
788
789 CurrentTime = time (NULL);
790 StaticTimeString = ctime (&CurrentTime);
791 TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1);
792 strcpy (TimeString, StaticTimeString);
793
794 TimeString[strlen(TimeString) -1] = 0; /* Remove trailing newline */
795 Op->Asl.Value.String = TimeString;
796 break;
797
798 default: /* This would be an internal error */
799
800 return (NULL);
801 }
802
803 DbgPrint (ASL_PARSE_OUTPUT,
804 "\nCreateConstantLeafNode Ln/Col %u/%u NewNode %p "
805 "Op %s Value %8.8X%8.8X \n",
806 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode),
807 ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer));
808 return (Op);
809 }
810
811
812 /*******************************************************************************
813 *
814 * FUNCTION: TrCreateTargetOperand
815 *
816 * PARAMETERS: OriginalOp - Op to be copied
817 *
818 * RETURN: Pointer to the new node. Aborts on allocation failure
819 *
820 * DESCRIPTION: Copy an existing node (and subtree). Used in ASL+ (C-style)
821 * expressions where the target is the same as one of the
822 * operands. A new node and subtree must be created from the
823 * original so that the parse tree can be linked properly.
824 *
825 * NOTE: This code is specific to target operands that are the last
826 * operand in an ASL/AML operator. Meaning that the top-level
827 * parse Op in a possible subtree has a NULL Next pointer.
828 * This simplifies the recursion.
829 *
830 * Subtree example:
831 * DeRefOf (Local1) += 32
832 *
833 * This gets converted to:
834 * Add (DeRefOf (Local1), 32, DeRefOf (Local1))
835 *
836 * Each DeRefOf has a single child, Local1. Even more complex
837 * subtrees can be created via the Index and DeRefOf operators.
838 *
839 ******************************************************************************/
840
841 ACPI_PARSE_OBJECT *
842 TrCreateTargetOperand (
843 ACPI_PARSE_OBJECT *OriginalOp,
844 ACPI_PARSE_OBJECT *ParentOp)
845 {
846 ACPI_PARSE_OBJECT *Op;
847
848
849 if (!OriginalOp)
850 {
851 return (NULL);
852 }
853
854 Op = TrGetNextNode ();
855
856 /* Copy the pertinent values (omit link pointer fields) */
857
858 Op->Asl.Value = OriginalOp->Asl.Value;
859 Op->Asl.Filename = OriginalOp->Asl.Filename;
860 Op->Asl.LineNumber = OriginalOp->Asl.LineNumber;
861 Op->Asl.LogicalLineNumber = OriginalOp->Asl.LogicalLineNumber;
862 Op->Asl.LogicalByteOffset = OriginalOp->Asl.LogicalByteOffset;
863 Op->Asl.Column = OriginalOp->Asl.Column;
864 Op->Asl.Flags = OriginalOp->Asl.Flags;
865 Op->Asl.CompileFlags = OriginalOp->Asl.CompileFlags;
866 Op->Asl.AmlOpcode = OriginalOp->Asl.AmlOpcode;
867 Op->Asl.ParseOpcode = OriginalOp->Asl.ParseOpcode;
868 Op->Asl.Parent = ParentOp;
869 UtSetParseOpName (Op);
870
871 /* Copy a possible subtree below this node */
872
873 if (OriginalOp->Asl.Child)
874 {
875 Op->Asl.Child = TrCreateTargetOperand (OriginalOp->Asl.Child, Op);
876 }
877
878 if (OriginalOp->Asl.Next) /* Null for top-level node */
879 {
880 Op->Asl.Next = TrCreateTargetOperand (OriginalOp->Asl.Next, ParentOp);
881 }
882
883 return (Op);
884 }
885
886
887 /*******************************************************************************
888 *
889 * FUNCTION: TrCreateValuedLeafNode
890 *
891 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node
892 * Value - Value to be assigned to the node
893 *
894 * RETURN: Pointer to the new node. Aborts on allocation failure
895 *
896 * DESCRIPTION: Create a leaf node (no children or peers) with a value
897 * assigned to it
898 *
899 ******************************************************************************/
900
901 ACPI_PARSE_OBJECT *
902 TrCreateValuedLeafNode (
903 UINT32 ParseOpcode,
904 UINT64 Value)
905 {
906 ACPI_PARSE_OBJECT *Op;
907
908
909 Op = TrAllocateNode (ParseOpcode);
910
911 DbgPrint (ASL_PARSE_OUTPUT,
912 "\nCreateValuedLeafNode Ln/Col %u/%u NewNode %p "
913 "Op %s Value %8.8X%8.8X ",
914 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode),
915 ACPI_FORMAT_UINT64 (Value));
916 Op->Asl.Value.Integer = Value;
917
918 switch (ParseOpcode)
919 {
920 case PARSEOP_STRING_LITERAL:
921
922 DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value);
923 break;
924
925 case PARSEOP_NAMESEG:
926
927 DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value);
928 break;
929
930 case PARSEOP_NAMESTRING:
931
932 DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value);
933 break;
934
935 case PARSEOP_EISAID:
936
937 DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value);
938 break;
939
940 case PARSEOP_METHOD:
941
942 DbgPrint (ASL_PARSE_OUTPUT, "METHOD");
943 break;
944
945 case PARSEOP_INTEGER:
946
947 DbgPrint (ASL_PARSE_OUTPUT, "INTEGER->%8.8X%8.8X",
948 ACPI_FORMAT_UINT64 (Value));
949 break;
950
951 default:
952
953 break;
954 }
955
956 DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
957 return (Op);
958 }
959
960
961 /*******************************************************************************
962 *
963 * FUNCTION: TrCreateNode
964 *
965 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node
966 * NumChildren - Number of children to follow
967 * ... - A list of child nodes to link to the new
968 * node. NumChildren long.
969 *
970 * RETURN: Pointer to the new node. Aborts on allocation failure
971 *
972 * DESCRIPTION: Create a new parse node and link together a list of child
973 * nodes underneath the new node.
974 *
975 ******************************************************************************/
976
977 ACPI_PARSE_OBJECT *
978 TrCreateNode (
979 UINT32 ParseOpcode,
980 UINT32 NumChildren,
981 ...)
982 {
983 ACPI_PARSE_OBJECT *Op;
984 ACPI_PARSE_OBJECT *Child;
985 ACPI_PARSE_OBJECT *PrevChild;
986 va_list ap;
987 UINT32 i;
988 BOOLEAN FirstChild;
989
990
991 va_start (ap, NumChildren);
992
993 /* Allocate one new node */
994
995 Op = TrAllocateNode (ParseOpcode);
996
997 DbgPrint (ASL_PARSE_OUTPUT,
998 "\nCreateNode Ln/Col %u/%u NewParent %p Child %u Op %s ",
999 Op->Asl.LineNumber, Op->Asl.Column, Op,
1000 NumChildren, UtGetOpName(ParseOpcode));
1001
1002 /* Some extra debug output based on the parse opcode */
1003
1004 switch (ParseOpcode)
1005 {
1006 case PARSEOP_ASL_CODE:
1007
1008 Gbl_ParseTreeRoot = Op;
1009 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
1010 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
1011 break;
1012
1013 case PARSEOP_DEFINITION_BLOCK:
1014
1015 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
1016 break;
1017
1018 case PARSEOP_OPERATIONREGION:
1019
1020 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
1021 break;
1022
1023 case PARSEOP_OR:
1024
1025 DbgPrint (ASL_PARSE_OUTPUT, "OR->");
1026 break;
1027
1028 default:
1029
1030 /* Nothing to do for other opcodes */
1031
1032 break;
1033 }
1034
1035 /* Link the new node to its children */
1036
1037 PrevChild = NULL;
1038 FirstChild = TRUE;
1039 for (i = 0; i < NumChildren; i++)
1040 {
1041 /* Get the next child */
1042
1043 Child = va_arg (ap, ACPI_PARSE_OBJECT *);
1044 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
1045
1046 /*
1047 * If child is NULL, this means that an optional argument
1048 * was omitted. We must create a placeholder with a special
1049 * opcode (DEFAULT_ARG) so that the code generator will know
1050 * that it must emit the correct default for this argument
1051 */
1052 if (!Child)
1053 {
1054 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
1055 }
1056
1057 /* Link first child to parent */
1058
1059 if (FirstChild)
1060 {
1061 FirstChild = FALSE;
1062 Op->Asl.Child = Child;
1063 }
1064
1065 /* Point all children to parent */
1066
1067 Child->Asl.Parent = Op;
1068
1069 /* Link children in a peer list */
1070
1071 if (PrevChild)
1072 {
1073 PrevChild->Asl.Next = Child;
1074 };
1075
1076 /*
1077 * This child might be a list, point all nodes in the list
1078 * to the same parent
1079 */
1080 while (Child->Asl.Next)
1081 {
1082 Child = Child->Asl.Next;
1083 Child->Asl.Parent = Op;
1084 }
1085
1086 PrevChild = Child;
1087 }
1088 va_end(ap);
1089
1090 DbgPrint (ASL_PARSE_OUTPUT, "\n");
1091 return (Op);
1092 }
1093
1094
1095 /*******************************************************************************
1096 *
1097 * FUNCTION: TrLinkChildren
1098 *
1099 * PARAMETERS: Op - An existing parse node
1100 * NumChildren - Number of children to follow
1101 * ... - A list of child nodes to link to the new
1102 * node. NumChildren long.
1103 *
1104 * RETURN: The updated (linked) node
1105 *
1106 * DESCRIPTION: Link a group of nodes to an existing parse node
1107 *
1108 ******************************************************************************/
1109
1110 ACPI_PARSE_OBJECT *
1111 TrLinkChildren (
1112 ACPI_PARSE_OBJECT *Op,
1113 UINT32 NumChildren,
1114 ...)
1115 {
1116 ACPI_PARSE_OBJECT *Child;
1117 ACPI_PARSE_OBJECT *PrevChild;
1118 va_list ap;
1119 UINT32 i;
1120 BOOLEAN FirstChild;
1121
1122
1123 va_start (ap, NumChildren);
1124
1125
1126 TrSetEndLineNumber (Op);
1127
1128 DbgPrint (ASL_PARSE_OUTPUT,
1129 "\nLinkChildren Line [%u to %u] NewParent %p Child %u Op %s ",
1130 Op->Asl.LineNumber, Op->Asl.EndLine,
1131 Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode));
1132
1133 switch (Op->Asl.ParseOpcode)
1134 {
1135 case PARSEOP_ASL_CODE:
1136
1137 Gbl_ParseTreeRoot = Op;
1138 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
1139 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
1140 break;
1141
1142 case PARSEOP_DEFINITION_BLOCK:
1143
1144 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
1145 break;
1146
1147 case PARSEOP_OPERATIONREGION:
1148
1149 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
1150 break;
1151
1152 case PARSEOP_OR:
1153
1154 DbgPrint (ASL_PARSE_OUTPUT, "OR->");
1155 break;
1156
1157 default:
1158
1159 /* Nothing to do for other opcodes */
1160
1161 break;
1162 }
1163
1164 /* Link the new node to it's children */
1165
1166 PrevChild = NULL;
1167 FirstChild = TRUE;
1168 for (i = 0; i < NumChildren; i++)
1169 {
1170 Child = va_arg (ap, ACPI_PARSE_OBJECT *);
1171
1172 if ((Child == PrevChild) && (Child != NULL))
1173 {
1174 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child,
1175 "Child node list invalid");
1176 va_end(ap);
1177 return (Op);
1178 }
1179
1180 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
1181
1182 /*
1183 * If child is NULL, this means that an optional argument
1184 * was omitted. We must create a placeholder with a special
1185 * opcode (DEFAULT_ARG) so that the code generator will know
1186 * that it must emit the correct default for this argument
1187 */
1188 if (!Child)
1189 {
1190 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
1191 }
1192
1193 /* Link first child to parent */
1194
1195 if (FirstChild)
1196 {
1197 FirstChild = FALSE;
1198 Op->Asl.Child = Child;
1199 }
1200
1201 /* Point all children to parent */
1202
1203 Child->Asl.Parent = Op;
1204
1205 /* Link children in a peer list */
1206
1207 if (PrevChild)
1208 {
1209 PrevChild->Asl.Next = Child;
1210 };
1211
1212 /*
1213 * This child might be a list, point all nodes in the list
1214 * to the same parent
1215 */
1216 while (Child->Asl.Next)
1217 {
1218 Child = Child->Asl.Next;
1219 Child->Asl.Parent = Op;
1220 }
1221
1222 PrevChild = Child;
1223 }
1224
1225 va_end(ap);
1226 DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
1227 return (Op);
1228 }
1229
1230
1231 /*******************************************************************************
1232 *
1233 * FUNCTION: TrLinkPeerNode
1234 *
1235 * PARAMETERS: Op1 - First peer
1236 * Op2 - Second peer
1237 *
1238 * RETURN: Op1 or the non-null node.
1239 *
1240 * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null.
1241 *
1242 ******************************************************************************/
1243
1244 ACPI_PARSE_OBJECT *
1245 TrLinkPeerNode (
1246 ACPI_PARSE_OBJECT *Op1,
1247 ACPI_PARSE_OBJECT *Op2)
1248 {
1249 ACPI_PARSE_OBJECT *Next;
1250
1251
1252 DbgPrint (ASL_PARSE_OUTPUT,
1253 "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n",
1254 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL,
1255 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL);
1256
1257
1258 if ((!Op1) && (!Op2))
1259 {
1260 DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n");
1261 return (Op1);
1262 }
1263
1264 /* If one of the nodes is null, just return the non-null node */
1265
1266 if (!Op2)
1267 {
1268 return (Op1);
1269 }
1270
1271 if (!Op1)
1272 {
1273 return (Op2);
1274 }
1275
1276 if (Op1 == Op2)
1277 {
1278 DbgPrint (ASL_DEBUG_OUTPUT,
1279 "\n************* Internal error, linking node to itself %p\n",
1280 Op1);
1281 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1,
1282 "Linking node to itself");
1283 return (Op1);
1284 }
1285
1286 Op1->Asl.Parent = Op2->Asl.Parent;
1287
1288 /*
1289 * Op 1 may already have a peer list (such as an IF/ELSE pair),
1290 * so we must walk to the end of the list and attach the new
1291 * peer at the end
1292 */
1293 Next = Op1;
1294 while (Next->Asl.Next)
1295 {
1296 Next = Next->Asl.Next;
1297 }
1298
1299 Next->Asl.Next = Op2;
1300 return (Op1);
1301 }
1302
1303
1304 /*******************************************************************************
1305 *
1306 * FUNCTION: TrLinkPeerNodes
1307 *
1308 * PARAMETERS: NumPeers - The number of nodes in the list to follow
1309 * ... - A list of nodes to link together as peers
1310 *
1311 * RETURN: The first node in the list (head of the peer list)
1312 *
1313 * DESCRIPTION: Link together an arbitrary number of peer nodes.
1314 *
1315 ******************************************************************************/
1316
1317 ACPI_PARSE_OBJECT *
1318 TrLinkPeerNodes (
1319 UINT32 NumPeers,
1320 ...)
1321 {
1322 ACPI_PARSE_OBJECT *This;
1323 ACPI_PARSE_OBJECT *Next;
1324 va_list ap;
1325 UINT32 i;
1326 ACPI_PARSE_OBJECT *Start;
1327
1328
1329 DbgPrint (ASL_PARSE_OUTPUT,
1330 "\nLinkPeerNodes: (%u) ", NumPeers);
1331
1332 va_start (ap, NumPeers);
1333 This = va_arg (ap, ACPI_PARSE_OBJECT *);
1334 Start = This;
1335
1336 /*
1337 * Link all peers
1338 */
1339 for (i = 0; i < (NumPeers -1); i++)
1340 {
1341 DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This);
1342
1343 while (This->Asl.Next)
1344 {
1345 This = This->Asl.Next;
1346 }
1347
1348 /* Get another peer node */
1349
1350 Next = va_arg (ap, ACPI_PARSE_OBJECT *);
1351 if (!Next)
1352 {
1353 Next = TrAllocateNode (PARSEOP_DEFAULT_ARG);
1354 }
1355
1356 /* link new node to the current node */
1357
1358 This->Asl.Next = Next;
1359 This = Next;
1360 }
1361 va_end (ap);
1362
1363 DbgPrint (ASL_PARSE_OUTPUT,"\n");
1364 return (Start);
1365 }
1366
1367
1368 /*******************************************************************************
1369 *
1370 * FUNCTION: TrLinkChildNode
1371 *
1372 * PARAMETERS: Op1 - Parent node
1373 * Op2 - Op to become a child
1374 *
1375 * RETURN: The parent node
1376 *
1377 * DESCRIPTION: Link two nodes together as a parent and child
1378 *
1379 ******************************************************************************/
1380
1381 ACPI_PARSE_OBJECT *
1382 TrLinkChildNode (
1383 ACPI_PARSE_OBJECT *Op1,
1384 ACPI_PARSE_OBJECT *Op2)
1385 {
1386 ACPI_PARSE_OBJECT *Next;
1387
1388
1389 DbgPrint (ASL_PARSE_OUTPUT,
1390 "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n",
1391 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL,
1392 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL);
1393
1394 if (!Op1 || !Op2)
1395 {
1396 return (Op1);
1397 }
1398
1399 Op1->Asl.Child = Op2;
1400
1401 /* Set the child and all peers of the child to point to the parent */
1402
1403 Next = Op2;
1404 while (Next)
1405 {
1406 Next->Asl.Parent = Op1;
1407 Next = Next->Asl.Next;
1408 }
1409
1410 return (Op1);
1411 }
1412
1413
1414 /*******************************************************************************
1415 *
1416 * FUNCTION: TrWalkParseTree
1417 *
1418 * PARAMETERS: Visitation - Type of walk
1419 * DescendingCallback - Called during tree descent
1420 * AscendingCallback - Called during tree ascent
1421 * Context - To be passed to the callbacks
1422 *
1423 * RETURN: Status from callback(s)
1424 *
1425 * DESCRIPTION: Walk the entire parse tree.
1426 *
1427 ******************************************************************************/
1428
1429 ACPI_STATUS
1430 TrWalkParseTree (
1431 ACPI_PARSE_OBJECT *Op,
1432 UINT32 Visitation,
1433 ASL_WALK_CALLBACK DescendingCallback,
1434 ASL_WALK_CALLBACK AscendingCallback,
1435 void *Context)
1436 {
1437 UINT32 Level;
1438 BOOLEAN NodePreviouslyVisited;
1439 ACPI_PARSE_OBJECT *StartOp = Op;
1440 ACPI_STATUS Status;
1441
1442
1443 if (!Gbl_ParseTreeRoot)
1444 {
1445 return (AE_OK);
1446 }
1447
1448 Level = 0;
1449 NodePreviouslyVisited = FALSE;
1450
1451 switch (Visitation)
1452 {
1453 case ASL_WALK_VISIT_DOWNWARD:
1454
1455 while (Op)
1456 {
1457 if (!NodePreviouslyVisited)
1458 {
1459 /* Let the callback process the node. */
1460
1461 Status = DescendingCallback (Op, Level, Context);
1462 if (ACPI_SUCCESS (Status))
1463 {
1464 /* Visit children first, once */
1465
1466 if (Op->Asl.Child)
1467 {
1468 Level++;
1469 Op = Op->Asl.Child;
1470 continue;
1471 }
1472 }
1473 else if (Status != AE_CTRL_DEPTH)
1474 {
1475 /* Exit immediately on any error */
1476
1477 return (Status);
1478 }
1479 }
1480
1481 /* Terminate walk at start op */
1482
1483 if (Op == StartOp)
1484 {
1485 break;
1486 }
1487
1488 /* No more children, visit peers */
1489
1490 if (Op->Asl.Next)
1491 {
1492 Op = Op->Asl.Next;
1493 NodePreviouslyVisited = FALSE;
1494 }
1495 else
1496 {
1497 /* No children or peers, re-visit parent */
1498
1499 if (Level != 0 )
1500 {
1501 Level--;
1502 }
1503 Op = Op->Asl.Parent;
1504 NodePreviouslyVisited = TRUE;
1505 }
1506 }
1507 break;
1508
1509 case ASL_WALK_VISIT_UPWARD:
1510
1511 while (Op)
1512 {
1513 /* Visit leaf node (no children) or parent node on return trip */
1514
1515 if ((!Op->Asl.Child) ||
1516 (NodePreviouslyVisited))
1517 {
1518 /* Let the callback process the node. */
1519
1520 Status = AscendingCallback (Op, Level, Context);
1521 if (ACPI_FAILURE (Status))
1522 {
1523 return (Status);
1524 }
1525 }
1526 else
1527 {
1528 /* Visit children first, once */
1529
1530 Level++;
1531 Op = Op->Asl.Child;
1532 continue;
1533 }
1534
1535 /* Terminate walk at start op */
1536
1537 if (Op == StartOp)
1538 {
1539 break;
1540 }
1541
1542 /* No more children, visit peers */
1543
1544 if (Op->Asl.Next)
1545 {
1546 Op = Op->Asl.Next;
1547 NodePreviouslyVisited = FALSE;
1548 }
1549 else
1550 {
1551 /* No children or peers, re-visit parent */
1552
1553 if (Level != 0 )
1554 {
1555 Level--;
1556 }
1557 Op = Op->Asl.Parent;
1558 NodePreviouslyVisited = TRUE;
1559 }
1560 }
1561 break;
1562
1563 case ASL_WALK_VISIT_TWICE:
1564
1565 while (Op)
1566 {
1567 if (NodePreviouslyVisited)
1568 {
1569 Status = AscendingCallback (Op, Level, Context);
1570 if (ACPI_FAILURE (Status))
1571 {
1572 return (Status);
1573 }
1574 }
1575 else
1576 {
1577 /* Let the callback process the node. */
1578
1579 Status = DescendingCallback (Op, Level, Context);
1580 if (ACPI_SUCCESS (Status))
1581 {
1582 /* Visit children first, once */
1583
1584 if (Op->Asl.Child)
1585 {
1586 Level++;
1587 Op = Op->Asl.Child;
1588 continue;
1589 }
1590 }
1591 else if (Status != AE_CTRL_DEPTH)
1592 {
1593 /* Exit immediately on any error */
1594
1595 return (Status);
1596 }
1597 }
1598
1599 /* Terminate walk at start op */
1600
1601 if (Op == StartOp)
1602 {
1603 break;
1604 }
1605
1606 /* No more children, visit peers */
1607
1608 if (Op->Asl.Next)
1609 {
1610 Op = Op->Asl.Next;
1611 NodePreviouslyVisited = FALSE;
1612 }
1613 else
1614 {
1615 /* No children or peers, re-visit parent */
1616
1617 if (Level != 0 )
1618 {
1619 Level--;
1620 }
1621 Op = Op->Asl.Parent;
1622 NodePreviouslyVisited = TRUE;
1623 }
1624 }
1625 break;
1626
1627 default:
1628 /* No other types supported */
1629 break;
1630 }
1631
1632 /* If we get here, the walk completed with no errors */
1633
1634 return (AE_OK);
1635 }
1636