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