xref: /freebsd/sys/contrib/dev/acpica/compiler/aslmethod.c (revision 119b75925c562202145d7bac7b676b98029c6cb9)
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 
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] |= 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 & 0x0007);
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 (!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 (!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 
490 void
491 MtCheckNamedObjectInMethod (
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 
544 ACPI_STATUS
545 MtMethodAnalysisWalkEnd (
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