xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/aslmethod.c (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1 /******************************************************************************
2  *
3  * Module Name: aslmethod.c - Control method analysis walk
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2019, 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 (AslGbl_CrossReferenceOutput)
99     {
100         OtXrefWalkPart1 (Op, Level, MethodInfo);
101     }
102 
103     switch (Op->Asl.ParseOpcode)
104     {
105     case PARSEOP_METHOD:
106 
107         AslGbl_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_NAMESEG (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_NAMESEG (METHOD_NAME__PS1, Op->Asl.NameSeg) ||
137             ACPI_COMPARE_NAMESEG (METHOD_NAME__PS2, Op->Asl.NameSeg) ||
138             ACPI_COMPARE_NAMESEG (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 (AslGbl_MsgBuffer,
145                     "%4.4s requires _PS0 in same scope", Op->Asl.NameSeg);
146 
147                 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
148                     AslGbl_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         /* Check for a recursive method call */
243 
244         if (MethodInfo &&
245            (Op->Asl.Node == MethodInfo->Op->Asl.Node))
246         {
247             if (MethodInfo->CreatesNamedObjects)
248             {
249                 /*
250                  * This is an error, as it will fail at runtime on all ACPI
251                  * implementations. Any named object declarations will be
252                  * executed twice, causing failure the second time. Note,
253                  * this is independent of whether the method is declared
254                  * Serialized, because the same thread is attempting to
255                  * reenter the method, and this will always succeed.
256                  */
257                 AslDualParseOpError (ASL_ERROR, ASL_MSG_ILLEGAL_RECURSION, Op,
258                     Op->Asl.Value.String, ASL_MSG_FOUND_HERE, MethodInfo->Op,
259                     MethodInfo->Op->Asl.ExternalName);
260             }
261             else
262             {
263                 /* Method does not create objects, issue a remark */
264 
265                 AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName);
266             }
267         }
268         break;
269 
270     case PARSEOP_LOCAL0:
271     case PARSEOP_LOCAL1:
272     case PARSEOP_LOCAL2:
273     case PARSEOP_LOCAL3:
274     case PARSEOP_LOCAL4:
275     case PARSEOP_LOCAL5:
276     case PARSEOP_LOCAL6:
277     case PARSEOP_LOCAL7:
278 
279         if (!MethodInfo)
280         {
281             /*
282              * Local was used outside a control method, or there was an error
283              * in the method declaration.
284              */
285             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
286                 Op, Op->Asl.ExternalName);
287             return (AE_ERROR);
288         }
289 
290         RegisterNumber = (Op->Asl.AmlOpcode & 0x0007);
291 
292         /*
293          * If the local is being used as a target, mark the local
294          * initialized
295          */
296         if (Op->Asl.CompileFlags & OP_IS_TARGET)
297         {
298             MethodInfo->LocalInitialized[RegisterNumber] = TRUE;
299         }
300 
301         /*
302          * Otherwise, this is a reference, check if the local
303          * has been previously initialized.
304          *
305          * The only operator that accepts an uninitialized value is ObjectType()
306          */
307         else if ((!MethodInfo->LocalInitialized[RegisterNumber]) &&
308                  (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
309         {
310             LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30);
311             AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName);
312         }
313         break;
314 
315     case PARSEOP_ARG0:
316     case PARSEOP_ARG1:
317     case PARSEOP_ARG2:
318     case PARSEOP_ARG3:
319     case PARSEOP_ARG4:
320     case PARSEOP_ARG5:
321     case PARSEOP_ARG6:
322 
323         if (!MethodInfo)
324         {
325             /*
326              * Arg was used outside a control method, or there was an error
327              * in the method declaration.
328              */
329             AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
330                 Op, Op->Asl.ExternalName);
331             return (AE_ERROR);
332         }
333 
334         RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8;
335         ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30);
336 
337         /*
338          * If the Arg is being used as a target, mark the local
339          * initialized
340          */
341         if (Op->Asl.CompileFlags & OP_IS_TARGET)
342         {
343             MethodInfo->ArgInitialized[RegisterNumber] = TRUE;
344         }
345 
346         /*
347          * Otherwise, this is a reference, check if the Arg
348          * has been previously initialized.
349          *
350          * The only operator that accepts an uninitialized value is ObjectType()
351          */
352         else if ((!MethodInfo->ArgInitialized[RegisterNumber]) &&
353             (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
354         {
355             AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName);
356         }
357 
358         /* Flag this arg if it is not a "real" argument to the method */
359 
360         if (RegisterNumber >= MethodInfo->NumArguments)
361         {
362             AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName);
363         }
364         break;
365 
366     case PARSEOP_RETURN:
367 
368         if (!MethodInfo)
369         {
370             /*
371              * Probably was an error in the method declaration,
372              * no additional error here
373              */
374             ACPI_WARNING ((AE_INFO, "%p, No parent method", Op));
375             return (AE_ERROR);
376         }
377 
378         /*
379          * A child indicates a possible return value. A simple Return or
380          * Return() is marked with OP_IS_NULL_RETURN by the parser so
381          * that it is not counted as a "real" return-with-value, although
382          * the AML code that is actually emitted is Return(0). The AML
383          * definition of Return has a required parameter, so we are
384          * forced to convert a null return to Return(0).
385          */
386         if ((Op->Asl.Child) &&
387             (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) &&
388             (!(Op->Asl.Child->Asl.CompileFlags & OP_IS_NULL_RETURN)))
389         {
390             MethodInfo->NumReturnWithValue++;
391         }
392         else
393         {
394             MethodInfo->NumReturnNoValue++;
395         }
396         break;
397 
398     case PARSEOP_BREAK:
399     case PARSEOP_CONTINUE:
400 
401         Next = Op->Asl.Parent;
402         while (Next)
403         {
404             if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
405             {
406                 break;
407             }
408             Next = Next->Asl.Parent;
409         }
410 
411         if (!Next)
412         {
413             AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
414         }
415         break;
416 
417     case PARSEOP_STALL:
418 
419         /* We can range check if the argument is an integer */
420 
421         if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
422             (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
423         {
424             AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
425         }
426         break;
427 
428     case PARSEOP_DEVICE:
429 
430         if (!ApFindNameInDeviceTree (METHOD_NAME__HID, Op) &&
431             !ApFindNameInDeviceTree (METHOD_NAME__ADR, Op))
432         {
433             AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
434                 "Device object requires a _HID or _ADR in same scope");
435         }
436         break;
437 
438     case PARSEOP_EVENT:
439     case PARSEOP_MUTEX:
440     case PARSEOP_OPERATIONREGION:
441     case PARSEOP_POWERRESOURCE:
442     case PARSEOP_PROCESSOR:
443     case PARSEOP_THERMALZONE:
444 
445         /*
446          * The first operand is a name to be created in the namespace.
447          * Check against the reserved list.
448          */
449         i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
450         if (i < ACPI_VALID_RESERVED_NAME_MAX)
451         {
452             AslError (ASL_ERROR, ASL_MSG_RESERVED_USE,
453                 Op, Op->Asl.ExternalName);
454         }
455         break;
456 
457     case PARSEOP_NAME:
458 
459         /* Typecheck any predefined names statically defined with Name() */
460 
461         ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
462 
463         /* Special typechecking for _HID */
464 
465         if (!strcmp (METHOD_NAME__HID, Op->Asl.NameSeg))
466         {
467             Next = Op->Asl.Child->Asl.Next;
468             AnCheckId (Next, ASL_TYPE_HID);
469         }
470 
471         /* Special typechecking for _CID */
472 
473         else if (!strcmp (METHOD_NAME__CID, Op->Asl.NameSeg))
474         {
475             Next = Op->Asl.Child->Asl.Next;
476 
477             if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
478                 (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
479             {
480                 Next = Next->Asl.Child;
481                 while (Next)
482                 {
483                     AnCheckId (Next, ASL_TYPE_CID);
484                     Next = Next->Asl.Next;
485                 }
486             }
487             else
488             {
489                 AnCheckId (Next, ASL_TYPE_CID);
490             }
491         }
492 
493         break;
494 
495     default:
496 
497         break;
498     }
499 
500     /* Check for named object creation within a non-serialized method */
501 
502     MtCheckNamedObjectInMethod (Op, MethodInfo);
503     return (AE_OK);
504 }
505 
506 
507 /*******************************************************************************
508  *
509  * FUNCTION:    MtCheckNamedObjectInMethod
510  *
511  * PARAMETERS:  Op                  - Current parser op
512  *              MethodInfo          - Info for method being parsed
513  *
514  * RETURN:      None
515  *
516  * DESCRIPTION: Detect if a non-serialized method is creating a named object,
517  *              which could possibly cause problems if two threads execute
518  *              the method concurrently. Emit a remark in this case.
519  *
520  ******************************************************************************/
521 
522 static void
523 MtCheckNamedObjectInMethod (
524     ACPI_PARSE_OBJECT       *Op,
525     ASL_METHOD_INFO         *MethodInfo)
526 {
527     const ACPI_OPCODE_INFO  *OpInfo;
528 
529 
530     /* We don't care about actual method declarations or scopes */
531 
532     if ((Op->Asl.AmlOpcode == AML_METHOD_OP) ||
533         (Op->Asl.AmlOpcode == AML_SCOPE_OP))
534     {
535         return;
536     }
537 
538     /* Determine if we are creating a named object within a method */
539 
540     if (!MethodInfo)
541     {
542         return;
543     }
544 
545     OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
546     if (OpInfo->Class == AML_CLASS_NAMED_OBJECT)
547     {
548         /*
549          * 1) Mark the method as a method that creates named objects.
550          *
551          * 2) If the method is non-serialized, emit a remark that the method
552          * should be serialized.
553          *
554          * Reason: If a thread blocks within the method for any reason, and
555          * another thread enters the method, the method will fail because
556          * an attempt will be made to create the same object twice.
557          */
558         MethodInfo->CreatesNamedObjects = TRUE;
559         if (!MethodInfo->ShouldBeSerialized)
560         {
561             AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op,
562                 "due to creation of named objects within");
563 
564             /* Emit message only ONCE per method */
565 
566             MethodInfo->ShouldBeSerialized = TRUE;
567         }
568     }
569 }
570 
571 
572 /*******************************************************************************
573  *
574  * FUNCTION:    MtMethodAnalysisWalkEnd
575  *
576  * PARAMETERS:  ASL_WALK_CALLBACK
577  *
578  * RETURN:      Status
579  *
580  * DESCRIPTION: Ascending callback for analysis walk. Complete method
581  *              return analysis.
582  *
583  ******************************************************************************/
584 
585 ACPI_STATUS
586 MtMethodAnalysisWalkEnd (
587     ACPI_PARSE_OBJECT       *Op,
588     UINT32                  Level,
589     void                    *Context)
590 {
591     ASL_ANALYSIS_WALK_INFO  *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
592     ASL_METHOD_INFO         *MethodInfo = WalkInfo->MethodStack;
593 
594 
595     switch (Op->Asl.ParseOpcode)
596     {
597     case PARSEOP_METHOD:
598     case PARSEOP_RETURN:
599 
600         if (!MethodInfo)
601         {
602             printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
603             AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
604                 "No method info for this method");
605 
606             CmCleanupAndExit ();
607             return (AE_AML_INTERNAL);
608         }
609         break;
610 
611     default:
612 
613         break;
614     }
615 
616     switch (Op->Asl.ParseOpcode)
617     {
618     case PARSEOP_METHOD:
619 
620         WalkInfo->MethodStack = MethodInfo->Next;
621 
622         /*
623          * Check if there is no return statement at the end of the
624          * method AND we can actually get there -- i.e., the execution
625          * of the method can possibly terminate without a return statement.
626          */
627         if ((!AnLastStatementIsReturn (Op)) &&
628             (!(Op->Asl.CompileFlags & OP_HAS_NO_EXIT)))
629         {
630             /*
631              * No return statement, and execution can possibly exit
632              * via this path. This is equivalent to Return ()
633              */
634             MethodInfo->NumReturnNoValue++;
635         }
636 
637         /*
638          * Check for case where some return statements have a return value
639          * and some do not. Exit without a return statement is a return with
640          * no value
641          */
642         if (MethodInfo->NumReturnNoValue &&
643             MethodInfo->NumReturnWithValue)
644         {
645             AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
646                 Op->Asl.ExternalName);
647         }
648 
649         /*
650          * If there are any RETURN() statements with no value, or there is a
651          * control path that allows the method to exit without a return value,
652          * we mark the method as a method that does not return a value. This
653          * knowledge can be used to check method invocations that expect a
654          * returned value.
655          */
656         if (MethodInfo->NumReturnNoValue)
657         {
658             if (MethodInfo->NumReturnWithValue)
659             {
660                 Op->Asl.CompileFlags |= OP_METHOD_SOME_NO_RETVAL;
661             }
662             else
663             {
664                 Op->Asl.CompileFlags |= OP_METHOD_NO_RETVAL;
665             }
666         }
667 
668         /*
669          * Check predefined method names for correct return behavior
670          * and correct number of arguments. Also, some special checks
671          * For GPE and _REG methods.
672          */
673         if (ApCheckForPredefinedMethod (Op, MethodInfo))
674         {
675             /* Special check for two names like _L01 and _E01 in same scope */
676 
677             ApCheckForGpeNameConflict (Op);
678 
679             /*
680              * Special check for _REG: Must have an operation region definition
681              * within the same scope!
682              */
683             ApCheckRegMethod (Op);
684         }
685 
686         ACPI_FREE (MethodInfo);
687         break;
688 
689     case PARSEOP_NAME:
690 
691          /* Special check for two names like _L01 and _E01 in same scope */
692 
693         ApCheckForGpeNameConflict (Op);
694         break;
695 
696     case PARSEOP_RETURN:
697 
698         /*
699          * If the parent is a predefined method name, attempt to typecheck
700          * the return value. Only static types can be validated.
701          */
702         ApCheckPredefinedReturnValue (Op, MethodInfo);
703 
704         /*
705          * The parent block does not "exit" and continue execution -- the
706          * method is terminated here with the Return() statement.
707          */
708         Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
709 
710         /* Used in the "typing" pass later */
711 
712         Op->Asl.ParentMethod = MethodInfo->Op;
713 
714         /*
715          * If there is a peer node after the return statement, then this
716          * node is unreachable code -- i.e., it won't be executed because of
717          * the preceding Return() statement.
718          */
719         if (Op->Asl.Next)
720         {
721             AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE,
722                 Op->Asl.Next, NULL);
723         }
724         break;
725 
726     case PARSEOP_IF:
727 
728         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
729             (Op->Asl.Next) &&
730             (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
731         {
732             /*
733              * This IF has a corresponding ELSE. The IF block has no exit,
734              * (it contains an unconditional Return)
735              * mark the ELSE block to remember this fact.
736              */
737             Op->Asl.Next->Asl.CompileFlags |= OP_IF_HAS_NO_EXIT;
738         }
739         break;
740 
741     case PARSEOP_ELSE:
742 
743         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
744             (Op->Asl.CompileFlags & OP_IF_HAS_NO_EXIT))
745         {
746             /*
747              * This ELSE block has no exit and the corresponding IF block
748              * has no exit either. Therefore, the parent node has no exit.
749              */
750             Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
751         }
752         break;
753 
754 
755     default:
756 
757         if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
758             (Op->Asl.Parent))
759         {
760             /* If this node has no exit, then the parent has no exit either */
761 
762             Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
763         }
764         break;
765     }
766 
767     return (AE_OK);
768 }
769