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