aslmethod.c revision 281075
1/******************************************************************************
2 *
3 * Module Name: aslmethod.c - Control method analysis walk
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2015, 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/acparser.h>
47#include <contrib/dev/acpica/include/amlcode.h>
48
49
50#define _COMPONENT          ACPI_COMPILER
51        ACPI_MODULE_NAME    ("aslmethod")
52
53
54/* Local prototypes */
55
56void
57MtCheckNamedObjectInMethod (
58    ACPI_PARSE_OBJECT       *Op,
59    ASL_METHOD_INFO         *MethodInfo);
60
61
62/*******************************************************************************
63 *
64 * FUNCTION:    MtMethodAnalysisWalkBegin
65 *
66 * PARAMETERS:  ASL_WALK_CALLBACK
67 *
68 * RETURN:      Status
69 *
70 * DESCRIPTION: Descending callback for the analysis walk. Check methods for:
71 *              1) Initialized local variables
72 *              2) Valid arguments
73 *              3) Return types
74 *
75 ******************************************************************************/
76
77ACPI_STATUS
78MtMethodAnalysisWalkBegin (
79    ACPI_PARSE_OBJECT       *Op,
80    UINT32                  Level,
81    void                    *Context)
82{
83    ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
84    ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
85    ACPI_PARSE_OBJECT       *Next;
86    UINT32                  RegisterNumber;
87    UINT32                  i;
88    char                    LocalName[] = "Local0";
89    char                    ArgName[] = "Arg0";
90    ACPI_PARSE_OBJECT       *ArgNode;
91    ACPI_PARSE_OBJECT       *NextType;
92    ACPI_PARSE_OBJECT       *NextParamType;
93    UINT8                   ActualArgs = 0;
94
95
96    switch (Op->Asl.ParseOpcode)
97    {
98    case PARSEOP_METHOD:
99
100        TotalMethods++;
101
102        /* Create and init method info */
103
104        MethodInfo       = UtLocalCalloc (sizeof (ASL_METHOD_INFO));
105        MethodInfo->Next = WalkInfo->MethodStack;
106        MethodInfo->Op = Op;
107
108        WalkInfo->MethodStack = MethodInfo;
109
110        /*
111         * Special handling for _PSx methods. Dependency rules (same scope):
112         *
113         * 1) _PS0 - One of these must exist: _PS1, _PS2, _PS3
114         * 2) _PS1/_PS2/_PS3: A _PS0 must exist
115         */
116        if (ACPI_COMPARE_NAME (METHOD_NAME__PS0, Op->Asl.NameSeg))
117        {
118            /* For _PS0, one of _PS1/_PS2/_PS3 must exist */
119
120            if ((!ApFindNameInScope (METHOD_NAME__PS1, Op)) &&
121                (!ApFindNameInScope (METHOD_NAME__PS2, Op)) &&
122                (!ApFindNameInScope (METHOD_NAME__PS3, Op)))
123            {
124                AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
125                    "_PS0 requires one of _PS1/_PS2/_PS3 in same scope");
126            }
127        }
128        else if (
129            ACPI_COMPARE_NAME (METHOD_NAME__PS1, Op->Asl.NameSeg) ||
130            ACPI_COMPARE_NAME (METHOD_NAME__PS2, Op->Asl.NameSeg) ||
131            ACPI_COMPARE_NAME (METHOD_NAME__PS3, Op->Asl.NameSeg))
132        {
133            /* For _PS1/_PS2/_PS3, a _PS0 must exist */
134
135            if (!ApFindNameInScope (METHOD_NAME__PS0, Op))
136            {
137                sprintf (MsgBuffer,
138                    "%4.4s requires _PS0 in same scope", Op->Asl.NameSeg);
139
140                AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
141                    MsgBuffer);
142            }
143        }
144
145        /* Get the name node */
146
147        Next = Op->Asl.Child;
148
149        /* Get the NumArguments node */
150
151        Next = Next->Asl.Next;
152        MethodInfo->NumArguments = (UINT8)
153            (((UINT8) Next->Asl.Value.Integer) & 0x07);
154
155        /* Get the SerializeRule and SyncLevel nodes, ignored here */
156
157        Next = Next->Asl.Next;
158        MethodInfo->ShouldBeSerialized = (UINT8) Next->Asl.Value.Integer;
159
160        Next = Next->Asl.Next;
161        ArgNode = Next;
162
163        /* Get the ReturnType node */
164
165        Next = Next->Asl.Next;
166
167        NextType = Next->Asl.Child;
168        while (NextType)
169        {
170            /* Get and map each of the ReturnTypes */
171
172            MethodInfo->ValidReturnTypes |= AnMapObjTypeToBtype (NextType);
173            NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
174            NextType = NextType->Asl.Next;
175        }
176
177        /* Get the ParameterType node */
178
179        Next = Next->Asl.Next;
180
181        NextType = Next->Asl.Child;
182        while (NextType)
183        {
184            if (NextType->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
185            {
186                NextParamType = NextType->Asl.Child;
187                while (NextParamType)
188                {
189                    MethodInfo->ValidArgTypes[ActualArgs] |= AnMapObjTypeToBtype (NextParamType);
190                    NextParamType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
191                    NextParamType = NextParamType->Asl.Next;
192                }
193            }
194            else
195            {
196                MethodInfo->ValidArgTypes[ActualArgs] =
197                    AnMapObjTypeToBtype (NextType);
198                NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
199                ActualArgs++;
200            }
201
202            NextType = NextType->Asl.Next;
203        }
204
205        if ((MethodInfo->NumArguments) &&
206            (MethodInfo->NumArguments != ActualArgs))
207        {
208            /* error: Param list did not match number of args */
209        }
210
211        /* Allow numarguments == 0 for Function() */
212
213        if ((!MethodInfo->NumArguments) && (ActualArgs))
214        {
215            MethodInfo->NumArguments = ActualArgs;
216            ArgNode->Asl.Value.Integer |= ActualArgs;
217        }
218
219        /*
220         * Actual arguments are initialized at method entry.
221         * All other ArgX "registers" can be used as locals, so we
222         * track their initialization.
223         */
224        for (i = 0; i < MethodInfo->NumArguments; i++)
225        {
226            MethodInfo->ArgInitialized[i] = TRUE;
227        }
228        break;
229
230    case PARSEOP_METHODCALL:
231
232        if (MethodInfo &&
233           (Op->Asl.Node == MethodInfo->Op->Asl.Node))
234        {
235            AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName);
236        }
237        break;
238
239    case PARSEOP_LOCAL0:
240    case PARSEOP_LOCAL1:
241    case PARSEOP_LOCAL2:
242    case PARSEOP_LOCAL3:
243    case PARSEOP_LOCAL4:
244    case PARSEOP_LOCAL5:
245    case PARSEOP_LOCAL6:
246    case PARSEOP_LOCAL7:
247
248        if (!MethodInfo)
249        {
250            /*
251             * Local was used outside a control method, or there was an error
252             * in the method declaration.
253             */
254            AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName);
255            return (AE_ERROR);
256        }
257
258        RegisterNumber = (Op->Asl.AmlOpcode & 0x000F);
259
260        /*
261         * If the local is being used as a target, mark the local
262         * initialized
263         */
264        if (Op->Asl.CompileFlags & NODE_IS_TARGET)
265        {
266            MethodInfo->LocalInitialized[RegisterNumber] = TRUE;
267        }
268
269        /*
270         * Otherwise, this is a reference, check if the local
271         * has been previously initialized.
272         *
273         * The only operator that accepts an uninitialized value is ObjectType()
274         */
275        else if ((!MethodInfo->LocalInitialized[RegisterNumber]) &&
276                 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
277        {
278            LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30);
279            AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName);
280        }
281        break;
282
283    case PARSEOP_ARG0:
284    case PARSEOP_ARG1:
285    case PARSEOP_ARG2:
286    case PARSEOP_ARG3:
287    case PARSEOP_ARG4:
288    case PARSEOP_ARG5:
289    case PARSEOP_ARG6:
290
291        if (!MethodInfo)
292        {
293            /*
294             * Arg was used outside a control method, or there was an error
295             * in the method declaration.
296             */
297            AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName);
298            return (AE_ERROR);
299        }
300
301        RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8;
302        ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30);
303
304        /*
305         * If the Arg is being used as a target, mark the local
306         * initialized
307         */
308        if (Op->Asl.CompileFlags & NODE_IS_TARGET)
309        {
310            MethodInfo->ArgInitialized[RegisterNumber] = TRUE;
311        }
312
313        /*
314         * Otherwise, this is a reference, check if the Arg
315         * has been previously initialized.
316         *
317         * The only operator that accepts an uninitialized value is ObjectType()
318         */
319        else if ((!MethodInfo->ArgInitialized[RegisterNumber]) &&
320                 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
321        {
322            AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName);
323        }
324
325        /* Flag this arg if it is not a "real" argument to the method */
326
327        if (RegisterNumber >= MethodInfo->NumArguments)
328        {
329            AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName);
330        }
331        break;
332
333    case PARSEOP_RETURN:
334
335        if (!MethodInfo)
336        {
337            /*
338             * Probably was an error in the method declaration,
339             * no additional error here
340             */
341            ACPI_WARNING ((AE_INFO, "%p, No parent method", Op));
342            return (AE_ERROR);
343        }
344
345        /*
346         * A child indicates a possible return value. A simple Return or
347         * Return() is marked with NODE_IS_NULL_RETURN by the parser so
348         * that it is not counted as a "real" return-with-value, although
349         * the AML code that is actually emitted is Return(0). The AML
350         * definition of Return has a required parameter, so we are
351         * forced to convert a null return to Return(0).
352         */
353        if ((Op->Asl.Child) &&
354            (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) &&
355            (!(Op->Asl.Child->Asl.CompileFlags & NODE_IS_NULL_RETURN)))
356        {
357            MethodInfo->NumReturnWithValue++;
358        }
359        else
360        {
361            MethodInfo->NumReturnNoValue++;
362        }
363        break;
364
365    case PARSEOP_BREAK:
366    case PARSEOP_CONTINUE:
367
368        Next = Op->Asl.Parent;
369        while (Next)
370        {
371            if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
372            {
373                break;
374            }
375            Next = Next->Asl.Parent;
376        }
377
378        if (!Next)
379        {
380            AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
381        }
382        break;
383
384    case PARSEOP_STALL:
385
386        /* We can range check if the argument is an integer */
387
388        if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
389            (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
390        {
391            AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
392        }
393        break;
394
395    case PARSEOP_DEVICE:
396
397        Next = Op->Asl.Child;
398
399        if (!ApFindNameInScope (METHOD_NAME__HID, Next) &&
400            !ApFindNameInScope (METHOD_NAME__ADR, Next))
401        {
402            AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
403                "Device object requires a _HID or _ADR in same scope");
404        }
405        break;
406
407    case PARSEOP_EVENT:
408    case PARSEOP_MUTEX:
409    case PARSEOP_OPERATIONREGION:
410    case PARSEOP_POWERRESOURCE:
411    case PARSEOP_PROCESSOR:
412    case PARSEOP_THERMALZONE:
413
414        /*
415         * The first operand is a name to be created in the namespace.
416         * Check against the reserved list.
417         */
418        i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
419        if (i < ACPI_VALID_RESERVED_NAME_MAX)
420        {
421            AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, Op, Op->Asl.ExternalName);
422        }
423        break;
424
425    case PARSEOP_NAME:
426
427        /* Typecheck any predefined names statically defined with Name() */
428
429        ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
430
431        /* Special typechecking for _HID */
432
433        if (!ACPI_STRCMP (METHOD_NAME__HID, Op->Asl.NameSeg))
434        {
435            Next = Op->Asl.Child->Asl.Next;
436            AnCheckId (Next, ASL_TYPE_HID);
437        }
438
439        /* Special typechecking for _CID */
440
441        else if (!ACPI_STRCMP (METHOD_NAME__CID, Op->Asl.NameSeg))
442        {
443            Next = Op->Asl.Child->Asl.Next;
444
445            if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
446                (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
447            {
448                Next = Next->Asl.Child;
449                while (Next)
450                {
451                    AnCheckId (Next, ASL_TYPE_CID);
452                    Next = Next->Asl.Next;
453                }
454            }
455            else
456            {
457                AnCheckId (Next, ASL_TYPE_CID);
458            }
459        }
460
461        break;
462
463    default:
464
465        break;
466    }
467
468    /* Check for named object creation within a non-serialized method */
469
470    MtCheckNamedObjectInMethod (Op, MethodInfo);
471    return (AE_OK);
472}
473
474
475/*******************************************************************************
476 *
477 * FUNCTION:    MtCheckNamedObjectInMethod
478 *
479 * PARAMETERS:  Op                  - Current parser op
480 *              MethodInfo          - Info for method being parsed
481 *
482 * RETURN:      None
483 *
484 * DESCRIPTION: Detect if a non-serialized method is creating a named object,
485 *              which could possibly cause problems if two threads execute
486 *              the method concurrently. Emit a remark in this case.
487 *
488 ******************************************************************************/
489
490void
491MtCheckNamedObjectInMethod (
492    ACPI_PARSE_OBJECT       *Op,
493    ASL_METHOD_INFO         *MethodInfo)
494{
495    const ACPI_OPCODE_INFO  *OpInfo;
496
497
498    /* We don't care about actual method declarations */
499
500    if (Op->Asl.AmlOpcode == AML_METHOD_OP)
501    {
502        return;
503    }
504
505    /* Determine if we are creating a named object */
506
507    OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
508    if (OpInfo->Class == AML_CLASS_NAMED_OBJECT)
509    {
510        /*
511         * If we have a named object created within a non-serialized method,
512         * emit a remark that the method should be serialized.
513         *
514         * Reason: If a thread blocks within the method for any reason, and
515         * another thread enters the method, the method will fail because an
516         * attempt will be made to create the same object twice.
517         */
518        if (MethodInfo && !MethodInfo->ShouldBeSerialized)
519        {
520            AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op,
521                "due to creation of named objects within");
522
523            /* Emit message only ONCE per method */
524
525            MethodInfo->ShouldBeSerialized = TRUE;
526        }
527    }
528}
529
530
531/*******************************************************************************
532 *
533 * FUNCTION:    MtMethodAnalysisWalkEnd
534 *
535 * PARAMETERS:  ASL_WALK_CALLBACK
536 *
537 * RETURN:      Status
538 *
539 * DESCRIPTION: Ascending callback for analysis walk. Complete method
540 *              return analysis.
541 *
542 ******************************************************************************/
543
544ACPI_STATUS
545MtMethodAnalysisWalkEnd (
546    ACPI_PARSE_OBJECT       *Op,
547    UINT32                  Level,
548    void                    *Context)
549{
550    ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
551    ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
552
553
554    switch (Op->Asl.ParseOpcode)
555    {
556    case PARSEOP_METHOD:
557    case PARSEOP_RETURN:
558
559        if (!MethodInfo)
560        {
561            printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
562            AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
563                "No method info for this method");
564
565            CmCleanupAndExit ();
566            return (AE_AML_INTERNAL);
567        }
568        break;
569
570    default:
571
572        break;
573    }
574
575    switch (Op->Asl.ParseOpcode)
576    {
577    case PARSEOP_METHOD:
578
579        WalkInfo->MethodStack = MethodInfo->Next;
580
581        /*
582         * Check if there is no return statement at the end of the
583         * method AND we can actually get there -- i.e., the execution
584         * of the method can possibly terminate without a return statement.
585         */
586        if ((!AnLastStatementIsReturn (Op)) &&
587            (!(Op->Asl.CompileFlags & NODE_HAS_NO_EXIT)))
588        {
589            /*
590             * No return statement, and execution can possibly exit
591             * via this path. This is equivalent to Return ()
592             */
593            MethodInfo->NumReturnNoValue++;
594        }
595
596        /*
597         * Check for case where some return statements have a return value
598         * and some do not. Exit without a return statement is a return with
599         * no value
600         */
601        if (MethodInfo->NumReturnNoValue &&
602            MethodInfo->NumReturnWithValue)
603        {
604            AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
605                Op->Asl.ExternalName);
606        }
607
608        /*
609         * If there are any RETURN() statements with no value, or there is a
610         * control path that allows the method to exit without a return value,
611         * we mark the method as a method that does not return a value. This
612         * knowledge can be used to check method invocations that expect a
613         * returned value.
614         */
615        if (MethodInfo->NumReturnNoValue)
616        {
617            if (MethodInfo->NumReturnWithValue)
618            {
619                Op->Asl.CompileFlags |= NODE_METHOD_SOME_NO_RETVAL;
620            }
621            else
622            {
623                Op->Asl.CompileFlags |= NODE_METHOD_NO_RETVAL;
624            }
625        }
626
627        /*
628         * Check predefined method names for correct return behavior
629         * and correct number of arguments. Also, some special checks
630         * For GPE and _REG methods.
631         */
632        if (ApCheckForPredefinedMethod (Op, MethodInfo))
633        {
634            /* Special check for two names like _L01 and _E01 in same scope */
635
636            ApCheckForGpeNameConflict (Op);
637
638            /*
639             * Special check for _REG: Must have an operation region definition
640             * within the same scope!
641             */
642            ApCheckRegMethod (Op);
643        }
644
645        ACPI_FREE (MethodInfo);
646        break;
647
648    case PARSEOP_NAME:
649
650         /* Special check for two names like _L01 and _E01 in same scope */
651
652        ApCheckForGpeNameConflict (Op);
653        break;
654
655    case PARSEOP_RETURN:
656
657        /*
658         * If the parent is a predefined method name, attempt to typecheck
659         * the return value. Only static types can be validated.
660         */
661        ApCheckPredefinedReturnValue (Op, MethodInfo);
662
663        /*
664         * The parent block does not "exit" and continue execution -- the
665         * method is terminated here with the Return() statement.
666         */
667        Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
668
669        /* Used in the "typing" pass later */
670
671        Op->Asl.ParentMethod = MethodInfo->Op;
672
673        /*
674         * If there is a peer node after the return statement, then this
675         * node is unreachable code -- i.e., it won't be executed because of
676         * the preceding Return() statement.
677         */
678        if (Op->Asl.Next)
679        {
680            AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE, Op->Asl.Next, NULL);
681        }
682        break;
683
684    case PARSEOP_IF:
685
686        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
687            (Op->Asl.Next) &&
688            (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
689        {
690            /*
691             * This IF has a corresponding ELSE. The IF block has no exit,
692             * (it contains an unconditional Return)
693             * mark the ELSE block to remember this fact.
694             */
695            Op->Asl.Next->Asl.CompileFlags |= NODE_IF_HAS_NO_EXIT;
696        }
697        break;
698
699    case PARSEOP_ELSE:
700
701        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
702            (Op->Asl.CompileFlags & NODE_IF_HAS_NO_EXIT))
703        {
704            /*
705             * This ELSE block has no exit and the corresponding IF block
706             * has no exit either. Therefore, the parent node has no exit.
707             */
708            Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
709        }
710        break;
711
712
713    default:
714
715        if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) &&
716            (Op->Asl.Parent))
717        {
718            /* If this node has no exit, then the parent has no exit either */
719
720            Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT;
721        }
722        break;
723    }
724
725    return (AE_OK);
726}
727