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