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 }