asltree.c revision 306536
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 <contrib/dev/acpica/compiler/aslcompiler.h>
45#include "aslcompiler.y.h"
46#include <contrib/dev/acpica/include/acapps.h>
47#include <time.h>
48
49#define _COMPONENT          ACPI_COMPILER
50        ACPI_MODULE_NAME    ("asltree")
51
52/* Local prototypes */
53
54static ACPI_PARSE_OBJECT *
55TrGetNextNode (
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
72void
73TrSetParent (
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
96static ACPI_PARSE_OBJECT *
97TrGetNextNode (
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
138ACPI_PARSE_OBJECT *
139TrAllocateNode (
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
172void
173TrReleaseNode (
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
193void
194TrSetCurrentFilename (
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
217ACPI_PARSE_OBJECT *
218TrUpdateNode (
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
313void
314TrPrintNodeCompileFlags (
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
459ACPI_PARSE_OBJECT *
460TrSetNodeFlags (
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
496ACPI_PARSE_OBJECT *
497TrSetNodeAmlLength (
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
528void
529TrSetEndLineNumber (
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
561ACPI_PARSE_OBJECT *
562TrCreateAssignmentNode (
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
648CannotOptimize:
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
677ACPI_PARSE_OBJECT *
678TrCreateLeafNode (
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
708ACPI_PARSE_OBJECT *
709TrCreateNullTarget (
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
745ACPI_PARSE_OBJECT *
746TrCreateConstantLeafNode (
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
841ACPI_PARSE_OBJECT *
842TrCreateTargetOperand (
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
901ACPI_PARSE_OBJECT *
902TrCreateValuedLeafNode (
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
977ACPI_PARSE_OBJECT *
978TrCreateNode (
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
1110ACPI_PARSE_OBJECT *
1111TrLinkChildren (
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
1244ACPI_PARSE_OBJECT *
1245TrLinkPeerNode (
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
1317ACPI_PARSE_OBJECT *
1318TrLinkPeerNodes (
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
1381ACPI_PARSE_OBJECT *
1382TrLinkChildNode (
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
1429ACPI_STATUS
1430TrWalkParseTree (
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